How to add optional claims to B2C access tokens - azure-ad-b2c

According to https://learn.microsoft.com/en-us/azure/active-directory/develop/active-directory-optional-claims it should be possible to add optional claims to a JWT access token or ID token issued by Azure AD, and email is a predefined optional claim. We have added these lines to the manifest for the API application (and to the client application, just in case we were misunderstanding):
"optionalClaims": {
"idToken": [],
"accessToken": [
{
"name": "email",
"source": null,
"essential": true,
"additionalProperties": []
}
],
"saml2Token": []
},
The issuing of ID tokens and access tokens continues to work as before. But access tokens on behalf of an authenticated user whose profile does have an email still do not include the email claim. We originally set essential to false, but that value has made no difference. The email claim is included, and always has been, in the ID token returned to the client by our custom policy.
We are working in an Azure B2C tenant, not AAD, and I wonder if optional claims are not supported in B2C access tokens. Is that the case, or is there something else we just aren't understanding about this documentation?

Related

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

How to add optional claims to access token when using azure oauth client credential flow

In my scenario there is a Azure Application Registration (client_app) with credentials. This application is used to request an oauth2 access token. A second Application Registration (main_app) is the scope, which is providing App Roles and more.
My goal is to include information from client_app in a jwt token claim, when requesting the token using the client credential flow on an azure /oauth2/v2.0/token endpoint.
This is a token request:
POST /<tenant id>/oauth2/v2.0/token HTTP/1.1
Host: login.microsoftonline.com
Content-Type: application/x-www-form-urlencoded
client_id=<Application ID of client_app>
&client_secret=<secret of client_app>
&scope=<Application ID URI of main_app + "/.default">
&grant_type=client_credentials
The response of the token request is a valid token including roles (granted App Roles from main_app to client_app), aud, sub and idtype: app claims. But my optional claims are missing.
MS docs state, that it is possible to include optional claims using directory extensions
Schema and open extensions are not supported by optional claims, only the AAD-Graph style directory extensions. This feature is useful for attaching additional user information that your app can use [...]
So I tried adding a directory extension to my main_app (extension_<main_app ID>_someAttrName), added an optional claim to main_app and stored a value to this directory extension in client_app. Unfortunately the extension value is not reflected in the token.
I tried adding the directory extension on the client_app itself (extension_<client_app ID>_someAttrName) and map the directory extension to main_app by using ClaimsMappingPolicy. Unfortunately the extension value is not reflected in the token.
It seems to me, that the claims are missing, since they do not originate from a user object. MS docs provide a lot of information to add optional claims, but most scenarios involve a user. E.g. the optional claims source property of a manifest:
The source (directory object) of the claim. There are predefined claims and user-defined claims from extension properties. If the source value is null, the claim is a predefined optional claim. If the source value is user, the value in the name property is the extension property from the user object.
As I understand it, only null and "user" is supported. I want to include a directory extension originating from an Application Registration (client_app). And since I have to use the client credential flow (server-to-server) there is no user involvement.
So how do I add custom optional claims to a token when using client credential flow, when no user object is involved? There is an application object involved. So how do I need to configure claims to reflect custom application data (e.g. directory extensions)?
Manifest of main_app:
{
"id": "<main_app ID>",
"acceptMappedClaims": true,
"accessTokenAcceptedVersion": 2,
"appId": "<main_app APP ID>",
"appRoles": [{
"allowedMemberTypes": ["Application"],
"isEnabled": true,
"origin": "Application",
"value": "readAll"
},{
"allowedMemberTypes": ["Application"],
"isEnabled": true,
"origin": "Application",
"value": "writeAll"
}],
"identifierUris": ["api://<main_app ID>"],
"optionalClaims": {
"idToken": [],
"accessToken": [ {
"name": "extension_<main_app ID>_someAttrName",
"source": "application", <-- propably invalid, "user" or null is supported
"essential": false,
"additionalProperties": []
}, { ... }
],
},
} /# trunced for readability
Manifest of client_app:
{
"id": "<client_app ID>",
"accessTokenAcceptedVersion": null,
"appId": "<client_app APP ID>",
"passwordCredentials": [{...}],
"extension_<main_app ID>_someAttrName": "some-string-value"
} /# trunced for readability
My ClaimsMappingPolicy definition looks like this:
"ClaimsMappingPolicy": { "Version": 1, "IncludeBasicClaimSet": "true",
"ClaimsSchema": [ {
"Source": "application",
"ExtensionID": "extension_<client_app ID>_someAttrName",
"JwtClaimType": "someAttrName"
} ]
}
I reached out to Azure support engineers, and they told me, that it's not possible to include directory extension based claims originating from Application Registrations. They did not go into detail but replied this:
I apologize to inform we got to know that reflecting extension claims in JWT token won't be possible. Since directory extensions can't be added to servicePrincipal objects.
I'm assuming the requesting entity is a service principal when using the client credentials flow.

Azure OAuth2 Code Flow - no groups claim in access token (and no "hasgroups" either)

