I have a Web API "App Registration" called "BackEnd_API" which defines some Application Roles and User Roles.
{
"allowedMemberTypes": [
"Application"
],
"description": "resource.READ allows you read access to all items in the application",
"displayName": "resource.READ",
"id": "9650cfb9-570d-4b79-1337-a01337ed6c29",
"isEnabled": true,
"lang": null,
"origin": "Application",
"value": "resource.READ"
},
I then have another Client Application "App Registration" called "Client_App" which consumes that API to which i've assigned the AppRoles "resource.READ" using either Azure_CLI or PowerShell.
In the Azure Portal I can see that the Service Principal is assigned the role.
When i use the Client_Credentials Flow the resulting access token DOES contain that Roles claim which i use on the BackEnd to authorize the caller.
Until Here ALL Good.
Now, I want to consume the same Web API "BackEnd_API" from another Consuming Application using Managed Identities. So I've created another "App Service", enabled System Assigned Identity and assigned the AppRoles "resource.READ" using Azure CLI.
In the Azure Portal I can see that the Service Principal is assigned the role.
I can get a Token using the JS Azure SDK.
var withClientSecretCredential = () => {
require("#azure/core-auth");
require('dotenv').config()
const {
ManagedIdentityCredential
} = require("#azure/identity");
const logger = require('#azure/logger');
logger.setLogLevel('info');
// Load the .env file if it exists
const credentials = new ChainedTokenCredential(
new ManagedIdentityCredential("54e5c672-872f-4866-b067-132973cb0c91"),
);
token = credentials.getToken(['api://e22fd9eb-3088-4155-936a-0919681c3eb5/.default']);
return token
But the received token in this case has no 'role' claims, so the API call fails to authorize.
I double checked roles and assignment all looks good; is this supposed to work ?
Token without 'role' claim.
{
"aud": "e22fd9eb-3088-4155-936a-0919681c3eb5",
"iss": "https://login.microsoftonline.com/45591230-6e37-4be7-acfb-4c9e23b261ea/v2.0",
"iat": 1634550153,
"nbf": 1634550153,
"exp": 1634636853,
"aio": "E2ZgYGguYd9fNkv3pOV5Iduv2655AgA=",
"azp": "7dd894ca-6c1b-45ae-b67c-75db99593a14",
"azpacr": "2",
"oid": "54e5c672-872f-4866-b067-132973cb0c91",
"rh": "0.ARAAYH9ZRTdu50us-0yeI7Jh6sqU2H0bbK5Ftnx125lZOhQQAAA.",
"sub": "54e5c672-872f-4866-b067-132973cb0c91",
"tid": "45597f60-6e37-4be7-acfb-4c9e23b261ea",
"uti": "qOLzTFlmw0yuWeFXXT1pAA",
"ver": "2.0"
}
Thanks for helping.
The token you might be getting should be an access token and the roles you are looking for should be in the id token. Did you tried this by enabling "ID Token" in azure portal?
Related
I am creating an outlook add-in and am trying to use the SSO access token as authorisation for my backend.
I have the flow working. I trigger my Add-In, get the access token and use the access token to "login" to my backend.
However, the issue I have is that I am not getting the email claim in the token despite a) adding it to the API permissions in the Azure App Registration, b) adding to the WebApplicationInfo. Should I be receiving it?
Azure App Registration Permissions
Web Application Info
<WebApplicationInfo>
<Id>xxx</Id>
<Resource>api://localhost:3000/xxx</Resource>
<Scopes>
<Scope>openid</Scope>
<Scope>User.Read</Scope>
<Scope>profile</Scope>
<Scope>email</Scope>
</Scopes>
</WebApplicationInfo>
Code to receive token
OfficeRuntime.auth.getAccessToken( { allowSignInPrompt: true })
Token received
{
"aud": "api://localhost:3000/xxx",
"iss": "https://sts.windows.net/my_tenant_id/",
"iat": 1605992211,
"nbf": 1605992211,
"exp": 1605999711,
"acr": "1",
"aio": "E2RgYDDdzii4P/xP/cPTbg4lPk7dJ6c8aQnapLU19aiV+Zy400sA",
"amr": [
"pwd"
],
"appid": "xxx",
"appidacr": "0",
"family_name": "Adams",
"given_name": "Iain",
"ipaddr": "51.111.111.111",
"name": "Iain Adams",
"oid": "my_oid",
"pwd_exp": "157262",
"pwd_url": "https://portal.microsoftonline.com/ChangePassword.aspx",
"rh": "0.AAAAmj9NLsNP80SAITLYeWEJg9YOWdOzUgJBrv-q0ikqsBxHANs.",
"scp": "access_as_user",
"sub": "my_sub",
"tid": "my_tenant",
"unique_name": "iain#abc.com",
"upn": "iain#abc.com",
"uti": "1KNbNttkDUCrKXblaK5BAA",
"ver": "1.0"
}
Whilst I know the email address is being returned in the upn and unique_name claims, AND, I know that oid should be used as the unique identifier for this user, however, I need to lookup based on email address (if it exists).
You need to customize the access token configuration and then add the email as an optional claim. Go to azure portal>App registrations>your app>Token configuration.
Parse the token:
You need to pay attention to: For managed users (the users inside the tenant), it must be requested through this optional claim or, on v2.0 only, with the OpenID scope.
See: Document.
The "Email" value is part of optional claims. It's included by default if the user is a guest in the tenant. For managed users (it means, the users inside the tenant), it must be requested through this optional claim or, on v2.0 only, with the OpenID scope. For managed users, the email address must be set in the Office admin portal (https://portal.office.com/adminportal/home#/users).
I have an issue with the Microsoft Graph API.
I have registered a new app in the Azure portal
Added Application.ReadWrite.All and Application.ReadWrite.OwnedBy application permissions
Click on the admin consent button
empty
After that, I'm trying to get an access token by
POST https://login.microsoftonline.com/12fb9222-8b6e-4006-a483-a87fa44621c3/oauth2/v2.0/token
client_id=dc07d452-9ce1-4b0f-a1a6-4fb5b230a4bb
scope=https://graph.microsoft.com/.default
grant_type=client_credentials
client_secret={client_secret}
And I'm getting the token.
Token looks like that:
{
"aud": "https://graph.microsoft.com",
"iss": "https://sts.windows.net/12fb9222-8b6e-4006-a483-a87fa44621c3/",
"iat": 1570007742,
"nbf": 1570007742,
"exp": 1570011642,
"aio": "42VgYHi/n737QYBx8DrOTW5Ft0skAQ==",
"app_displayname": "testapp",
"appid": "dc07d452-9ce1-4b0f-a1a6-4fb5b230a4bb",
"appidacr": "1",
"idp": "https://sts.windows.net/12fb9222-8b6e-4006-a483-a87fa44621c3/",
"oid": "24d9cd08-efaf-497b-b023-920cc208400a",
"roles": [
"Application.ReadWrite.OwnedBy",
"Application.ReadWrite.All",
],
"sub": "24d9cd08-efaf-497b-b023-920cc208400a",
"tid": "12fb9222-8b6e-4006-a483-a87fa44621c3",
"uti": "f38JDx5iw0Kkp16mnZIqAA",
"ver": "1.0",
"xms_tcdt": 1569224302
}
After that, I'm executing
GET https://graph.microsoft.com/beta/applications/bb4c22ea-632e-45d8-ad0f-2ba39cf399c1
And I'm getting app properties.
And finally I want to update my app properties and I'm trying execute
PATCH https://graph.microsoft.com/beta/applications/bb4c22ea-632e-45d8-ad0f-2ba39cf399c1
{
"displayName": "displayName"
}
And I'm getting:
{
"error": {
"code": "Authorization_RequestDenied",
"message": "Insufficient privileges to complete the operation.",
"innerError": {
"request-id": "1565bb72-8392-4ca7-bb20-02b40f5603bd",
"date": "2019-10-02T09:23:57"
}
}
}
I'm confused. I have permissions for the API update application, but I got the error, please help.
This seems like a bug, I tried with client credentials and granted Application.ReadWrite.All and Application.ReadWrite.OwnedBy permissions. I encountered the same error as yours.
Then I tried with Delegated permission with a user login, it worked. You can follow this article or just call the api with Microsoft Graph explorer.
Note:
APIs under the /beta version in Microsoft Graph are subject to change.
Use of these APIs in production applications is not supported.
So I have began practicing and using Identity Server 4, my goal is to have an authentication and authorization server for all the applications within my organization. I got to the point where I can log in correctly to my identity server from a third application and get my access_token and it works nicely.
The second step is to get my userinfo inside my access_token but when I decode it I get this:
{
"nbf": 1505250392,
"exp": 1505253992,
"iss": "http://localhost:5000",
"aud": [
"http://localhost:5000/resources",
"SecretAPIEndpoints"
],
"client_id": "SecretClient",
"sub": "ebf3fcad-6ab3-4bcd-88ce-0c5794ebdffa",
"auth_time": 1505250391,
"idp": "local",
"scope": [
"openid",
"SecretAPIEndpoints"
],
"amr": [
"pwd"
]
}
So if I use this token I can make my endpoints work correctly but I want to get it one step further and get my SPA to show my user first name and last name and also their email and roles.
I haven't found documentation or examples to make this happen, so any bit of help would be greatly appreciated.
If you want to consume identity data in JS-based client app, ask for an id_token in addition to an access token.
https://openid.net/specs/openid-connect-core-1_0.html#ImplicitFlowAuth
Is it possible to access the Microsoft Graph API using an access token obtained through the Azure Active Directory 1.0 Endpoint with the Client Credentials OAuth 2 flow?
For example:
POST https://login.microsoftonline.com/{mytenant}.onmicrosoft.com/oauth2/token
grant_type=client_credentials,
client_id={app id registered in azure portal},
client_secret={registered app key},
resource=https://graph.microsoft.com
When I use the token returned from this request, I get the following error trying to call https://graph.microsoft.com/v1.0/groups.
Decoded JWT
Header
{
"typ": "JWT",
"alg": "RS256",
"x5t": "HHByKU-0DqAqMZh6ZFPd2VWaOtg",
"kid": "HHByKU-0DqAqMZh6ZFPd2VWaOtg"
}
Payload
{
"aud": "00000002-0000-0000-c000-000000000000",
"iss": "https://sts.windows.net/{tenant id}/",
"iat": 1504804880,
"nbf": 1504804880,
"exp": 1504808780,
"aio": "Y2FgYDiiO8/s3smXRdxLg87zBPRNAwA=",
"appid": "{client id}",
"appidacr": "1",
"idp": "https://sts.windows.net/{tenant id}/",
"oid": "{enterprise app object id}",
"sub": "{enterprise app object id}",
"tenant_region_scope": "NA",
"tid": "{tenant id}",
"uti": "uIzrJNpHcEGXoQ4ZKZgqAA",
"ver": "1.0"
}
{
"error": {
"code": "InvalidAuthenticationToken",
"message": "Access token validation failure.",
"innerError": {
"request-id": "3537d28e-a061-4430-aef5-4a75bf791d90",
"date": "2017-09-07T16:38:26"
}
}
}
I've ensured the application has the correct permissions assigned through the portal. Under Required Permissions > Application Permissions, "Read and write all groups" is selected.
Azure Portal Permissions
Is there anything I'm missing or is this not possible?
In your JWT token, the Audience Value (aud) is wrong.
If you are trying to call https://graph.microsoft.com or any of it's APIs, you need a token with the aud claim of https://graph.microsoft.com or 00000003-0000-0000-c000-000000000000.
The token you have is for the AAD Graph API, https://graph.windows.net a.k.a. 00000002-0000-0000-c000-000000000000
While these two resources look similar in both URL and GUID form, they are completely separate identities. You should confirm throughout your code that you are specifying the correct resource value when retrieving your access token. Your small sample above implies that you are doing it correct, but the token shows that you are not.
What we are planning to achieve is a role-based security for a Front end Angular-2 and back-end ASP.NET Web API application. We are doing the authentication process with the help of ADAL.js and storing the token in the local storage. We have also implemented the approach shown here i.e. to call the Graphi API and get the user groups to stuff them into Claims.
My question is : Is there anyway, we can add role claims from server to the bearerToken which is residing in the local storage. Or is there any better way to approach this issue.
The code sample mentioned assign the role based on the group. If you have the Azure AD basic version, it support to assign the role to the users/groups directly.
My question is : Is there anyway, we can add role claims from server to the bearerToken which is residing in the local storage. Or is there any better way to approach this issue.
Yes, it is possible. To issue the role claims we need to assign the users to assign the roles to users or group first. Then when the user acquire the token, the Azure AD would issue the relative role claims in the token.
You can refer the code sample for using the role claim from here.
And you may also be interest in groups claim developing.
ok i was struggling with this for a while and i have figured it out i believe.
First,
In Azure AD, set up your WebApi app as application type to be Web App / API.
go to Manifest file and add your roles like
[
{
"allowedMemberTypes": [
"User"
],
"displayName": "Reviewer",
"id": "0238c2bb-9857-4d07-b760-a47ec621d57a",
"isEnabled": true,
"description": "Reviewer only have the ability to view tasks and their statuses.",
"value": "reviewer"
},
{
"allowedMemberTypes": [
"User"
],
"displayName": "Approver",
"id": "000018cb-19e3-4f89-bf99-5d7acf30773b",
"isEnabled": true,
"description": "Approvers have the ability to change the status of tasks.",
"value": "approver"
}
]
Then create the the Client app as Application type to be Native app and add required permissions to the service you added above.
In the SPA Angular app add something like this
var endPoints = {
// "https://localhost:44386/" is the API URL
// "xxxxxxxxxxxxxxxxxxxxxxxxxxxxx" is the Service Application ID
"https://localhost:44386/": "xxxxxxxxxxxxxxxxxxxxxxxxxx"
};
adalAuthenticationServiceProvider.init({
instance: "https://login.microsoftonline.com/",
// tenant is your tenant name (something like below)
tenant: "{NAME}.onmicrosoft.com",
// this is the Native app application ID (ClientID) you registered
clientId: "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyy",
extraQueryParameter: "nux=1",
endpoints: endPoints
}, $httpProvider);
}
]);
Then, in your startup.cs you need to set up the Service App like the following:
app.UseWindowsAzureActiveDirectoryBearerAuthentication(
new WindowsAzureActiveDirectoryBearerAuthenticationOptions
{
TokenValidationParameters = new TokenValidationParameters
{
/* "xxxxxxxxxxxxxxxxxxxxxxxxxxxxx" is the Service Application ID. (Same as you registered in the client app above)*/
ValidAudience = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
RoleClaimType = "roles"
},
/*enant is your tenant name (same as you registered in client app above)*/
Tenant = "{NAME}.onmicrosoft.com"
});
Finally you need to go to Azure active directory => Enterprise application => all applications => select your webAPI service => Users and groups => then assign users to the roles.
When this is all done when you log through your client app to authenticate and call the webapi, adal.js and ada-angular.js will put the proper bearer token that contains roles
Good to learn this approach.
Ted, thanks for sharing your solution !
For those who are not familiar with operating Azure AD manifest file. The following is a good resource.
https://thinkthencode.wordpress.com/2016/04/24/azure-ad-using-app-roles-for-authorization/
"appRoles": [
{
"allowedMemberTypes": [
"User"
],
"displayName": "Reviewer",
"id": "0238c2bb-9857-4d07-b760-a47ec621d57a",
"isEnabled": true,
"description": "Reviewer only have the ability to view tasks and their statuses.",
"value": "reviewer"
},
{
"allowedMemberTypes": [
"User"
],
"displayName": "Approver",
"id": "000018cb-19e3-4f89-bf99-5d7acf30773b",
"isEnabled": true,
"description": "Approvers have the ability to change the status of tasks.",
"value": "approver"
}
]