ClientCredentials flow and expired tokens over multiple time-delayed physical boundaries - identityserver3

In our scenario we have an on-premise device (A) making a call to our cloud hosted service (B). Each device belongs to a customer and each customer has a unique api-key and api-secret. These are securely held on the device.
The device uses these to authenticate via Client Credentials flow; token lasts for around 10 hours.
service B dumps the request onto a message queue.
service C takes from the queue, performs some processing and calls service D, service D calls service E.... etc.
Each service is a distinct physical boundary (think microservices) called by https.
We are using a "delegated authority" concept so that the token is passed around as a custom claim that can then be used to attach to the next request in the chain. This means each service is operating under the original device A requested authentication and has access to the custom, customer specific, claims created when device A authenticated.
We also pass the JWT token in the message as a string between service B and C and this works fine when we use it to set the bearer token in service C when it calls service D.
My problem is what if service B doesn't process the message within 10 hours (e.g. a fault). After 10 hours the token will have expired, and service B does not have access to the credentials used by device A to re-request the token.
I thought I needed a refresh token too, but this isn't supported for Client Credentials flow. Then I thought of "cheating" and making my token last "a very long time", but then I'm not sure how I can invalidate it in a security breach. My final option is to actually pass the api-key and api-secret in the token as a claim that can then be used to re-request a new token by any service in the chain... but this feels like a security breach waiting to happen. To be honest though, so does having the refresh token as it acts like a master password anyway.
Is there any advice / best practice on this scenario?
Many thanks

I see two options
a) make the token long lasting - but use reference tokens. This way you can revoke the token if needed
b) implement a custom grant that allows authorized clients to request a token copy with a new lifetime.

Related

Keycloak implementing both user and app authentication in the same realm

