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.
Related
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.
Currently I have this setup:
At login, and in every subsequent request after login, a mobile application that I have built uses Basic Authentication to authenticate the user with a web service that serves the app with information it requests.
On every request the Authorization header is inspected, the password and username are extracted from the header, the password is hashed using a proprietary DLL (so the web service doesn't actually contain the hashing algorithm) and compared to the hashed password associated with the username that is stored in the database.
I have now been asked to include Azure AD SSO in the login options.
After reading much about the topic, this looks seems to me like the setup:
I'm curious about a few things:
Is this setup correct, more or less?
Does the app send the Identity Token to the web service? If so, how does the webservice validate that token?
Is it correct that the webservice can match the Azure Identity to the DB user using one of the claims in the Security Token?
Where do Access Token fit in this picture?
Thanks for the help!
(Side Note: I know that Basic Authentication is not the preferred way to go in the first scenario. This was a temporary decision till we developed the token handling code, it only works using HTTPS and this is an internal application - you wouldn't be able to activate the app unless you have a code we give you)
I have little experience in azure ad but I think we could talk about your case.
First, whatever id token and access token are both jwt token, so to your web service application, you need to use jwt decode library to decrypt the token and get claims it contains. Here we need to know the difference between id token and access token, and I think you'll know that for your web service application, if it's more likely to play the role of an api application, you need to use access token because this token also contains user information. Then you need to add code in your program to decode the token and check if it's a 'valid' token for the request.(Because you've used azure ad to achieve the login part, you don't need to use your custom login part.)
Next, the signing in feature provided by azure ad requires to use account and password in the tenant which azure ad belongs to, the user accounts may look like xx#xx.onmicrosoft.com, it doesn't required to keep sycn with the accounts in your database, so it's difficult and needless for you to compare the user name obtained from the decoded token with those in your database. Because when your web service received the token(id or access token), that means someone has passed the authentication from azure ad. The token contains user information including role, expired time etc. You need to check if the token has expired and if has the correct scope. (Let's see a common situation, microsoft provides many graph apis to call, when accessing these api, we need to provide access token in request head with matching scope, e.g. https://graph.microsoft.com/v1.0/me
requires a delegated api permission of User.Read)
To sum up here, if your web service just required the users in your database to sign in then can be access, id token and access token are both suitable for you because they both contains user name like 'xx#xx.onmicrosoft.com', what you need to do is decode the token and check if the token has expired and whether this user exists in your database(you may set up a mapping between them).
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
I'm using oauth2 authorization code flow with the ASP.NET core 2.2 AddJwtBearer. My token end point returns JWT access toke with all the claims needed for checking the user's permissions.
I can send this token as the bearer for any Web API call and the standard .net code can use those claims to check permissions eg [Authorize(Policy="somePolicy")].
One of the claims points at an internal session key that we can revoke.
So my question is why would I need an ID token or even a refresh token?
The claims and other details are in the access token so what would an ID token add to this?
Having to use a further call to a userinfo end points send to be a waste if the info is in the Auth token?
If I can revoke the session that Auth token points at, surely I don't need a refresh token and can have longer life Auth tokens?
I've read lots of examples and comparisons but most computations between just oauth2 and enhanced with openid connect seem to be with very basic oauth2 not using JWT etc and so written to exaggerate the differences.
So I'm unclear when both are using the same authorization code flow and JWT tokens, what the team advantages are in using the id token in my situation??
Given your context, it seems that OpenId Connect is not necessary for your situation. It really adds value when you are implementing single sign-on (SSO). In that case the Identity token can also be used on SSO logout.
Having additional claims about the identity in the access token is also a waste. Having to send all this information on each call. Especially when you need the information only once (a Spa may persist the information in memory). It's better to have some api (endpoint) expose the information when requested.
About the access token, you can't revoke it. You may be able to revoke authorization, but the access token remains valid until it expires. You want invalid access tokens to short-circuit as soon as possible in the pipeline, before policies are evaluated.
Please note that it's not a common scenario where the api can revoke access by using an internal session key. Most api's are 'session-less' and fully rely on the access token. Because that's the purpose of a JWT, being self-contained, not having to contact the authority to verify the token.
Perhaps you can use a long-lived access token because in your situation the authorization is determined at another level. But are you capable of detecting when the token is compromised? And where are you going to check it? In every api and client? Or would you rather let the authority take care of it (single responsibility)?
When implementing security you should look at the design, the responsibilities, where to do what. Let the authority, that issues the tokens, take care of authentication and client/resource authorization. The Api, being the resource where the business rules (policies) are implemented, can take care of (user) authorization.
The problem with a long-lived token is that when it falls into the wrong hands, it allows access until it expires or, in your case, until you detect something is wrong. Where a short-lived token always allows access for a short time, making it almost not worthwhile for a hacker to obtain a token for the time it can be used.
With short-lived access tokens you'll have to use refresh tokens. The authority can verify on each call whether a new access token should be issued. Of course here counts the same, this only applies to the situation where you are actually verifying the request. Tokens in itself are not safe. You'll have to add some level of security, e.g. check the ip address. But having the authority to take care of it and using one-time-use refresh tokens already does add security.
In my experience with oidc/oauth2, the access token is mainly used to grant client applications access to a resource (on behalf of a user). Where scope claims define the accessible functionality and the sub claim identifies the user.
Authorization can be implemented on different levels and doesn't have to be part of the access token. In fact, permissions should not be part of the access token at all.
So your setup may be fine. But I wouldn't use long-lived access tokens for the reasons already mentioned. Plus they are not managable. You can't update the access token when someting changes in the flow, e.g. when a scope is added.
While starting to integrate auth0, I came across this article
So its clear that to secure apis, all we need is the access_token and that is sent with each http request in the request Authorization header(Bearer scheme).
But then auth0(and possibly other providers) also send an Id_token that contains information about the user. My confusion is that how do I use this id_token to pass user information to my api. ( I have a spa running front end that authenticates to auth0 and gets these 2 tokens).
I can ofc call the userInfo end point in my api to get user info. But then wouldn't this defeat the purpose of the Id tokens?
The ID Token is consumed by the application and the claims included,
are typically used for UI display. It was added to the OIDC
specification as an optimization so the application can know the
identity of the user, without having to make an additional network
requests.
So my question is how do I access user profile in my api using id tokens?
"My confusion is that how do I use this id_token to pass user information to my api"
for that confusion, you just pass your JWT token. while generating JWT token, you need to add user information in payload part in JWT token. When your api get the JWT token, just check your JWT token is correct or not by the use of secret key and if correct, you can get data. How to get is just go from that JWT Authentication for Asp.Net Web Api
ID token is sent from the authorization server as a part of OIDC protocol. The purpose of this is to authenticate the user to your client application (SPA in this case). i.e. to let your API or the application know which particular user authorized the client to access a certain resource on its behalf.
Best way to use the ID token is by decoding and verifying it using a library. This will allow you to verify the signature of the token and any other claim that is included in the token (you can add custom claims to the tokens). Validation of those claims can be used to determine identity of the user and match with the user profile in your API. You will have to check the documentation related to your IdP(auth0) to figure out how to add new claims that are used by the user profile in your API.