Azure AD Directory Extensions claims missing - azure-active-directory

I have added about 18 extension claims to my access token. Based on the application state you may get different claims from this list. I'm sure that those claims have some values assigned. But for some reason, I'm not receiving all of them as part of my JWT Access token. I can get these values using graph API.
Example of extension claim from jwt token:
"extn.***_**_CreatedDate": [
"30/09/2022 12:21:01 PM +00:00"]
Example of application manifest token configuration:
"optionalClaims": {
"idToken": [
{
"name": "extension_someguid_***_***_CreatedDate",
"source": "user",
"essential": false,
"additionalProperties": []
}]
}
Are there any limits on clams/extension claims count added to AAD access token?

If application sends the claims with data in the form of extension attribute registered on a different application, a claims mapping policy must be used to map the extension attribute to the claim.
New-AzureADPolicy -Definition #('{
"ClaimsMappingPolicy":
{"Version":1,
"IncludeBasicClaimSet":"true",
"ClaimsSchema": [
{
"Source":"user",
"ID":"employeeid",
"SamlClaimType":"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/employeeid","JwtClaimType":"employeeid"
},
{
"Source":"company",
"ID":"tenantcountry",
"SamlClaimType":"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/country",
"JwtClaimType":"country"}]}}')
-DisplayName "ExtraClaimsExample"
-Type "ClaimsMappingPolicy"
accesstokenAcceptedVersion must be set to supported value 1, 2, or null , depends on the issuer enpoint obtained from the token.
"acceptMappedClaims" must be set to true, for single tenant app.
Also do make sure to give claims under accessToken in manifest .
Note:
If want to have the claims in the access token then you may need to modify the manifest of the resource app. i.e.; If you have an web App
that calls Web API B and you want the claims in the access_token then
you need to modify the manifest of web api B.
Only extension attributes on user objects can be used for emitting claims to applications.
When adding claims to the access token, the
claims emitted are for a web API and not requested by the
application. So you will be able to see only claims emitted are for
access tokens requested for the application webApi.
Reference: Use Azure AD directory extension attributes in claims - Microsoft Entra | Microsoft Learn

Related

Azure Authentication - Access Token returning wrong AUD(00000003-0000-0000-c000-000000000000)

I'm trying to authenticate with API Management in Azure through OAuth. I've set up that piece fine.
However from the response, the aud(00000003-0000-0000-c000-000000000000) is invalid from the access token.
Any suggestions/ideas to get the accurate aud in access_token.
I tried to reproduce the same in my environment and got the results like below:
I generated the access token with the same aud as you and got the validation error:
I agree with juunas, To authenticate with API Management in Azure through OAuth, make sure to pass the scope while generating the access token.
I created an Azure AD Application, exposed an API and added scope like below:
Added API permissions like below:
To resolve the error, make sure to pass scope as api://AppID/.default.
https://login.microsoftonline.com/TenantID/oauth2/v2.0/token
client_id:ClientID
client_secret:ClientSecret
scope:api://ee1782a6-a994-4013-a396-XXXXX/.default
grant_type:client_credentials
A valid access token to access APIM will be generated like below:
To pass the particular scope from react app using MSAL you can make refer the below sample code:
auth: {
authority: "https://login.microsoftonline.com/common",
clientId: "ClientID",
postLogoutRedirectUri: RedirectURI
redirectUri: RedirectURI
validateAuthority: true,
navigateToLoginRequestUrl: true,
},
cache:
{ cacheLocation: 'sessionStorage',
storeAuthStateInCookie: true,
},
},
{
scopes: ['api://clientid/.default']
},
LoginType.Redirect
References:
OAuth 2.0 Authorisation with the Client Credentials Flow on Azure API Management by Paco de la Cruz
Connect React App with Azure AD using react msal by Ray
You have mistaken the values.
TL;DR: ignore "access token", obtain and read "id token" and verify that "aud" field is your client ID.
First you might obtain a single-use access code (likely something like 0.ABC). Optionally you could fetch open id token. "scope" must include "openid"
Then you can fetch actual open id token using the single-use code. "scope" must be "openid" again. Response might include:
access token - which can be anything including random number of characters, string, your full details or an JWT; I believe that Microsoft returns JWT which is meant to the "00000003-0000-0000-c000-000000000000" audience (meaning "only 00000003-0000-0000-c000-000000000000 can use it - ignore if you are NOT the one")
id token - which is an JWT and should contain your application ID (client ID) in the "aud" field
Always check the "aud" as this says who is the token created for. If it is not you - the token is not for you.

