AAD B2C - Missing upn claim in access token - azure

I have an Angular Application which is authenticated using AAD B2C. This talks to a .Net Core API using an access token.
My problem is that I am not receiving a User Principal Name (upn) in my access token.
I have been adding additional "Application claims" like "Given name" and "Surname" and these appear in my access token just fine! Therefore, I believe that my scopes (openid, profile, email) are set correctly and that this in theory is working.
I believe since I am using version 1.0 of the token, that I do not need to configure an any additional claims in my application manifest. My user is a standard AD user not a guest.
The following document states that the upn claim should be included in the v1.0 tokens:
https://learn.microsoft.com/en-us/azure/active-directory/develop/active-directory-optional-claims
What am I doing wrong?!
Decoded Access Token:
{
"iss": "https://(my-tenant-name).b2clogin.com/(guid)/v2.0/",
"exp": (number),
"nbf": (number),
"aud": "(guid)",
"oid": "(guid)",
"sub": "(guid)",
"name": "My Name",
"given_name": "Given name",
"family_name": "Surname",
"country": "Norge",
"tfp": "B2C_1_signupsignin2",
"nonce": "(guid)",
"scp": "basic",
"azp": "(guid)",
"ver": "1.0",
"iat": (number)
}

UPN is not returned in AAD B2C tokens because it is an irrelevant random string that is set.
Rather AAD B2Cs unique name is stored in signInNames attribute, and returned in your token as email or username.
The doc you linked is for AAD, and irrelevant to AAD B2C. These are two seperate token issuer services. Select in your User Flow Application Claims to return “email addresses”.
https://learn.microsoft.com/en-us/azure/active-directory-b2c/user-flow-overview#email-address-storage

At this time, apps that support both personal accounts and Azure AD (registered through the app registration portal) cannot use optional claims. However, apps registered for just Azure AD using the v2.0 endpoint can get the optional claims they requested in the manifest.
To achieve UPN Claim in the token, use B2C Custom Policy.
Refer this link for the starter pack: https://github.com/Azure-Samples/active-directory-b2c-custom-policy-starterpack
Add below claim to the TechnicalProfile AAD-UserReadUsingObjectId and in the Relying Party Policy (Eg: SignUpOrSignin.xml):
<OutputClaim ClaimTypeReferenceId="userPrincipalName" />

As per the code you have provided we observed you are using v2 endpoint( "iss": "https://(my-tenant-name).b2clogin.com/(guid)/v2.0/")
As per the document if you see iss:If the token was issued by the v2.0 endpoint, the URI will end in /v2.0.
In the V2 endpoint you need to make a request explicitly for UPN claim.
In v1.0 endpoint they are returned by default but v2.0 made smaller tokens so they made it optional.
Please go through the following links for more understanding. https://learn.microsoft.com/en-us/azure/active-directory/develop/active-directory-optional-claims How to add optional claims in application manifest https://learn.microsoft.com/en-us/azure/active-directory/develop/reference-app-manifest

Related

Retrieve custom claim from federating IdP access token in Azure AD B2C custom policy

I am configuring an OIDC-based SSO flow in Azure AD B2C using custom policy to allow users to login to downstream applications with their federated identity provider's (IdP) credentials. Custom policy is used to allow some complex business logic to be run prior to providing the token to the downstream applications.
The flow is correctly redirecting users to the external IdP for login and ultimately back to my downstream applications with associated claims. However, there is a custom claim that is only available in the access token received by B2C from the external IdP (not the ID token), and I can't figure out how to retrieve this claim from the access token to be used in the B2C user journey and ultimately provided with all the other claims to the downstream applications.
I can see that B2C does receive both the ID and access tokens by reviewing Application Insights logs (sample output):
"TESTtechnicalprofile": {
"ContentType": "Jwt",
"Created": "2022-10-15T07:37:45.8678974Z",
"Key": "TESTtechnicalprofile",
"Persistent": true,
"Value": "eyJhb..."
},
"TESTtechnicalprofileaccess_token": {
"ContentType": "Unspecified",
"Created": "2022-10-15T07:37:45.8678974Z",
"Key": "TESTtechnicalprofileaccess_token",
"Persistent": false,
"Value": "eyJhb..."
},
And general format of the payloads of the tokens is as follows:
ID Token
{
"<name of custom claim I can retrieve>": "custom claim value",
"iss": ...,
...
}
Access Token
{
"<name of custom claim I cannot retrieve>": "custom claim value",
"iss": ...,
...
}
I can successfully retrieve claims from the ID token by mapping from the partner claim type:
<OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="<name of claim containing email in ID token>" />
However this same method doesn't work for claims in the access token. If I reference the name of the custom claim in the access token in PartnerClaimType then B2C omits the claim (presumably because it fails to retrieve it).
I've tried retrieving the access token itself as a claim using the method described here and that works (token in claim matches token seen in Application Insights logs), however I'm not sure if it's possible to decode this token in B2C policy and subsequently pull claims from it (or even if one would want to do that).
While I could let the downstream applications retrieve what they need from the access token, I have business logic in my user journey that needs this claim prior to providing the final token to the applications.
Following up here for anyone else trying to do the same, according to Microsoft Support it isn't possible to extract a claim from an access token in B2C policy. I ended up crafting a workaround involving calling an external REST API from B2C to retrieve the needed info for the user journey.

