Azure AD B2C Access token claims do not update after refreshing token - azure

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.

Related

Azure Active Directory add custom data to Oauth2 token

I'm using the auth endpoint https://login.microsoftonline.com/tenant-id/oauth2/v2.0/token programmatically (Nodejs) for getting back a token that will be used against my API. I have everything properly configured to send the request using a "Client secret" I setup on the Azure Portal - App registration service.
This issues a valid token that I can later check with the help of the Passport azure AD npm library. However I've been looking for a way of somehow adding more metadata to that token (i.e. a custom user name) so that when it gets validated and parsed by my server upon future requests I can extract this information.
When issuing tokens using a frontend application library (like msal) I have access to some of the user's information on the token (like its oid and email address). I'd like to be able to "extend" the token generated by the client secret to also contain a couple custom fields, which I can use after validating and parsing it.
Hopefully that's clear enough. I'm lost on how to achieve this. Thanks
It is a common requirement for APIs to authorize based on claims stored in the business data, eg roles or other custom data.
OPTION 1
Ideally the authorization server can reach out at the time of token issuance to an API or database to include the custom claims. This is not always supported though.
OPTION 2
Another option is for the API to process the incoming access token into a ClaimsPrincipal and to include custom values at that point. For an example see this code of mine.
PRIVACY
When adding more claims, you should also be careful about revealing sensitive data in JWTs returned to internet clients. Eg if you include names and emails, they are easily readable, and this can sometimes be a security concern.

Get a msgraph access token using another access token

I created an Azure app for which I created custom scopes through the "Expose API" screen. I have a single page application that uses the code flow to login into the application requesting these custom scopes. On my ASP.NET Core web application, I added the authentication layer to use JWT as bearer. Works pretty well and I can secure my web APIs as expected.
Now, I also added API permissions for msgraph because I want to be able to create online meetings with it. The flow would be:
The user logs in using my custom scope audience
He sends a call to a secure web api to create something
Something is added to the database
An online meeting is created on behalf of the user
The "issue" is that the access token received by my web API is not valid for msgraph, I need to get one, on behalf of the user related to the access_token. However, I have no idea how to get a msgraph token using another access_token. I don't even know if that's possible.
However, if it's not possible, how am I supposed to create the online meeting from the .NET Core part of my application ?
Take a look at the On Behalf Flow, specifically the example "First case: Access token request with a shared secret". You can use your existing access token as the assertion parameter.
The following HTTP POST requests an access token and refresh token with user.read scope for the https://graph.microsoft.com web API.
//line breaks for legibility only
POST /oauth2/v2.0/token HTTP/1.1
Host: login.microsoftonline.com
Content-Type: application/x-www-form-urlencoded
grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer
&client_id=2846f71b-a7a4-4987-bab3-760035b2f389
&client_secret=BYyVnAt56JpLwUcyo47XODd
&assertion=eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsImtpZCI6InowMzl6ZHNGdWl6cEJmQlZLMVRuMjVRSFlPMCJ9.eyJhdWQiOiIyODQ2ZjcxYi1hN2E0LTQ5ODctYmFiMy03NjAwMzViMmYzODkiLCJpc3MiOiJodHRwczovL2xvZ2luLm1pY3Jvc29mdG9ubGluZS5jb20vNzJmOTg4YmYtODZmMS00MWFmLTkxYWItMmQ3Y2QwMTFkYjQ3L3YyLjAiLCJpYXQiOjE0OTM5MjA5MTYsIm5iZiI6MTQ5MzkyMDkxNiwiZXhwIjoxNDkzOTI0ODE2LCJhaW8iOiJBU1FBMi84REFBQUFnZm8vNk9CR0NaaFV2NjJ6MFFYSEZKR0VVYUIwRUlIV3NhcGducndMMnVrPSIsIm5hbWUiOiJOYXZ5YSBDYW51bWFsbGEiLCJvaWQiOiJkNWU5NzljNy0zZDJkLTQyYWYtOGYzMC03MjdkZDRjMmQzODMiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJuYWNhbnVtYUBtaWNyb3NvZnQuY29tIiwic3ViIjoiZ1Q5a1FMN2hXRUpUUGg1OWJlX1l5dVZNRDFOTEdiREJFWFRhbEQzU3FZYyIsInRpZCI6IjcyZjk4OGJmLTg2ZjEtNDFhZi05MWFiLTJkN2NkMDExZGI0NyIsInV0aSI6IjN5U3F4UHJweUVPd0ZsTWFFMU1PQUEiLCJ2ZXIiOiIyLjAifQ.TPPJSvpNCSCyUeIiKQoLMixN1-M-Y5U0QxtxVkpepjyoWNG0i49YFAJC6ADdCs5nJXr6f-ozIRuaiPzy29yRUOdSz_8KqG42luCyC1c951HyeDgqUJSz91Ku150D9kP5B9-2R-jgCerD_VVuxXUdkuPFEl3VEADC_1qkGBiIg0AyLLbz7DTMp5DvmbC09DhrQQiouHQGFSk2TPmksqHm3-b3RgeNM1rJmpLThis2ZWBEIPx662pjxL6NJDmV08cPVIcGX4KkFo54Z3rfwiYg4YssiUc4w-w3NJUBQhnzfTl4_Mtq2d7cVlul9uDzras091vFy32tWkrpa970UvdVfQ
&scope=https://graph.microsoft.com/user.read+offline_access
&requested_token_use=on_behalf_of