I am using OAuth2 Code flow and trying to get the user's groups back in my access token. Everything I'm reading says I should see either a groups claim or a hasgroups claim, but I see neither.
I've altered the following fields in the App registration manifest for my client app:
"groupMembershipClaims": "SecurityGroup",
"optionalClaims": {
"idToken": [],
"accessToken": [
{
"name": "groups",
"source": null,
"essential": false,
"additionalProperties": [
"dns_domain_and_sam_account_name"
]
}
],
"saml2Token": []
},
Here is an example of my querystring for the login redirection url (login.microsoftonline.com)...
client_id=<clientId>
&response_type=code
&redirect_uri=<redirectUri>
&response_mode=query
&scope=<appScope>%20offline_access
&state=67890
Here is an example of my querystring for my requesting the token using authCode (login.microsoftonline.com/{tenantId}/oauth2/v2.0/token)
client_id=<clientId>
&scope=<uriEncodedScopes>%20offline_access
&redirect_uri=<uriEncodedRedirectUri>
&code=<authCode>
&client_secret=<uriEncodedClientSecret>
&grant_type=authorization_code
Everything is working great, but I can't figure out how to get groups info back in my token.
UPDATE
I added %20openid to my scope in both urls, and now I'm getting an id_token, but I still don't see "groups" or "hasgroups" in either token.
UPDATE
I just added the same manifest changes (groupMembership, optionalClaims) to my API App Registration (instead of my client) - the API that exposes the scope, and I see no change whatsoever. Access token and Id token don't have any reference to groups at all.
Per my test, it should work. And you just need to configure the groupMembershipClaims, optionalClaims in your API App Registration, refer to the reason below.
You could refer to my test sample below, I tried with a work account or personal account, both work.
Request the authorization code(the api://3e013fde-xxxxxxa422f3/User.Test is my API permission):
https://login.microsoftonline.com/<tenant-id>/oauth2/v2.0/authorize?
client_id=xxxxxxxxxxxxxxx
&response_type=code
&redirect_uri=https://localhost
&response_mode=query
&scope=openid offline_access api://3e013fde-xxxxxxa422f3/User.Test
&state=12345
Request the token:
Decode the token in https://jwt.io/, the groups claim is included.
Note:
My client App and API App are both created today, I suppose there are may some difference between the app created in the old App Registration(it is not existing in the portal currently), app registration portal(it has been moved to the new App Registrations), new App Registration(theApp Registrationin portal currently).
And from this doc:
There is also a weird thing during my test, when I create a new API App Registration, just set "groupMembershipClaims": "SecurityGroup" without setting optionalClaims, the manifest will be like below.
"groupMembershipClaims": "SecurityGroup",
"optionalClaims": {
"idToken": [],
"accessToken": [],
"saml2Token": []
}
Then the Access token will not include groups, the ID token has the groups.
If I set it with yours, the Access token will have the groups.
"groupMembershipClaims": "SecurityGroup",
"optionalClaims": {
"idToken": [],
"accessToken": [
{
"name": "groups",
"source": null,
"essential": false,
"additionalProperties": [
"dns_domain_and_sam_account_name"
]
}
],
"saml2Token": []
}
But when I set it return to
"groupMembershipClaims": "SecurityGroup",
"optionalClaims": {
"idToken": [],
"accessToken": [],
"saml2Token": []
}
The Access token still has the groups.
From the portal - Token configuration (preview) and this doc - Configure group claims for applications with Azure Active Directory (Public Preview), the feature should be in preview, it may be a bug(I am not sure).
So in conclusion, I recommend you to use two new Apps to have a try.

How to add a User as a Member from another IDP?

We have ADB2C tenant with a Identity Provider setup to an Okta setup in another Organization via Open ID Connect.
We have a Admin UI to add users. I see that GraphAPI has a createUser which takes a json with Password and changePwdOnFirstUse setting. This is fine to add a direct member to ADB2C.
The problem I have is that, how can I add the User from the other Okta
Organization so that when this user logs in to my App (and is authenticated by Okta), can login to my App.
At present, after authentication from Okta, we see User not found Error.
I suppose, I cannot add this user via Graph API using same createUser method as this user password is not something we are supposed to manage.
How do I add this other Organization user to ADB2C, so that I do not see this "User not found" issue?
Thanks.
Using Azure AD Graph API, you can create an external account user, with the userIdentities property of the user object being set to the sub (subject) claim of Okta's ID token:
{
"accountEnabled": false,
"displayName": "John Smith",
"mailNickname": "john.smith",
"otherMails": [
"john.smith#company.com"
],
"userIdentities": [
{
"issuer": "{okta-id-token-iss-claim-value}",
"issuerUserId": "{okta-id-token-sub-claim-value}"
}
],
"userPrincipalName": "{guid}#{your-tenant-name}.onmicrosoft.com"
}
where issuerUserId must be set to the base64 encoding for the sub claim of Okta's ID token.

How to add additional claims to ID Token - Azure Government Portal

I'm trying to overload the OAuth ID Token by adding additional claims. I can already use the Graph API to get the claims that I need but I would like to understand if it's possible to add the additional claims directly into the ID Token? I've updated the manifest by adding the required claims in and then flipping "acceptMappedClaims" to true, however I still don't see these in the ID token. What am I missing?
"optionalClaims": {
"idToken": [
{
"name": "employeeid",
"source": "user",
"essential": true,
"additionalProperties": []
},
{
"name": "mail",
"source": "user",
"essential": true,
"additionalProperties": []
}
],
"accessToken": [],
"saml2Token": []
},
"acceptMappedClaims": true,
This depends on where the ID token is generated from. If it's on-premises AD and federated identity is used take a look at Customizing the OIDC id_token in ADFS 2016.
If it's just a cloud identity I'd take a look at the second link jwmiller5 posted or this one: how-to-set-claims-from-asp-net-openid-connect-owin-components.
Hope this helps,
Bernie
If you are trying to add additional claims into your AD token, you would need Azure AD premium and you can add the values as attributes. See Claim augmentation with Azure AD authentcation
If you just need the claims in one particular application, you can add the claims in the app itself. See Azure AD PostAuthentication add claims

Resources