SharePoint Access token has two different scope values for tenants

when I decode SharePoint access token for Tenant A and B it shows as below
for the tenant A
"scp": "AllSites.FullControl User.Read User.ReadBasic.All"
for the tenant B
"scp": ".1f7f4061-caa1-44c4-b29a-6d877e9a5211"
are there any possible reasons to this kind of result for different tenants where i am expecting Teanat A result.
my token request call is similar to this
{ "grant_type", "authorization_code" },
{ "client_id", azureConfig.ClientId },
{ "client_secret", azureConfig.ClientSecret },
{ "scope", "https://123435350365.sharepoint.com/.default"},
{ "redirect_uri","url" },
{ "code", code }
I tried to reproduce the same in my environment and got the scopes successfully in both tenants.
I used the below parameters for both the tenants and got the access token for SharePoint successfully:
After decoding the token, I got the scope for both tenants successfully like below:
Please check the scope you are giving for Tenant B and verify whether your tenant has access to SharePoint API or not.
After decoding the token for Tenant B please check the aud and iss claims are valid or not.
Please note that value for the SharePoint Online Tenant Id may vary for each Tenant.
Make sure if you are giving permissions for Microsoft Graph then change the scope to https://graph.microsoft.com/.default.
If still the issue persists, try to raise Azure Support Ticket.
You can refer the below links to get some pointer to resolve the issue:
azure - SharePoint online OAuth2 token invalid_scope - Stack Overflow
How to access SharePoint Online data using Postman - REST API and Bearer token

How to check if a user is in an AD group via Azure AD?

Setup Specifications
.NET 4.5.1 MVC Project
Project contains .aspx files (legacy)
Currently user Azure AD for authentication via Cookies.
Azure portal configured (via App Registrations) with "Implicit Grant - ID Tokens" and "Accounts in this organizational directory only"
On-Premise AD groups are pushed up to Azure AD.
Startup.cs Configuration
// COOKIES: Tells it to use cookies for authentication.
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions()
{
CookieManager = new SystemWebCookieManager()
});
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions()
{
ClientId = ClientID,
Authority = Authority,
PostLogoutRedirectUri = PostLogoutRedirectUri,
Notifications = new OpenIdConnectAuthenticationNotifications()
{
AuthenticationFailed = PrincipalService.OnAzureAuthenticationFailure,
AuthorizationCodeReceived = (AuthorizationCodeReceivedNotification notification) =>
{
var username = notification.AuthenticationTicket.Identity.Name.Split('#').LastOrDefault();
var emailAddress = notification.AuthenticationTicket.Identity.Claims.FirstOrDefault(x => x.Type.Contains("emailaddress"))?.Value;
Logger.Log(Level.Auth, $"Azure login success! Username: '{username}' Email: '{emailAddress}'.");
return Task.FromResult(0);
}
}
});
Question
How can I, given this setup, check if the currently logged in user is in a particular AD Group?
What I've tried
All the guides on doing Microsoft Graph API always come up with a problem that I don't know how to get past (e.g. GetAccountsAsync returning empty, etc).
I added the following to our app registration manifest:
"optionalClaims": {
"idToken": [
{
"name": "email",
"source": null,
"essential": true,
"additionalProperties": []
},
{
"name": "groups",
"source": null,
"essential": true,
"additionalProperties": []
}
],
"accessToken": [],
"saml2Token": []
}
email works fine, but obviously groups doesn't as it was a shot in the dark.
1. Getting Group Membership Claims as part of Token
You can enable group claims to come in as part of the access token for your application by editing your application's manifest (this can be done directly in Azure Portal) and setting "groupMembershipClaims" property to "All" or "SecurityGroup" as needed.
2. Group Ids are returned as part of Claims
Once application manifest is updated as mentioned above, you can get Group Id's as part of claims. Here's a quick sample for a decoded JWT token
3. Limit on the number of groups that can be returned as part of token
To ensure that the token size doesn't exceed HTTP header size limits, Azure AD limits the number of objectIds that it includes in the groups claim. If a user is member of more groups than the overage limit (150 for SAML tokens, 200 for JWT tokens), then Azure AD does not emit the groups claim in the token. Instead, it includes an overage claim in the token that indicates to the application to query the Graph API to retrieve the user's group membership.
4. Relevant Microsoft Graph APIs
NOTE: Working with Microsoft Graph APIs can be pretty powerful, since you can get around overage scenarios as well as get all other kinds of information about groups if needed (like name). In this particular case, since intent is to validate group membership, group Id is the best field as it will not change while others like name can.
Check member groups
This one will be helpful if you already know the groups that you want to check/validate membership in.
POST https://graph.microsoft.com/v1.0/users/{id | userPrincipalName}/checkMemberGroups
In request body, you can provide groupdIds, i.e. a collection that contains the object IDs of the groups in which to check membership. Up to 20 groups may be specified.
{
"groupIds": [
"fee2c45b-915a-4a64b130f4eb9e75525e",
"4fe90ae065a-478b9400e0a0e1cbd540"
]
}
user: getMemberGroups
This one will be helpful if you don't already know the group and want to get all the groups that this user belongs to.
POST https://graph.microsoft.com/v1.0/users/{id | userPrincipalName}/getMemberGroups
Here is another related SO Post