Microsoft Graph API: how to get access token without browser

I would like to upload a given file to Sharepoint. I'm using the Microsoft Graph API.
The documentation follows this workflow:
1. If no token, redirect the user to the Microsoft signin page.
2. The user is then redirected to the application, with an access token
3. Use access token to have an authorization bearer
4. Do what you gotta do...
My problem is the sign-in part. I don't want my users to be redirected to the Microsoft signin page. I want my application to connect and get the access token in the background (with cURL or whatever).
How can I do that? Why is the "open in browser" necessary?
I tried to replicate the sign-in process, but all I get back is the HTML response from the signin page.
Thanks in advance.
Your application act as a single-tenant service or daemon app.
The documentation about this scenario is here : https://developer.microsoft.com/en-us/graph/docs/authorization/app_only
The application must be registered in the AzureAD directory corresponding to the Office365 tenant
A first request is made by passing the application unique identifier and secret key as registered in the directory. This request returns an access token
The access token can now be used in the Authorization header of the following request to the Microsoft Graph API.
This method (of using Client ID and Secret) works well but there are other ways which may be better suited for similar scenarios.
The one major thing which is missing in access token generated this way is a user, meaning the token only contains the identity of the OAuth application (client) which called it but is not associated with any user for the request.
This could have a couple of implications:
Since the token is not associated with a specific user you will not know who performed the operation. In your example, you would not know who uploaded the file (and other similar information may be missing).
Access token without users will not work at all for some methods. For those, you need a delegated token.
Creating a delegated token requires some effort, if you are interested you can find the details in my article:
Getting Access Token for Microsoft Graph Using OAuth REST API

Auth0 - Rules & Groups && User Management

