How do you guarantee safety when validating Keycloak (OIDC) tokens without making requests to the Keycloak API? - oauth

There is a lot of information on OAuth, OIDC and Keycloak, but the main thing every tutorial seems to gloss over is offline validation. The only information I found is in the Keycloak docs on RPT introspection:
No. Just like a regular access token issued by a Keycloak server, RPTs also use the JSON web token (JWT) specification as the default format. If you want to validate these tokens without a call to the remote introspection endpoint, you can decode the RPT and query for its validity locally. Once you decode the token, you can also use the permissions within the token to enforce authorization decisions.
If I wanted to verify a user's request with an authorization token, I would make a request to the Keycloak introspection (or userinfo?) API. I'm not completely sure, but I would guess that Keycloak then verifies the info encoded in the JWT with the Keycloak user database.
However, what if I don't want to make a Keycloak request on every API request? This could improve system performance by limiting the amount of HTTP requests. There are mentions of JWT signature validations and reading the scope and user information encoded in the JWT, but I don't see how this guarantees safety. Isn't it possible to just generate any old JWT, encode any information you want and basically spoof an authorization token? How would I check if the user mentioned in the JWT really exists in the Keycloak database?
I think I am missing some crucial part of this technology.

For example, in ASP.NET Core, an API that receives a JWT token will, at startup, download the public signing keys from the token provider, and by default, it will refresh the keys every 24 hours.
So, when the API receives a JWT token, it will do various checks to validate the token, including:
Validating the signature using the provider public signing key
Validate the audience claim (is the token intended for me?)
Validate the expiry date
The API should not need to query anything against the token provider (keycloak) to let the user in.
However, then we have authorization (What the user is allowed to do), which is a different thing, and that all depends on your requirements.
JWT is all about who the user is; if the token is valid, you can trust that information.
With JWT-tokens, your API can work almost offline from the token provider. It can even be 100% disconnected if you copy the public signing key manually into the API.

Related

Access tokens and id tokens

I am pretty new with these protocols, and I am having some trouble understanding something.
I am currently working on an application which API and Frontend is mine, I use azure identity platform to receive the tokens on the clientside and send the token to the server that validates the token using passport-azure-ad bearerStrategy. (I have my app registration for that purposes ofcourse).
The thing that I don't get, is that I missed correctly used the tokens I received from azure in my client and sent the ID Token to my API, it verifes it as a valid one and user is authenticated to perform the request sent.
But, as I read here https://learn.microsoft.com/en-us/azure/active-directory/develop/id-tokens, and in any other article about oAuth2 and openID, ID tokens are for UX stuff and client, while I should have used the access token in my request to my API.
But howcome the ID Token is also verified in my API? It makes no sense for me, or am I missing something?
And if so, is there any vurlnabilty in using Id Token as I did?
Thank you!
APIs should first validate the JWT access token, to check these fields have allowed values. An ID token will then fail the audience check.
JWT signature
Not expired / valid at this time
Issuer (a Microsoft ID)
Audience (eg api.mycompany.com)
Access tokens have scopes, whereas ID tokens do not. Every API endpoint should validate the received scope, eg to ensure that it has received the right type of token. This will also ensure that the API does not accept ID tokens.
So although some API tech stacks accept ID tokens, making the standard checks will ensure the right behavior. And the real API authorization is then done using claims, to apply your business rules.

OAuth redirect flow server to server token generation for client

I have a rest API service that enables API calls for some resources.
The API calls can be done from an API server using a secret, or from a web client using a bearer token.
In order to get to the web client flow, a URL must be generated by the API server call:
https://www.someapi.com/somelink
The response will be a link with a token I call "action token". This token is passed with the link, for example:
https://www.somepage.com/?action_token=somejwttoken
By entering the link, the action token will be exchanged with an access token, that enables a client to access some pre-defined resources.
I wonder if there is a best practice for such flow.
ONE TIME TOKENS
If using tokens in URLs you should also ensure that:
The token has a one time use
The token is short lived
The token is not guessable - eg make it a UUID
The final access token returned has limited privileges and also a short lifetime
The one time action token may then be available in the browser history or server logs, so be aware of that. Make the actual swap for the proper token a JSON to JSON POST operation, after the page has loaded.
Typically each action token issued would also be stored by the API in a database along with its expiry time, then used to verify links later.
This type of URL solution is sometimes used in operations such as verify email or to enable magic links, where users can quickly access limited data.
OAUTH FLOWS
One time tokens should not be overused and they are of course no substitute for signing the user in properly via OpenID Connect standards, then running an authenticated user session.
SCOPES AND API TO API FLOWS
A more secure option may be to forward JWTs from the original client to downstream APIs, as described in Scopes Best Practices. This enables user context to flow securely and also simplifies code. This may eliminate or reduce the need for any token exchange operations.

Extending OAuth2 MS AD access_token data

