Azure AD Custom Claims in JWT - azure

I have an Azure AD app and I am trying to add custom claims to a JWT. I'm using the claims mapping feature in Azure for my specific app, and updated the app manifest in the Azure Portal to include the optional claims. However, when I log in and view the decoded access token, the claim is not present in the token. I haven't found much documentation relating to using extension attributes as claims, but from what I've found it should follow the same patterns, but it is not working as expected.
How do I add a custom claim, sourced from a custom property in the user object in AD, to a JWT when the user logs in?
Thanks in advance!
Steps to re-create
Use the Azure AD Graph API to register a directory extension
Request:
POST https://graph.windows.net/mytenant.onmicrosoft.com/applications/<application-object-id>/extensionProperties?api-version=1.5
Body:
{
"name": "customUserRoles",
"dataType": "String",
"targetObjects": ["User"]
}
Write a value to the extension for a specific AD user
Request:
PATCH https://graph.windows.net/mytenant.onmicrosoft.com/users/user123#mytenant.onmicrosoft.com?api-version=1.5
Body:
{
"extension_<appId>_customUserRoles": "My Custom Role 1, Another Role 2"
}
In PowerShell, I installed the Azure AD module: Install-Module -Name AzureADPreview
Create an Azure AD policy
New-AzureADPolicy -Definition #('{"ClaimsMappingPolicy":{"Version": 1, "IncludeBasicClaimSet": "true", "
ClaimsSchema": [ { "Source": "user", "ID": "extension_<appId>_customUserRoles", "JwtClaimType": "customUserRoles" } ] } }') -DisplayName "customUserRoles" -Type "ClaimsMappingPolicy"
Add the policy to the service principal
Add-AzureADServicePrincipalPolicy -Id <service-principla-id> -RefObjectId <azure-ad-policy-id>
In the Azure Portal, navigate to Azure AD -> App Registrations -> My App -> Manifest
Update the following properties
{
...
"acceptMappedClaims: true,
"optionalClaims": {
"idToken": [
{
"name": "extension_<appId>_customUserRoles",
"source": "user",
"essential": false,
}
],
"accessToken": [
{
"name": "extension_<appId>_customUserRoles",
"source": "user",
"essential": false,
}
],
"samlToken": []
}
}
Save the file
Navigate to https://login.microsoftonline.com/mytenant.onmicrosoft.com/oauth2/authorize?client_id=<appId>&response_type=token&resource=https://mytenant.sharepoint.com and login with Azure AD user account user123#mytenant.onmicrosoft.com
In the URL, copy the value of the access_token parameter
Navigate to https://jwt.ms and paste the access token in the text area
In the decoded token section, the custom claim customUserRoles is not present
My expectation is I should see a new claim called customUserRoles or extn.customUserRoles in the decoded token.
What steps am I missing? I haven't gotten any errors throughout this process, but it doesn't appear to be working as the documentation suggests.
Reference Material
I have read through Microsoft's documentation on these topics:
Optional Claims: https://learn.microsoft.com/en-us/azure/active-directory/develop/active-directory-optional-claims
Claims Mapping: https://learn.microsoft.com/en-us/azure/active-directory/develop/active-directory-claims-mapping
I have also read through various forum posts and blog articles relating to this:
https://devonblog.com/cloud/azure-ad-adding-employeeid-claims-in-azure-ad-jwt-token/
http://www.redbaronofazure.com/?p=7566
https://social.msdn.microsoft.com/Forums/en-US/3e5114b6-24d6-4c60-b72b-b4c90baeecac/access-token-missing-optional-claims-that-are-schema-extensions-implicit-grant-flow
https://social.msdn.microsoft.com/Forums/en-US/dbeeed63-8d3f-4c27-b416-431f9fe6c729/providing-directory-extension-optional-claims-and-returning-value-within-token?forum=WindowsAzureAD