I have a setup like this:
Back-end REST API application - Single Instance running in Cloud Server - Let's call it as A
Public Users` Mobile app & browser clients - Let's call them together as X
We already are using Keycloak for Identity and Access Management. As per the current setup,
X to A uses Password grant flow, that is – a client is created in Keycloak with Client-Type as Public for user management and auth of X to A.
Now, we have to introduce new layer of back-end app, that is,
Back-end REST API application - Multiple Instances running in On-prem Servers across different physical locations - Let's call them together as B.
Now, both B and X both are clients of A, [i.e. A serve both B and X].
Please clarify:
Should I create another type of client in the same realm for B, like below?
B to A: Client credentials grant flow i.e. I have to create another Client-Type as Confidential for B to A, to configure a service-account for each of the instances of B.
If yes, please guide me on how to configure both Auth flows in A i.e. A has to auth both B and X.
I feel like this one as a bad idea - Using the existing setup as it is, which is explained below.
As per the new business logic,
X logs-in the app (mobile/web app) using username and password and calls an API of A to generate a QR Code, which will contain the hash of the user's (X's) access token and some other info.
A stores both hash and access token of X in the database
B gets the hash of the access token used by X to access A, from the QR Code scanned by the user. B uses the hash to validate the authenticity of the QRCode, by calling an API of A
As mentioned in the above business logic, if needed, A can expose an API, where the above said user access token can be retrieved through a get request, by sending the hash as a request header param or query. This token can be further used by B for further API calls to A.
I think that the above idea is bad, because, we are not supposed to send the user access token over the internet, even if there is a SSL/TLS connection between B and A.
Can the Client-Type, Bearer-Only be used in this scenario between B and A? If yes, Please guide me on this.
As you are having both Public and On prem services as clients, I would suggest the following:
As you said, X as public client shall use Password grant
B should use Client Credentials mechanism to get itself authenticated with Keycloak. Keycloak will provide it the access token through ${kc.realm-url}/protocol/openid-connect/token endpoint. This access token can be sent to A.
"A" should also be a registered client with its own credentials.
When "A" receives request from X or B, it should use a mechanism called Token verification through Introspection endpoint where it will get the token verified by calling Keycloak.
Introspection endpoint expects access token, client id and client secret.
This way, A can be sure that the token received by it is indeed issued by Keycloak.

How does all services in microservice architecture (token based) know that the user has logged out?

When a user logs out (sign out) of the application, how does the gateway communicate to all services that the user has logged out?
In other words, what happens when a user logs out in microservice architecture application?
This is generic question, I will give my personal thoughts.
Let's take a Single page application, talking to bunch of Microservices and secured by a Gateway that validates the token.
When user logs in, token given by auth server is stored within browser storage(ex: localstorage).
When user log out, no communication is sent to Gateway or auth server, tokens will simply be deleted from browser storage.
So, if someone gets hold of access tokens, they can be used to call services as long as access tokens doesn't expire.
This is typically why there are two tokens given by auth server, an access token and a refresh token. Access token which is used to secure apis expires pretty quickly and a refresh token which has much longer expiry time can be used to get new access token.
As you've included the JWT tag, so I'm trying to give the response by considering that only. The JWT token is a self-sufficient encoded token that contained certain attributes including an expiration period. The sole purpose is to provide stateless authentication. Authentication service usually returns two token, access_token and refresh_token. Client store both of them in some storage on their end. Access token usually issued for a very short span of time and so the client can use the refresh_token in order to get a new access_token on the expiration of the latter. One can access the services until refresh_token get expired. After that client has to go through the authentication process to get new tokens. In case when user logout from the system client should remove both of the tokens from its storage. Because as there is no state maintain in the case of JWT, the server can still accept the old token until they're not expired.
Validation of token for expiration and integrity should be done at the gateway level.
One can avoid the use of the token for service to service communications as those are internal services and running in a private network although one can do the same validation at this level too.
So in case of user sign out, the user's auth token should be removed from the client-side and the gateway should not communicate to other services. There are other special cases where token revoke is a particular case that could be handled by taking the help of distributed cached store in scaleable authentication systems.
A token-based service can generally infer the following from a token -
Who made a request?
Upto what time this token is considered valid?
Which actions are allowed when using this token?
A token based service just accepts or rejects a request depending on provided token, regardless of whether it is a user or a machine making the request. A logged-in user is just someone who can perform actions which this user is authorized to do. A token is a limited representation of such a user.
My point being, it is the application telling the user that they are logged in (have a token it can still use), or logged out (no token yet, or expired). Such a token is obtained by authenticating to the service using ones username and password.
Answer is based on my knowledge, so everyone, please do point out mistakes if any. I don't know in detail about aws api gateway stuff, so maybe someone else can brief you on it in case it works differently.

Azure AD OAuth Refreshing Tokens

I'm making an application that among it's task will use the REST API in KeyVault. I already have functions written that will query the KeyVault for the secret without an issue.
I also have functions written to request an OAuth token from AAD, following the documentation on this link:
https://learn.microsoft.com/en-us/azure/active-directory/develop/active-directory-protocols-oauth-code
What I'm not sure about is; Since the application is going to be installed on hundreds of computers when a token expires and the function to refresh the token is called chances are that more than one PC is going to make the POST. What is the best practice for a scenario like this? Should i just configure an exponential back off after a refresh token function is called?
The app installed on the machines will not have the ability to talk to each other.
The only way I can think to do this is to use a logic app as the broker but that would defeat the purpose of the KeyVault.
The document you provided is using the code grant flow to acquire the access token. This flow requires users to login to acquire the token. And did you mean all the PC you installed will use the same account to acquire the token?
If yes, you can design you own token cache. For example, you can using an SQL server to store the cache. Then the app will search the token/refresh token in the token cache before it sends the token request. And if the token is expired, you can refresh it. In this scenario, all PC will share the same access token since they are sign-in with same account.
If not, you need to refresh for the every PC when the access token is expired. Because the access token is different from each user.
So after some testing and verifying with MS it looks like the documentation on the link is outdated. When a token is generated it has a lifetime of 8 hours (this is configurable) so every time I make a request to /token a new token is handed out, since the time window is small I don't need to worry about token refreshes since PCs won't be on for over 8 hours.
The other part of this is that i built a function to test the validity of the existing token, before i query any azure service i test the token validity, if it fails a new token is requested. Since the token lifetime windows are short and each machine gets it's own token (i thought all machines were getting the same token, code error on my part) this is a non-issue anymore

JWT and blocking users

JWT is a stateless authentication mechanism as the user state is never saved in server memory.
How to invalidate the token if administrator blocks the user for some resons?
JWT is not an authentication mechanism but a token format. Since JWT are self-contained, you CAN use them for stateless authentication. However, this does not mean that your authentication mechanism MUST be stateless (although there it has its benefits).
There are several options for handling user lockout / revoking authorization:
Do a lookup of the user in every request after validating the JWT to see if the user is locked out
Access tokens are supposed to be short-lived, so you can look up the user the next time a new access token is requested (e.g., using a refresh token) and then refuse issuing a new access token
Alternatively, you can blacklist all tokens issued for a specific user by storing their jti in a database. See also: https://auth0.com/blog/denylist-json-web-token-api-keys/. EDIT: As pointed out in the comments, while not strictly stateless, this approach is still efficient, because a blacklist only needs to store blacklisted tokens for the duration of their lifetime, and lookup should be highly efficient.
You can look up the user identified by a specific JWT every N requests or whenever X percent of the lifetime of the JWT has passed rather than doing it in every request.
None of these approaches is entirely stateless. In general, stateless authorization is not possible if you want it to be possible to revoke authorization. If you want your tokens to be entirely stateless, you should make sure their lifetime is as short as possible, and issuing a new token is not stateless.

DC/OS - authentication vs. api token

As far as i know, DC/OS has two different types of tokens:
authentication token: retrieved via a login through
https://public-master-ip/login?redirect_uri=urn:ietf:wg:oauth:2.0:oob. This token is used to retrieve api tokens.
api token: retrieved via a post call to https://public-master-ip/acs/api/v1/auth/login with the authentication token in the request body. This token is used to authorize calls against the apis. Such a token expires after 5 days.
My questions are
Are my assumptions correct?
Does a authentication token expire? If so, when and is there a way to refresh it?
Let me first define the goal of the current (1.8) Open DC/OS authentication procedure and then walk through your assumptions. I'll answer your questions after that.
Goal
The goal of the current Open DC/OS authentication procedure is to use Auth0 infrastructure for triggering a single sign-on authentication flow against one of three popular identity providers, and have the result reported back to your DC/OS cluster. If the DC/OS cluster is happy with the result, it will emit an authentication token specifically adjusted to that individual cluster.
Comments on your assumptions
authentication token: retrieved via a login through https://public-master-ip/login?redirect_uri=urn:ietf:wg:oauth:2.0:oob. This token is used to retrieve api tokens.
That's roughly true. However, what you call "authentication token" actually is an OpenID Connect ID Token emitted by an OpenID Connect identity provider.
Let us take this one slowly, as it is a little involved.
What happens behind the scenes is an OpenID Connect single sign-on authentication flow.
More precisely, the DC/OS UI displays an iframe that loads a piece of JavaScript hosted by Auth0, which -- when executed in your browser -- performs the so-called implicit flow (which is one of three specified OpenID Connect authentication flow types).
By the end of this flow(*) the JavaScript code executed in your browser receives a so-called OpenID Connect ID Token (from the identity provider, of course, which is Auth0 in this case). This token is a JSON Web Token (JWT, see RFC7519) signed with the private key of the identity provider (in this case it actually is Auth0, which basically proxies other identity providers such as Google Accounts).
The piece of JavaScript that receives the ID token then -- as you say -- POSTs the ID Token to your DC/OS cluster (to https://public-master-ip/acs/api/v1/auth/login). The receiving end is a web application behind DC/OS' Admin Router (the latter is just a pimped nginx). That web application inspects the ID Token's payload (which is JSON) and finds the key/value pair "iss": "https://dcos.auth0.com/". So it knows who (pretends to) have issued that token! Then it goes ahead and fetches https://dcos.auth0.com/.well-known/openid-configuration (wooo, where does it know that URL from? This is magic defined by OpenID Connect Discovery 1.0 and RFC5785). That JSON document there defines a JSON Web Key Set (JWKS) document (specified via RFC7517), revealing the public key corresponding to the private key that had (supposedly) signed the ID Token. So, that web application goes ahead and fetches the public key directly from the identity provider (through HTTPS). It then uses that public key to verify the cryptographic signature of the ID Token (and it checks the expiration time, too, of course). If ID Token validation passes, the DC/OS web application I talked about rightfully assumes that the user agent that had sent the ID Token is successfully authenticated against Auth0. And, trusting Auth0, we rightfully assume that the user agent is authenticated against e.g. Google Accounts.
Only then it (the small web application in DC/OS I talked about) stores the identity within DC/OS, assigns a unique user ID, and emits the DC/OS authentication token. That token refers to the given identity via the named user ID.
(*)Note that the identity provider only emits the ID Token towards your browser after you have successfully authenticated yourself towards that provider (e.g. Google Accounts) and after you have given consent to share identity details with a third-party service.
api token: retrieved via a post call to https://public-master-ip/acs/api/v1/auth/login with the authentication token in the request body. This token is used to authorize calls against the apis. Such a token expires after 5 days.
In DC/OS terminology, this is the DC/OS authentication token. It is a JWT signed with a random key only known to your DC/OS cluster. The Admin Router in your DC/OS can validate such authentication tokens. Certain HTTP requests against Admin Router are only proxied to back-end services when they contain a valid authentication token in the request (hence, this token mainly serves authentication, but also a very basic coarse-grained authorization, if you want to say so). Otherwise, Admin Router will respond with a 401 (read: "not authenticated").
Answers to your questions
Are my assumptions correct?
I hope to have clarified
that what you call "authentication token" is an OpenID Connect ID Token (a JWT).
that what you call "api token" is what's called "DC/OS authentication token" in the DC/OS ecosystem (and it's technically a JWT, too).
Does a authentication token expire?
I read this question as "Does an OpenID Connect ID Token expire?" Yes, indeed! This is what the spec says about ID Token expiration:
exp -- REQUIRED -- Expiration time on or after which the ID Token MUST NOT be accepted for processing. The processing of this parameter requires that the current date/time MUST be before the expiration date/time listed in the value. Implementers MAY provide for some small leeway, usually no more than a few minutes, to account for clock skew. Its value is a JSON number representing the number of seconds from 1970-01-01T0:0:0Z as measured in UTC until the date/time. See RFC 3339 [RFC3339] for details regarding date/times in general and UTC in particular.
Note that the spec does not enforce a particular ID Token lifetime -- this is up to identity providers to set. In case of ID Tokens emitted by dcos.auth0.com I have just confirmed that
>>> exp = 1474742063
>>> iat = 1474310063
>>> lifetime_days = (exp - iat) / (60.0 * 60 * 24)
>>> lifetime_days
5.0
That is, the ID Token emitted by Auth0 expires after 5 days.
If so, when and is there a way to refresh it?
You can only obtain a new ID Token emitted by Auth0 by going through an OpenID Connect authentication flow involving one of the configured identity providers. That is, the (only) intended way to obtain such a token and pass it along to DC/OS is triggered through the DC/OS UI which starts the Auth0-based flow for you (well, you could technically hack this together yourself...).
Note that Enterprise DC/OS offers an OpenID Connect authentication flow that
directly communicates the ID Token securely between DC/OS and the identity provider (no user agent ever sees that ID Token).
enforces the usage of the optional nonce mechanism of OpenID Connect ID Tokens (described in the spec), introducing more conceptual security on multiple levels (e.g. mitigating replay attacks).
We will probably merge that functionality into Open DC/OS by one of the next releases (no promises at this point!).
I hope that helped, let me know if there are further questions.