Azure Ad B2C vs Keycloak

I have a question regarding keycloak and Azure Ad b2c. Both offres authentication with different identity providers. Main difference I can see is in authorization. With Keycloak I can easily manage claims and roles of users via admin portal. In Azure B2c it looks very hard (setting custom policies) maintaining all the data via custom created app. Am I missing something? Relying app is strongly cloud native (Azure of course) and thats why I'm thinking about azure b2c. Relying app will strongly use roles and claims also.
What do you think about these two identity solutions (pros and cons).
What is the easiest way to manage implemented (by custom policies) user claims and roles in azure b2c? (do I have to write separate management app by myself or there is easiesy solution?)
Edit: first conclusion is that right nów azure requires separate app for connecting to graphapi (via rest or using sdk). Keycloak has it built in. Any pros of using b2c in this case (for c# dev)?
You don't have to use custom policies to use custom claims. Below an example :
On your B2C tenant, go to Azure AD B2C > Manage > User attributes and create a custom attribute; here a client ID attribute :
Then Azure AD B2C > Policies > User flows and create a flow, for example "Sign In" :
Use the recommended flow :
During the flow's creation, at the last steps, you can specific what claim will be included in the returned jwt token on Sign in; select our custom attribute Client ID :
Then when I login into my application using a B2C account, I have the below JWT token returned :
JWT token's payload, base64 decoded :
{
"iss": "https://mytenant.b2clogin.com/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/v2.0/",
"exp": 1664181788,
"nbf": 1664178188,
"aud": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"oid": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"sub": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"extension_ClientID": 1,
"name": "myUserName",
"emails": [
"user#email.com"
],
"tfp": "B2C_1_SI",
"nonce": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"scp": "user_impersonation",
"azp": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"ver": "1.0",
"iat": 1664178188
}
I have set the "extension_ClientID": 1 using the msGraph API but this could also be done using a SignUp flow.

Not able to retrun access token in custom policy with local login

I have written one custom policy in azure AD b2c and its working ok , Now i want to return the access token as well if some one login from social media account i am able to return access token but with local account login i am not sure what steps needs to follow , Can any one help me on this
login via social media: Claims like below works fine
{
"exp": 7676868,
"nbf": 6868712,
"ver": "1.0",
"iss": "xyxjhgjgjg/v2.0/",
"sub": "26cd4=jfh1-9e4f-4d74-a4bd-afjhhdfkj6",
"aud": "584nczac-f6ba-4d42-a051-859700f247cj,
"acr": "b2c_1a_signuporsigninwithphoneoremail",
"iat": 1622700jhj,
"auth_time": 1622700447,
"givenName": "mnmn",
"surname": "nbnbnb",
"name": "nbvnvnv",
"idp_access_token": "v117OqsDGUyPjPlqmjfRCZB7zrsWZBxfzhgj,mnn,lwIEuDVyvE3VsH4cuZAf",
"tid": "d302bdbnbvv-09e5-42bf-9006-6bjhgjg"
}
When you login via a social idp, the user enters their credentials on the social idp page, and in return gets an access token which B2C can use to grab their information after consent.
There is not the case for local accounts, because when the user logs in using a local account, they enter their credentials on the B2C idp itself. The access token is what constitutes these entire claims you have shared.
So in essence, when using social idp, there are two access tokens, one related to B2C, which constitute the entire claims, and another related to the social idp, which you highlighted in your question.

Azure AD B2C Github identity provider does not provide any claims

I want to use the AAD B2C Github identity provider to authorize users in my app. To create a user I need at least get an email from it - but I get nothing. I did set up everything according to docs and I can see in the AAD B2C Users list that Name is set up correctly for a new user, but User Principal Name where email should be is null
Here is JWT answer
{
"typ": "JWT",
"alg": "RS256",
"kid": "X5eXk4xyojNFum1kl2Ytv8dlNP4-c57dO6QGTVBwaNk"
}.{
"exp": 1611879546,
"nbf": 1611875946,
"ver": "1.0",
"iss": "https://apichat.b2clogin.com/4d39cd56-4c18-4bc7-aaa8-36bf91191c8c/v2.0/",
"sub": "dfe38752-113e-4431-b1bd-23dd53119369",
"aud": "341eea81-859c-485c-baea-2cc9f75f6512",
"nonce": "defaultNonce",
"iat": 1611875946,
"auth_time": 1611875946,
"idp_access_token": "c5c79a8f49c44575cf127fc3c64aaa5710a0a465",
"idp": "github.com",
"tfp": "B2C_1_susi_debug"
}.[Signature]
What do I missing?
Added
After some studying, I have a suspicion that the Github provider here either does not have the required scopes or mappings. I don't see any ways to add it so far. Potentially that might be solved by a generic OpenID Connect provider but Github does not support well-known/openid-connect-discovery and I have no option to manually set endpoints in AAD B2C.
So far I don't see any way to connect GitHub to my AAD B2C and get that darn email - why the biggest cloud platform does not fully support the biggest dev repository when they have the same owner is beyond my understanding.
Ok, the solution I found looks like that
Set Display Name and Identity Provider Access Token in Application Claims of your User Flow
On GitHub auth you will get name aka username and idp_access_token aka token
That's allow us to call github user api curl -u username:token https://api.github.com/user
By default user api returns public user profile, which might not have a set email
curl -u username:token https://api.github.com/user/emails will return all user associated emails
We need the primary one
{
"email": "***#gmail.com",
"primary": true,
"verified": true,
"visibility": "public"
}

Microsoft graph and Azure Ad user authentication

I have an application registered in Azure ad.
When i do ADAL with the following details i get a authoriazation token to use with microsoft graph api.
`username = 'admin#domain.com'
password = 'password123'
client_id = application id from azure ad
client_secret = keys from application on azure ad
tenant = directory id from azure ad`
Using this token i can fetch the list of all sites in my sharepoint account.
Below is the endpoint i call to fetch the sites with the bearer token:
https://graph.microsoft.com/v1.0/sites?search=*
But when I just do the client authentication using token generated using below endpoint Iam not able to access the sites list.
login.microsoftonline.com/tenant_id/oauth2/v2.0/token
`grant_type : client_credentials
clientid : client_id
clientsecrte : client_secret
scope : https://graph.microsoft.com`
It does not return all of the sites.
Is there a way of getting all sites list with just client authentication.
Or can i get a token for user authentication without user password.
Here is the token decoded that i am using:
{
"aud": "https://graph.microsoft.com",
"iss": "https://sts.windows.net/586145ec-0428-4da6-8061-fb114257ab70/",
"iat": 1528949458,
"nbf": 1528949458,
"exp": 1528953358,
"aio": "Y2dgYLh*************xAAA=",
"app_displayname": "App Name",
"appid": "504ddb16-2899-48be-be57-**********",
"appidacr": "1",
"idp": "https://sts.windows.net/586145ec-0428-4da6-8061-fb114257ab70/",
"oid": "afcf166f-24c2-49f1-b285-b672d0413c50",
"roles": [
"Sites.Read.All",
"Sites.ReadWrite.All",
"Sites.Manage.All",
"Sites.FullControl.All",
],
"sub": "afcf166f-24c2-49f1-b285-b672d0413c50",
"tid": "586145ec-0428-4da6-8061-fb114257ab70",
"uti": "hwYd8FZCH0KruWGRFiIHAA",
"ver": "1.0"
}
I get other permissions also but these are site related in Microsoft Graph api
Cause:
The successful one is using ROPC flow and it can get delegated permissions onbehlaf of the user. But the failed one is using client_credentials flow which get application permissions and cannot onbehlf of the user.
Updated Answer
Solution:(Before you do this test, ensure you have SPO license in your tenant)
Try to add Sites.Read.All Application permission in your registrated AAD Application and do admin consent for it before you getting token.
If you're using AAD v1 endpoint, you can do admin consent by clicking Grant permissions button.If you're using v2 endpoint, please input this kind of URL in your internet browser to do admin grant:
https://login.microsoftonline.com/{yourtenant}/adminconsent?client_id={the applicationid of your client}&state=123&redirect_uri={the redirect uri of your app}
and sign in with Global admin account and accept this permission.
In my test lab, I used v2 endpoint.Here is the token I got via Postman:
Here is decoded token in https://jwt.ms , we can decoded the token to ensure it has the permissions we want.
Then I use this token in the head to call Microsoft Graph API and succeeded:
For more detials about Site permission for Microsoft Graph, please refer to this documentation.
Please let me know if this helps!

Resources