I have created an account with Auth0 and I am trying to get a simple login for Angular 2 to our backend API.
1. What I am trying to do is to be able to access the roles in the API to see whether the user has the correct permissions.
I have enabled the Auth0 Authorization extension I have gone in and created one group and one role, I have assigned these to a test user which I have created, I have then gone to the configuration and published the rules for token contents and persistence.
How can I view the permissions/groups from the JWT in an nodejs app? I am using express-jwt and this:
const authenticate = jwt({
secret: config.get('AUTH0_CLIENT_SECRET'),
audience: config.get('AUTH0_CLIENT_ID'),
credentialsRequired: false,
});
Which is giving me details such as iss, sub, aud. But no details on the user metadata, how am I able to retrieve this? Also as I have clearly not used Auth0 before, is it best practice to store the user details on our own databases also so I can use my own ID to store against the user actions, or is it possible to use an ID if Auth0 give one to store against user actions in our database.
EDIT 1
Ok I can see there is an options parameter for the Lock which you can pass scopes in, is it bad practice to request these when logging in? There will only really be a handful of groups/roles for now. Or is better that the API can lookup the user using the token provided to get the app_metadata to view the permissions etc, if so how can I look this up?
2. How am I able to manage the users and view them so I can display them in our own admin panel and manage the permissions they have.
For the case where the groups and roles information are available within the token itself (as groups and roles claims) and given that you're using express-jwt then you can access this information on the server-side by accessing:
req.user.groups
req.user.roles
In essence, express-jwt will make the claims contained within the token available in the req.user object.
In relation to the ID you use to identify the user you can use the value contained within the sub claim of the user token. This value is guaranteed to be unique and stable so a recurring user that uses authenticates in exactly the same way will always have the same value within the sub claim.
You already discovered that one way to include the groups and roles information is to request it through the scope parameter. It's not a bad practice to request this information to be included in the token, however, you need to take in consideration that tokens delivered through the implicit grant which is used by SPA are included as a part of the callback URL and as such their maximum size is constrained by the limits imposed on URL's.
In regards to your second question, you could implement your own management backend by integrating both the Auth0 Authorization extension API and also the Auth0 Management API; see the following links for more info:
https://auth0.com/docs/extensions/authorization-extension#enabling-api-access
https://auth0.com/docs/api/management/v2

How can the Azure Active Directory Authentication Service be forced to reissue an id_token with updated claims?

We are using Azure B2C to authenticate our users which is working fine. After signup we add some custom claims to our users which were defined in the B2C portal as "User attributes" using the graph api. When I log into the portal I can see these values have been set by our calls, as have some standard claims values(i.e. we also set Display Name by concatenating the givenName and lastName values).
The issue we are having is that after these values are set, they do not appear in the token retrieved by sending the access token to the authenticate endpoints until the user is logged out and back in again (which is obviously a pretty awful user experience after signup). It looks like the original id_token is cached when the user is created and that is what is being returned instead.
This doesnt make sense, as it seems perfectly sensible to let a user update their profile (claims values) while logged into an application and for those changes to take affect immediately without needing to re-authenticate?
Could someone explain how/if it is possible to force the cached id_token on the server to expire so that when we request a id_token using an access token, the id_token contains the most up-to-date claims values?
The issue we are having is that after these values are set, they do not appear in the token retrieved by sending the access token to the authenticate endpoints until the user is logged out and back in again (which is obviously a pretty awful user experience after signup).
Would you mind show the request detail about how you acquire the id_token?
Based on my test, I can acquire the id_token with updated claim successful like steps below:
1 . sign-in a web app
2 . update the DisplayName using Azure AD Graph like below:
POST: https://graph.windows.net/xxxx.onmicrosoft.com/users/{userId}?api-version=1.6
{
"displayName":"newValue"
}
3. re-request the id_token from OAuth2.0 Authorization endpoint using HTTP request without sign-out/sign-in( You also can capture the exact request using Fiddler when you sign-in the app)
GET:https://login.microsoftonline.com/xxxx.onmicrosoft.com/oauth2/authorize?client_id={clientId}&redirect_uri={redirectURL}&response_type=id_token&scope=email+openid&response_mode=query&nonce=HWUavSky1PksCJC5Q0xHsw%3d%3d&nux=1&nca=1&domain_hint={XXXX.onmicrosoft.com}
4 . the update claim value show in the new id_token as expected
To narrow down this issue, you may see whether there is cache for the id_token in your app.
OK so after nearly a month of waiting for a response, the official line is:
"Product Group identify that this is on the roadmap even that we still don't have a final date it should happen in a few months."
So basically they haven't acknowledged it's a bug and they can't tell when this scenario will be supported. Pretty poor level of support to be honest.

Resources