With reference to the following page:
https://learn.microsoft.com/en-us/azure/active-directory-b2c/id-token-hint
Is there a way to send multiple JWT tokens to a custom policy so that they all can be validated in the policy?
Reason I ask is as per above page, the JWT token must be sent as 'id_token_hint' query param which is reserved. Can this be extended to read a second JWT say 'id_token_hint2' from the query string and validate in GetClaims profile.
Use case:
I want to send the current signed-in users' ID token in id_token_hint param.
I want to also send a custom JWT in another param say id_token_hint2 param and validate it similar to #1 (but against my metadata endpoint).
Regards,
Dipesh
Not possible. This follows the OIDC specification for id token hint.
I don’t see why 1&2 can’t be a single JWT. 1 will also be against your metadata endpoint, as is 2.
Related
When requesting a token and id_token from Azure using the implicit grant flow using a request like
https://login.microsoftonline.com/{tenant}/oauth2/v2.0/authorize?
client_id=6731de76-14a6-49ae-97bc-6eba6914391e
&response_type=token%20id_token
&redirect_uri=http%3A%2F%2Flocalhost
&scope=openid%20user.read
&response_mode=fragment
&state=12345
&nonce=678910
I'm successfully getting a response back with an "access_token", and an "id_token".
From what I've read, when decoding the "id_token" I should see information about the user (like name, email, picture, etc), and the "access_token" (should not be decoded) is what should be used to use as the "Bearer" token in the "Authorization" header.
When I view the token details with https://jwt.ms the "access_token" is the one with the user details, and the "id_token" has none.
When I try to access my API with the "access_token", it doesn't allow, but if I access it with the "id_token" it does.
This seems contradictory to the documentation so I'm wondering if someone can clarify for me?
You are right - the ID token is the one which gives your app information about the authenticated user, the access token is the one that you should use to access MS APIs. That said, please note the following.
When I view the token details with https://jwt.ms the "access_token" is the one with the user details, and the "id_token" has none.
What do you mean by "user details"? Usually the access token will contain some details about the user, which the APIs would need to perform proper authorization. Very often it will be the sub claim, but there might be some other claims as well. Note also that by default the ID token doesn't carry much information about the user either. You have to request other openID scopes, like profile or email to get more information about the user in the ID token. Here's the documentation of what claims you can find in the ID token, and which scopes should be requested to get these claims: https://learn.microsoft.com/en-us/azure/active-directory/develop/id-tokens.
When I try to access my API with the "access_token", it doesn't allow, but if I access it with the "id_token" it does.
What do you mean by "my API"? Is it an API you created from scratch, or some API you deployed using Microsoft tools? Are you sure that your API is configured to be accessible with an access token from Microsoft? Usually that token would be used to access MS APIs, not your own.
Depending on how the authorization server is configured, the returned id-token might not contain that many user claims.
But how will the client get the missing information?
The client can then do a background request to the UserInfo endpoint to retrieve the additional claims and user information. by doing it in this way, the id-token size is reduced.
I am using the Microsoft Graph API along with Microsoft Authentication Library (MSAL) to acquire access tokens and I can successfully retrieve the access token, id token and refresh token. I can also successfully validate the id token. However, I cannot do the same for the access token as I'm getting this error:
raise InvalidSignatureError('Signature verification failed')
jwt.exceptions.InvalidSignatureError: Signature verification failed
I've reviewed as best as I can the microsoft documentation regarding validation here:
Microsoft identity platform access tokens
For validation, I can successfully decode using the jwt.ms site for jwt validation. So I know the tokens are good. I can see from the decode the claims and extract the aud(audience) and iss(issuer). These values are not the same for the id token (which I can successfully validate).
I am using the public keys from the following url as documented:
https://login.microsoftonline.com/<TENANT ID>/discovery/keys
So, what I missing in regards to validating the access token? (if I can validate the id token with no issues). How else can i troubleshoot this?
Jim's answer is correct and there are 2 use cases really - so it depends what you are trying to do:
Getting an access token for Microsoft resources - such as Graph - in which case you don't validate them
Getting a token for your own API resources, in which case you need to validate them. For this to work you need to 'expose an API scope' to get a different type of access token
Behaviour is not intuitive in my opinion, since I like to build standards based solutions. If it helps, here is a visual blog post of mine on getting the second scenario above working.
As far as I knew, we do not need to validate Microsoft graph signature. Because MsGraph recognized an opportunity to improve security for users. They achieved this by putting a ‘nonce’ into the jwt header. The JWS is signed with a SHA2 of the nonce, the nonce is replaced before the JWS is serialized. To Validate this token, the nonce will need to be replaced with the SHA2 of the nonce in the header. Now this can change since there is no public contract. So When calling Microsoft Graph, you should treat access tokens as opaque. For more details, please refer here and here
We are using Azure AD B2C with our application.
We authorize user using the API
https://{tenant}.b2clogin.com/{tenant}.onmicrosoft.com/{policy}/oauth2/v2.0/authorize?client_id=<client-id-uuid>
&nonce=defaultNonce&redirect_uri=http%3A%2F%2Flocalhost%3A4200%2Findex.html
&scope=openid%20offline_access%20https%3A%2F%2F{tenant}.onmicrosoft.com%2F<client-id-uuid>%2FUser.all
&response_type=code&prompt=login
using above we fetch the authorization_code.
This auth code is being used to authenticate the user with the application and fetch the access_token , refresh_token and id_token using
POST /{tenant}.onmicrosoft.com/{policy}/oauth2/v2.0/token HTTP/1.1
Host: {tenant}.b2clogin.com
Content-Type: application/x-www-form-urlencoded
Cache-Control: no-cache
grant_type=authorization_code&code={auth code received in previous step}
&scope=openid%20offline_access%20https%3A%2F%2F{tenant}.onmicrosoft.com%2F<client-id-uuid>%2FUser.all
&client_id={client id}&redirect_uri=localhost%253A4200%252Flogin.html%3A
after authentication the code is used for accessing various endpoints and azure functions.
In hte process we need user attributes like email, display_name, country, etc information that user had input while singing up.
Along with default attributes we have some custom attributes like team_name which is specific to our Web application use case. These attributes change over time.
For eg: person may switch team. thus we modify that in the user attribute using Graph APIs.
so in that case if attribute team_name = 'Team ABC' now changes to team_name = 'Team XYZ'
But after the attributes are changed, the attributes do not reflect the new values in the access_token / refresh_token or id_token. Is there a way we can get the refreshed values in the tokens without re authorizing the user?
currently we fetch the user attributes from the Graph APIs but its faster and more convenient if we get refreshed values in the token.
Custom policy doesn't have a mechanism publicly documented to get new access token claims in refresh token flow. So what You have observe is expected
As a somewhat workaround, we have found out that when refreshing the authentication via SSO cookie ("Web app session" in Azure B2C configuration portal), the claims are refreshed.
I think this basically amounts to "re-logging-in" but without a user-visible prompt.
We are using the msal-browser library to do SSO login automatically for us (it uses a hidden iframe for that), but I think you could also do the same by hand.
You need to call the /authorize endpoint with all the usual query parameters, and also:
prompt=none must be set
one of sid (with account-id) or login_hint (with the username) must be set
Haven't done it myself manually, so I might still be missing something, but I think these should be the major things.
i am totally confused about the usage of OAuth and i am not sure how to use oauth for my szenario. At the moment i use a "pure" JWT approach which looks like that:
Client (JavaScript Application) send login and password to my Rest-Endpoint (Server (Java)).
Server validate user informationen, read / generate some user roles and wrap it in a JWT Token (with a secret)
Server send JWT Token back to client
Client will perform additional Rest-Calls with Authorizationen Header
Server validates Token with private secret and grand access based on roles/user
Now i think about the usage of OAuth but i am confused how to use it to realize the szenario.
I registered an application at "auth0".
I use a JS library to redirect to the login process of auth0, login via auth0 account and consume the id_token and access_token
= i can send the id_token (JWT with RSA256) to my rest api, validate it with the public certificate and can extract some user information
but:
a) i have read that i should not use the id_token to access my api. Instead i should use the access_token (which is not in JWT format and will not give me any information about the user) and use the access_token to query for the user information? That whould be the case for every request?!
b) i don't see the point where the user roles come into play. When i have some operations (rest endpoints) which are only allowed for "admins" or "customers". I don't see any possibility to define them.
You see i am a little bit confused, i hope somebody can clarify all the things.
Thanks a lot
Chris
a) Both tokens you use should be in JWT format and you should use access_token for authenticated queries. The access_token not necessarily contains information about the user, so on server side you usually can decide only that the token is emitted by the token service and is valid. If all these checks are passed, you should accept it as an authenticated user.
b) User roles can be placed into the access_token's payload section as an additive claim (e.g. role=admin,datawriter or role=customer,listreader) like many other things.
I hope it helps.
a) Sounds like you are getting an opaque access_token back and not a JWT. You'll need to create an API in Auth0 (similar to the application/client you already created). Then you pass that identifier in the audience parameter when you authenticate. Then you should get a JWT back, and that will have a sub parameter which is the Auth0 ID of the user, which can help you identify who the user is. I believe you could also use Auth0 rules if you need to put more identification info into the token. See here for a full explanation of the opaque vs. JWT access token: https://auth0.com/docs/tokens/access-token
b) Roles are tricky. I believe Auth0 would suggest that you create scopes on your API, and then request the scopes needed during login. Auth0 Rules would then be used as a sort of "glue", to adjust scopes that were requested but not permitted for the authenticated user. They also have an Authorization Extension you can use to help facilitate some of this. Another option could be storing role info in the user metadata, and using rules to put that info into the token. Finally, the option we chose was to not use Auth0 to define our roles. We let Auth0 authenticate, and once authenticated we check access in our system for the authorization side of things. Lots of options.
After authenticating with a provider, an application will often receive both an ID token and an access token on behalf of the user. Now it seems there are two ways to assert who the user is.
Verify the ID token and then read the ID token.
Pass the access token to the userinfo endpoint and read the JSON response.
Both seem like acceptable avenues, but are there certain scenarios in which one or the other should be used?
If you have both tokens and the ID token contains all info you need, you can use either way. Below are few differences that came to my mind:
Verifying and reading an ID token can be done without accessing its OAuth2 server (if you have its certificate already downloaded locally), which makes it faster and there are fewer possible errors to deal with - no network requests.
If the user info was changing often, an ID token could contain obsolete data, but it's hardly ever a case.
Access tokens can be revoked (ID tokens cannot), so if you need it, they will do the job better.
Apart from the technical differences there's a semantic difference as well: the id_token and the info in the there represents and identifies an authenticated user. That user is "present" and logs in to the application.
The access_token and the information returned from the userinfo endpoint represents information about the user who issued the access token to the entity that presents it. That user doesn't need to be "present" or logged in (anymore).
An id_token is typically "one-time usage" and an access_token usually can be used for a short period of time.
Now in the case that both tokens are issued and received at the same time when a user logs in with OpenID Connect, the two overlap.