Based on this official doc :
Access tokens are always generated using the manifest of the resource,
not the client. So in the request
...scope=https://graph.microsoft.com/user.read... the resource is
Graph. Thus, the access token is created using the Graph manifest, not
the client's manifest. Changing the manifest for your application will
never cause tokens for Graph to look different. In order to validate
that your accessToken changes are in effect, request a token for your
application, not another app.
And based on your requirement , it is impossible if you want to make some change on an access token which resource is sharepoint online which is a multi-tenant app created and managed by MSFT.
For this doc , I also did some research for you . And the same , you should have control of the service side app so that you can make that happen.
This is my policy role assignment command :
$nsp = New-AzureADPolicy -Definition #('{"ClaimsMappingPolicy":{"Version":1,"IncludeBasicClaimSet":"true", "ClaimsSchema": [{"Source":"user","ID":"mailnickname","JwtClaimType":"testclaim"}]}}') -DisplayName "StanCustomCliamDemo_surname" -Type "ClaimsMappingPolicy"
Add-AzureADServicePrincipalPolicy -RefObjectId $nsp.Id -Id '<obj id of service side app>'
Token result :
What's more , pls note that extension_<appId>_customUserRoles is not a valid user source ID . For all valid user source ID , pls refer to here .
Hope it helps .

Related

Add app extension attribute in user flow JWT Azure AD B2C

I am working in Azure AD B2C to add custom extensions per application. Theses extensions must be returned in the jwt when the login is requested by the application.
So I create the extension on the app using the graph api
POST https://graph.microsoft.com/v1.0/applications/{{appid}}/extensionProperties
{
"name": "name",
"dataType": "String",
"targetObjects": [
"User"
]
}
Then I associate a value for a specific user
PATCH https://graph.microsoft.com/v1.0/users/{{userid}}
{
"extension_{{appid(without dashes}}_name": "1234"
}
Now I go on the app manifest to add the optional claim.
"optionalClaims": {
"idToken": [
{
"name": "extension_{{appid(without dashes}}_name",
"source": "user",
"essential": true,
"additionalProperties": []
}
],
"accessToken": [
{
"name": "extension_{{appid(without dashes}}_name",
"source": "user",
"essential": true,
"additionalProperties": []
}
],
"saml2Token": []
},
Save but the claim never appear on the jwt token.
I also tried using the answer of this post but didn't work either.
The problem is you’ve used Optional claims setup, which works for AAD but not AAD B2C.
Follow this: https://learn.microsoft.com/en-us/azure/active-directory-b2c/user-flow-custom-attributes?pivots=b2c-user-flow
If you want to select your custom attribute through the Azure Portal - AAD B2C - User Attributes blade, and the attribute was created via Graph API, you have to recreate it in the Portal for it to reconcile.
You would also need to target the b2c-extensions-app AppId when defining the attribute with Graph API.
I tried to reproduce the same in my environment and got the claims successfully
As Jas Suri - MSFT commented, this will only work if you are adding optional claims to Azure AD application.
I created the extension attribute via Graph API like below:
I associated the above extension attribute to a specific user like below:
Please check whether that extension attribute is visible in optional claims UI or not and add like below:
When you check the manifest, it will be added automatically like below:
I generated the JWT token using auth-code flow via Postman like below:
After decoding the JWT token (ID-Token), I got the claims successfully like below:

Azure AD service principal add optional claim value with powershell