Can I get an id_token from Azure AD for my app?

Using the client_credentials flow in Azure AD, I am unable to retrieve an id_token for my app.
I am experimenting with the Azure AD OAuth/OpenID endpoints, and running into some questions.
I create a simple app with minimal config through the Graph API (a beta endpoint, but still). I have removed all the headers and anonymised in code snippets below:
curl -X POST \
https://graph.microsoft.com/beta/applications \
-d '{
"displayName": "App Name",
"passwordCredentials": [
{
"endDateTime": "2299-12-30T23:00:00Z",
"startDateTime": "2019-02-14T20:19:14.686691Z",
"secretText": "<SOME KEY>",
"displayName": "Client Secret"
}
]
}'
In the response from Azure AD, I get an appId:
{
"#odata.context": "https://graph.microsoft.com/beta/$metadata#applications/$entity",
"id": "<SOME GUID>",
"deletedDateTime": null,
"isFallbackPublicClient": null,
"appId": "<SOME GUID>",
...
This is enough for me to be able to retrieve an access_token from the v1 OAuth endpoint:
curl -X POST \
https://login.microsoftonline.com/tenant_id/oauth2/token \
-d 'client_id=appId&client_secret=secretText&grant_type=client_credentials'
Response:
{
"token_type": "Bearer",
"expires_in": "3600",
"ext_expires_in": "3600",
"expires_on": "1550220412",
"not_before": "1550216512",
"resource": "00000002-0000-0000-c000-000000000000",
"access_token": "<JWT access token>"
}
Since I didn't specify a resource in my call, I get the default Graph API resource.
Now, what I also would like to get is an id_token for my app. I have been able to get these tokens from other OpenID providers. However, the OpenID Connect Core spec. gives me reason to think that id_tokens are for end users only, not apps:
"The ID Token is a security token that contains Claims about the Authentication of an End-User by an Authorization Server when using a Client, and potentially other requested Claims"
(From https://openid.net/specs/openid-connect-core-1_0.html#IDToken)
Adding resource=openid to the POST to the token endpoint above won't work, since openid is a scope, not a resource.
Switching to the v2 endpoints, I get access to a scope parameter. I can obtain an access token from there by setting scope=https://graph.microsoft.com/.default, explicitly requesting the access I got by default through the v1 endpoint.
However, setting the scope to for instance scope=https://graph.microsoft.com/.default openid does not give me an id_token for my app, and the access token looks identical to the previous call.
Trying just scope=openid gives me the following error from Azure AD:
AADSTS70011: The provided request must include a 'scope' input parameter. The provided value for the input parameter 'scope' is not valid. The scope openid is not valid.
All this combined leads me to believe that the OpenID providers I have used and have issued id_tokens through the client_credentials flow are breaking the spec, and that id_tokens can only be obtained for end users (using the authorization_code flow gives me an id_token from Azure AD for myself without any issues).
Is this a correct conclusion, or can I force Azure AD to issue id_tokens to apps as well as end users?
An id_token is issued when a user signs-in. Client credentail flows have no user, so no id_token is issued.
you'd need to use a flow like authorization code grant or openID connect to sign a user in. The response will have a id_token.
You cannot use the client credentials flow to get the id_token for app-only, it only returns the access_token.

"One or more scopes are not compatible with each other" error when retrieving access token for the

I have an app that integrated with Outlook, Calendar via the Azure AD REST API v.2. I have tried to use the incremental and dynamic scopes to "upgrade" the user's token so that the app can access OneDrive as well, (so the user could directly upload her email attachments in her cloud).
The authorization code retrieval redirects went well and the user is asked for the additional scope after login (files.readwrite). However, on step 2 when I try to obtain the access token I get the following error:
System.Exception: Acquire token by authorization code returned BadRequest:
{
"error": "invalid_scope",
"error_description": "AADSTS70011: The provided value for the input parameter 'scope' is not valid. One or more scopes in 'https://outlook.office.com/mail.readwrite https://outlook.office.com/mail.send https://outlook.office.com/contacts.readwrite https://outlook.office.com/calendars.readwrite https://outlook.office.com/people.read files.readwrite' are not compatible with each other.\\r\\nTrace ID: b02fa0bf-6e86-4156-81e8-294dbc851500\\r\\nCorrelation ID: 3697bd18-554c-47e6-81cc-de3c47780fc9\\r\\nTimestamp: 2018-02-01 15:26:10Z",
"error_codes": [
70011
],
"timestamp": "2018-02-01 15:26:10Z",
"trace_id": "b02fa0bf-6e86-4156-81e8-294dbc851500",
"correlation_id": "3697bd18-554c-47e6-81cc-de3c47780fc9"
}
Or this error:
System.Exception: Acquire token by authorization code returned BadRequest:
{
"error": "invalid_request",
"error_description": "AADSTS700022: The provided value for the input parameter scope is not valid because it contains more than one resource. The scope https://outlook.office.com/mail.readwrite https://outlook.office.com/mail.send https://outlook.office.com/contacts.readwrite https://outlook.office.com/calendars.readwrite https://outlook.office.com/people.read files.readwrite is not valid.\\r\\nTrace ID: 9781d206-11b3-46c8-b972-8c4e77641c00\\r\\nCorrelation ID: 7e63af89-6e95-45f4-abaa-8f32051fb9ef\\r\\nTimestamp: 2018-02-01 15:36:32Z",
"error_codes": [
700022
],
"timestamp": "2018-02-01 15:36:32Z",
"trace_id": "9781d206-11b3-46c8-b972-8c4e77641c00",
"correlation_id": "7e63af89-6e95-45f4-abaa-8f32051fb9ef"
}
I assume I can't use the same token for both Outlook and OneDrive access because they are "different resources", one being part of the Office 365 and the other in Microsoft graph, however, I struggle to find a comprehensive list of which resources are compatible with which in here (https://learn.microsoft.com/en-us/azure/active-directory/develop/active-directory-v2-scopes).
My question is, does this mean that I will need to maintain 2 different tokens (my app uses the offline scope to refresh the token) for OneDrive and Outlook?
Also is there a difference between OneDrive for a personal account and OneDrive for a business accounts (which I think is the same as Sharepoint)? When working with outlook I can use the same code for outlook.com and Office365 emails, but I am not sure this is the case when it comes to working with files.
With the Google APIs it's quite simple to just add the Google Drive (or any other API) scope to your Gmail access scopes, but I guess that's not the case with the Microsoft APIs.
Thanks
Yes you will need two tokens. As juunas said in his comment, the problem is the audience, or the aud parameter in the token. You're asking for scopes that apply to two different audiences: https://outlook.office.com and https://graph.microsoft.com.
The good news is that these two APIs do have overlapping scopes, and Azure AD will allow you to use a refresh token issued for Graph to get a token for the Outlook API. So here's what I suggest (assuming you're doing authorization code flow)
Do your authorization request using Graph scopes:
mail.readwrite
mail.send
contacts.readwrite
calendars.readwrite
people.read
files.readwrite
Do a token request with grant_type=authorization_code using those same Graph scopes. This gets your Graph token + refresh token.
Do a token request with grant_type=refresh_token using the refresh token from previous step, but this time with ONLY the Outlook-applicable scopes, qualified for https://outlook.office.com. This gets your Outlook token.
https://outlook.office.com/mail.readwrite
https://outlook.office.com/mail.send
https://outlook.office.com/contacts.readwrite
https://outlook.office.com/calendars.readwrite
https://outlook.office.com/people.read

Resources