I am missing some understanding of OAuth2 access_token hope someone can explain or guide me to what I am missing.
I am using Microsoft Azure AD as an authentication provider for my application, I used the returned id_token after successful authentication to extend it with some additional data custom to my application (to facilitate authorization).
I am doing this throw JWT.sign, I decode the data from id_token and add data then I sign it using a secret key saved at the server.
My question is, can I do the same for access_token? When I tried to do so, I get unauthorized.
Am I doing something wrong? Or this is not possible? And why is this happening, I don't find any request made to MS to validated my new signed access_token.
You should never change tokens issued - this is not a correct thing to do. But your point about using domain specific claims is totally valid - all real world systems need these for their authorization.
OPTION 1
Some specialist providers can reach out at time of token issuance and contact your APIs, to get domain specific data to include in tokens. See this Curity article for how that works. I don't think Azure AD supports this though.
PRIVACY
It is best to avoid revealing sensitive data in readable tokens returned to internet clients. If you include name, email etc in ID tokens or access tokens this may be flagged up in PEN tests, since it is Personally Identifiable Information and revealing it can conflict with regulations such as GDPR.
Curity recommends protecting access tokens by issuing them in an opaque reference token format - via the phantom token pattern.
OPTION 2
An option that would work fir Azure AD is to adopt the following approaches:
Look up extra domain specific claims in your API when an access token is first received, then cache results for further API requests with the same access token. See this Azure AD Code Sample class of mine for some code that builds a custom ClaimsPrincipal. Note that the API continues to validate the JWT on every request.
If the UI needs extra domain specific claims then serve them from your API, which can return both OAuth User Info and domain specific data from its ClaimsPrincipal to the UI. See this API controller class for how that looks. Personally I always do this and never read ID tokens in UIs - which should also never read access tokens.
Applications interacting with Azure AD, receive ID tokens after authenticating the users. The applications use access tokens and refresh tokens while interacting with APIs.
The id_token is a JSON Web Token (JWT) which has user profile
attributes in the form of claims. The ID Token is consumed by the
application and used to get user information like the user's name,
email.
The Access Token on the otherhand is a credential that can be
used by an application to access an API.
So if you need application to access api, there the access token is used and you may follow the suggestion steps provided by Tiny Wang
Similar to id tokens, access tokens are also signed, but they are not
encrypted. As per IETF OAuth (RFC 6749) standard specification ,
access token can have different formats and structures for each
services whereas, id token should be JWT format.
To validate an id_token or an access_token, your app has to validate
both the token's signature and the claims. To validate access tokens,
your app should also validate the issuer, the audience, and the
signing tokens.
So in production application, you should get id token by specifying
“id_token+code” or “id_token+token” as response_type to verify
whether the authentication is correctly succeeded. It means it uses
the id_token for authentication and “code” to exchange access_token
to access the resource for authorization.
In short id_token is used to identify the authenticated user, and the
access token is used to prove access rights to protected resources.
Refer this for the information regarding access token and id token.

Why would IdentityServer4 demo application's implicit client flow send me back an access_token that is the same as the id_token?

I am using a variant of the in-memory clients defined in the reference IdentityServer4 demo project and after I log into the Identity Server and get redirected, the URI is such that the id_token and access_token are the same exact JWT.
Is this a sensible behavior? Why would you want the id_token and access_token to be the same, ever? Maybe if you don't care about the access_token?
Not sure what you mean same exact JWT. But both access token and ID token can come as JWT tokens.
One good example is OAuth flow of Azure AD. According to the document successful token response return an access token and an id token (yes, Azure does send one for OAuth auth. code flow) both in JWT format (reference). But their contents could be different. For example, one could be a signed JWT and other could not be.
Reason for the usage of JWT is due to self-contained nature of them. For example, token validations can be done easily from client application end as well as protected API end.
Usually if both access token and ID token are JWTs they could be differ by claims. For example audience claim ("aud") could be different depending on intended audience of token.

SpringCloud Microservices JSON Web Token (JWT) Security

I have a multiple microservices architecture in which I intend to apply security.
My View of the Security Design:
The authentication will happen with an LDAP and when the user is authenticated a JSON Web Token (JWT) will get generated using a "secret key" and the token will have the roles, expiration time etc. With every call to a microservice this token will be passed in Header for authorization. In my view I just have one single auth server which authenticates the user and generates the JWT.
My Doubt:
Now, when a microservice will receive a call (containing the JWT in Header) will it always hit the auth server to get the token verified?
If yes, won't it lead to multiple calls to auth server and thus a bad practice?
If no, how will the client verify the token and what is the scope of the auth server?
JWTs are always signed, so that you can verify a given token without doing a call to some central auth instance. The auth server knows the secret to sign the token and all services that want to validate the token also need have a way to check this.
There are two different approaches to signing:
symmetric: A secret value is appended before hashing the payload. The consuming service also needs to know this secret and can verify by appending the secret to the payload received and checking the resulting hash with the transmitted hash.
asymmetric: By using some PKI signing/verification it is possible that only the auth server has the private key to sign the token. All consuming services then only need the public part to verify.
I prefer the second way, cause it reduces the chance of a key getting stolen. If one of the consuming services is hijacked, there is no secret lost such that the attacker can create valid tokens. Using such an algorithm could possibly take some more time / cpu cycles for validating than a simple hash used in the symmetric way.
Please see the official JWT page for an example of the different mechanisms: https://jwt.io/

Resources