I am trying to create GCP workload identity federation with Azure AD service principal but when I am trying to create the initial sts token with GCP I get bad request. I am suspecting that the problem is that my audience currently on jwt token is "https://management.azure.com" where it should be the audience that is set in the GCP WiF configuration. Currently I am getting the Azure AD accesstoken with:
$AzContext = Get-AzContext
$accesstoken = [Microsoft.Azure.Commands.Common.Authentication.AzureSession]::Instance.AuthenticationFactory.Authenticate(
$AzContext.'Account',
$AzContext.'Environment',
$AzContext.'Tenant'.'Id',
$null,
[Microsoft.Azure.Commands.Common.Authentication.ShowDialog]::Never,
$null,
'https://management.azure.com/'
).AccessToken
But is it possible to extend this command to populate my optional claim? Currently my manifest looks like this:
"optionalClaims": {
"idToken": [
{
"additionalProperties": [],
"essential": false,
"name": "onprem_sid",
"source": null
}
],
"accessToken": [],
"saml2Token": []
},
How I managed to get the proper audience in place without optional claims is that I used the application id with the tenant name:
$AzContext = Get-AzContext
$accesstoken = [Microsoft.Azure.Commands.Common.Authentication.AzureSession]::Instance.AuthenticationFactory.Authenticate(
$AzContext.'Account',
$AzContext.'Environment',
$AzContext.'Tenant'.'Id',
$null,
[Microsoft.Azure.Commands.Common.Authentication.ShowDialog]::Never,
$null,
'https://cfbf35b2-6346-48dc-9ac2-b77e77f90933.mytenant.onmicrosoft.com'
).AccessToken
I also did put that as my application id URL and the audience on GCP configuration and managed to get proper token from GCP.
• To get optional claims in the Access token, you will have to define them in your app manifest since access tokens are always generated using the manifest of the resource, not the client. To configure optional claims,
Go to the Azure portal.
Search for and select Azure Active Directory.
Under Manage, select App registrations.
Select the application you want to configure optional claims for in the list
Then under manage, select manifest option which opens an editor and edit the access token option in it as given below as a sample for reference to get the optional claims configured in the access token. Once finished, save it and the claims will be included in the token for your application: -
The following application manifest entry adds the auth_time, ipaddr, and upn optional claims to ID, access, and SAML tokens.
‘ "optionalClaims": {
"idToken": [
{
"name": "auth_time",
"essential": false
}
],
"accessToken": [
{
"name": "ipaddr",
"essential": false
}
],
"saml2Token": [
{
"name": "upn",
"essential": false
},
{
"name": "extension_ab603c56068041afb2f6832e2a17e237_skypeId",
"source": "user",
"essential": false
}
]
} ‘
So, once you save the manifest with the above said changes and request an access token as usual according to the command stated by you, these mentioned optional claims will be included in the JWT access token.
Please refer this below link for more information: -
https://learn.microsoft.com/en-us/azure/active-directory/develop/active-directory-optional-claims#configuring-optional-claims

Can we add a extra claims in Azure AD Groups when we create them via Graph API?

Is it possible to add extra properties to the Azure AD groups when we create them in azure ad b2c via graph api. Just like we do it for users (we can add claims to the user)
I am not able to find any resource for this. let me know if that is possible.
Thanks!
Yes. You could do that.
Find the "b2c-extensions-app" under Azure AD B2C - App registrations (Preview) in Azure AD B2C. It's the app which stores the extension property in Azure AD B2C. Record its object ID.
Use the following call to register an extension in the app above. Reference here.
POST https://graph.windows.net/{your B2C tenant}/applications/<applicationObjectId>/extensionProperties
{
"name": "customAttribute",
"dataType": "String",
"targetObjects": [
"Group"
]
}
Then you will get an extension for Group in the response: extension_{client id of b2c-extensions-app}_customAttribute.
Now create a group with the extension property.
POST https://graph.windows.net/{your B2C tenant}/groups
{
"displayName": "Example Group",
"mailNickname": "ExampleGroup",
"mailEnabled": false,
"securityEnabled": true,
"extension_{client id of b2c-extensions-app}_customAttribute": "customAttribute for group"
}

How to get user role claims in postman from Azure active directory?

I have a few users added to my Azure AD account, I would like to get the roles and user information on these users by calling an Azure API from Postman in the form of claims. I tried calling the following URL with the parameters as :
https://login.microsoftonline.com/myTenantId/oauth2/token
Body:
grant_type : password,
client_id : client id,
client secret : client secret
I receive the access_token in the encoded format in the response, When I decode it on https://jwt.io/ I see the decoded data, but there's no user roles in the access_token.
I would like to get the user information and the roles in the form of claims in same response.
What approach would I need to take on this ?
If the role you mentioned refers to directory role, the answer is no, it won't be returned in the token. Just like juunas said, you can call graph api to get directory role information.
If the role you mentioned refers to application role, the answer is yes, you can get the role information in id_token. The prerequisite is that you have assigned some roles to the user.
Here are the detailed steps. You can also refer to this article.
edit the manifest to add some custom roles.
Something like this.
{
"allowedMemberTypes": [
"User"
],
"displayName": "Test",
"id": "c200e304-fff3-49f1-a4df-e406741ea680",
"isEnabled": true,
"description": "Bla bla",
"value": "test"
}
2.assign users to roles.
Click Enterprise applications->All applications->
Click your application->click Users and groups->click Add user
role assign.
Here is the request to get id_token.
You will find the roles in id_token.

