JWT access tokens: a contradiction? - oauth-2.0

I'm attempting to implement a security solution for a micro-services architecture. My authentication server supports OAuth2 and OIDC.
I'm trying to figure out if I can pass a JWT token between my micro-services to avoid having to repeatedly exchange an opaque token to get the user's claims. There's nothing (practical) that stops me doing that. I can:
Use the JWT (ID token) I get from the auth server as a bearer token when making the calls.
Each service can validate that token against the auth server's (cached) JWKS to make sure it's valid
Each service can include the token on it's calls to other services
I've read that it's ok for an access token to be a JWT.
Great, but:
My (moral?) issue is this:
A JWT is intended for a specific audience. In fact the spec basically says that if it's not for you, you should reject it.
A Bearer token is intended to be non-audience specific. So if I issue a token that says that the bearer can read my mail, it can get passed through half a dozen different services, any one of which should be able to read my mail.
So my question is simply, how can a JWT be a bearer token?
Bonus points for links to any nice articles/videos/examples of an effective distributed authentication solution!

A JWT is intended for a specific audience. In fact the spec basically says that if it's not for you, you should reject it.
This is the case also for a bearer token. It can be passed on by anyone, but only the audience should act on its validity.
So, service X can get a JWT bearer token with intended audience service Y. It will not give the calling client any authorization based on that, but calling service Y with it does not violate the audience claim. What would violate the audience claim is if service X validates the JWT, seeing the mismatching audience and says "Well, since the client has a JWT stating that it is user Fubar, I can return some info about user Fubar.".
The difference for an opaque non-JWT bearer token is that service X would have no way to misuse it...

Related

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

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.

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.

Access Token from OIDC vs OAuth2.0

I know that the access token obtained from OAuth2.0 can be used to access protected resources.
OpenID Connect issues ID token and access token after authentication. And the spec says that the access token can be used to access userinfo endpoint to get additional user information.
One thing I'm not able to understand is, is there any difference between the access token obtained in #1 vs #2. If there is no difference then do we need OAuth2.0, if we implement OIDC.
You tend to just implement both OIDC and OAuth 2.0 together as a combined flow, by plugging in an Open Id Connect security library.
Eg For a mobile app it is common to plug in AppAuth Libraries, which would give you this behaviour:
An OAuth 2.0 authorization redirect using response_type=code
The Open Id Connect part is initiated by including scope=openid
You then get an authorization code (OAuth 2.0)
You then swap the authorization code for tokens
You get an access token (the OAuth 2.0 part)
You also get an id token (the OIDC part)
In practical terms OIDC introduces some standardisation that makes developing UI flows and dealing with access tokens in APIs easier, eg:
Metadata endpoint, to tell us where all the other endpoints live
JWKS endpoint, from which we can get the access token's public key
Typically in my own code I do not use the id token much at all. However, it is best practice to receive one, so that libraries such as AppAuth can make extra verification checks against received tokens.
If it helps, my Message Workflow Blog Post summarises some messages and use of endpoints.
This access tokens have different audiences ("aud" claim): the OAuth 2.0 access token is intended for resource server (i.e. API), and OIDC access token is intended for identity server itself.
As for me, they cannot be used interchangebly, but some examples (e.g. IdentityServer4) do that without checking the "aud" claim.
PS. The single access token can be used for both purposes if both audiences are included:
Each principal intended to process the JWT MUST identify itself with a
value in the audience claim.<...> In the general case, the "aud" value
is an array of case-sensitive strings, each containing a StringOrURI
value.
JWT doc

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.

Can oauth access tokens migrate?

I have very little experience with Oauth 2.0 and am trying to better understand how the system works. Are access tokens tied to a user/device/session? For example, can I migrate an access token granted for one app and use it in another app? How will the server/API know? I believe most APIs have apps request using an app_ID, is there any other data that goes into a request for a token?
Thanks!
The OAuth 2.0 protocol framework is designed to allow for different types of access tokens but the only access token that has been standardized so far is the so-called "Bearer" token, so I'm assuming your question is about that.
A Bearer token is opaque to the Client which means that it is just an "identifier" or "string" that the Client passes on to the Resource Server to get access to protected resources. This also means that it is not specifically tied to a device/session or Client. In fact anyone who gets a hold of the Bearer token can actually use it to get access to the protected resources. This is one of the known drawbacks of Bearer tokens but it makes it very easy to implement them. It relies on a secure HTTPs channel for confidentiality.
The previous paragraph describes how to use a Bearer token. The process that the Client has to go through to obtain such a token, may include presenting a Client identifier and a Client secret to the Authorization Server indeed. But the Resource Server (aka. Server or API) does not know or care how the Client obtained the Bearer token.
There are token extensions of OAuth 2.0 under development that would require the Client to proof that it is the rightful owner of the token. Such tokens are called "Proof of Possession" Tokens and may be useful in environments that have higher security requirements. See: http://www.thread-safe.com/2015/01/proof-of-possession-putting-pieces.html

Resources