Azure Active Directory RBAC Not Returning Roles in Bearer Token

I'm using the Azure AD Basic tier with an ASP.NET Core API, I've followed the RBAC sample. I've set up an application with roles in my manifest like so:
appRoles": [
{
"allowedMemberTypes": [ "User" ],
"displayName": "Read Device",
"id": "b2e6f6c2-c3d5-4721-ad49-0eea255ccf45",
"isEnabled": true,
"description": "Can read a device.",
"value": "read_device"
},
...
]
I've setup my API to use the UseJwtBearerAuthentication middleware like so:
application.UseJwtBearerAuthentication(
new JwtBearerOptions()
{
AuthenticationScheme = "Azure Active Directory",
Authority = options.Authority,
Audience = options.ClientId,
TokenValidationParameters = new TokenValidationParameters()
{
RoleClaimType = "roles",
ValidateIssuer = false
}
})
I've given my user the above 'Read Device' role:
I'm using Swagger UI to make the call to get the auth token. It calls the following URL:
https://login.microsoftonline.com/[Tenant].onmicrosoft.com/oauth2/authorize?
response_type=token
&redirect_uri=http%3A%2F%2Flocalhost%3A5100%2Fswagger%2Fo2c.html
&realm=-
&client_id=[Client ID]
&scope=http%3A%2F%2Fschemas.microsoft.com%2Fws%2F2008%2F06%2Fidentity%2Fclaims%2Frole
&state=oauth2
&resource=[Client ID]
I suspected that I am not passing the correct values to the scope parameter, so I have tried asking for every scope I can think of:
&scope=openid
%20email
%20profile
%20offline_access
%20user_impersonation
%20roles
%20http%3A%2F%2Fschemas.microsoft.com%2Fws%2F2008%2F06%2Fidentity%2Fclaims%2Frole
%20read_device
If I set "groupMembershipClaims": "All" in my manifest I can see group claims but I want roles instead. I'm able to login to call my API, however I never get any roles back in my JWT token, so I'm unable check the users role. What am I doing wrong?
It turns out I needed to request an id_token instead of a token. An id_token contains extra claims/scopes/resources about the user. I also needed to provide a nonce parameter containing a new random GUID on every request. Thus, I ended up with the following URL:
https://login.microsoftonline.com/[Tenant].onmicrosoft.com/oauth2/authorize?
response_type=id_token
&client_id=[Client ID]
&redirect_uri=http%3A%2F%2Flocalhost%3A5000%2F
&nonce=9ac5ad8d-df44-48e6-9bd6-e72743b3625c
If you are want to enable the role be assigned to users or groups(allowedMemberTypes=User) :
If you want to perform authorization using role claims , you could
follow the steps in this code sample , you could find the roles
claim is in the id_token .
If you want to make a client app to call your web api , when user
sign in ,app could check the access rules based on the role
claim,
you could use delegate flow(OAuth Authorization Code Grant,Implicit
Grant Flow..),roles claim is in the access_token ;
If you want to specify the role be assigned to client applications(allowedMemberTypes=Application), you could use OAuth Client Credential Flow ,appRoles of resource app/api that are assigned to the client app, and you will find the roles claim in the access_token ,check the detail steps from here.
Please click here for more details .
In my case I had mistakenly configured the App Registration to emit Security Groups as roles claims, thus overwriting the App Roles from the manifest. Removing the optional groups claim and logging back in correctly emitted the App Roles names in the roles claim of the id_token.

Resources