Azure Active Directory RBAC Not Returning Roles in Bearer Token - azure

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.

Related

Azure AD B2C Authorization support based on Scope/Role

We want to achieve an authorization at our APIs.
Ex. We have API-A and API-B and both are exposed to our different consumers.
We have setup of scope based authorization in place with IdentityServer4 where we decorate endpoints with different policies. With IdentityServer4 we are able to achieve this as IdentityServer4 token has scopes claims present in all the grant types but with Azure AD, we found we can't have scope claim in token generated with Client Credential flow.
In our case, Web API B is also exposed to consumers and again they have scope based authorization. To call, Web API B from Web API A we use client credential flow and it will not have scopes claim in token so we are not able to authorize our call to Web API B.
How to achieve scope based authorization with Azure AD in microservices architecture where we call other context APIs from one context.
When you are using client credential flow and using
application permission , you get roles and not scope i.e; scp claim in the token.
Application permissions are sort of roles given to the application
itself and the scope in client credentials should be used as
api://<APP_ID>/.default . They only apply when doing client
credentials authentication, where no user is involved.
See quickstart to configure app access web-apis
Scopes are usually delegated permissions that only apply when a
user is involved in the login process. They allow you to act on
behalf of a user i.e; In the user context only, we will get
scp claims in case of client credential flow.
See azure-ad-scope-based-authorization
So , If you want delegated permissions then you will have to use implicit grant flow instead of client credentials.
As scopes in expose an api page are for Authorization Code Grant flows and where the user is involved, in this case (client credential) its not possible, we have to add our own scopes that is availible for applications to use which are indirectly called roles that we need to add in the manifest itself under approles in the app registration or through the app roles blade.
ex:
{
"appRoles": [
{
"allowedMemberTypes": [
"Application"
],
"displayName": "Read all todo items",
"id": "f8dxxxxxxxxxxxxf98",
"isEnabled": true,
"description": "Allow the application to read all todo items as itself.",
"value": "Todo.Read.All"
}
]
}
After that , those has to be granted admin consent.
So now when requesting a token with a default scope of api://<app id>/.default the "scopes" are returned in the roles claim.
So we can use role claim for authorization purpose.
Also as a work around
Try to make sure to add additional scope like profile, offline_access open_id.
And give response_type=token instead of id_token
Example request:
......&redirect_uri=https://jwt.io&scope=openid profile offline_access&response_type=token&prompt=login
References:
Scope-based authorization in your API with Azure AD – the IT generalist (wordpress.com)
Scope is not being added to Access Token returned from Azure Ad - Stack Overflow
EDIT:
To call a web api from other , there need to be scopes defined in
one api i.e (api2 that you want to call) and those scopes need to be
selected in calling api(api1) . Please go through the process
here
When login in first Api include scope in the request and also try
response type as Token and see if scp available or then with idtoken
https://tenant.b2clogin.com/tenant.onmicrosoft.com/oauth2/v2.0/authorize?p=B2C_1_TenantSignUpIn&client_id=<appid>&nonce=defaultNonce&redirect_uri=https://jwt.ms&scope=openid offline profile https://tenant.onmicrosoft.com/b2capi/write https://tenant.onmicrosoft.com/b2capi/read https://tenant.onmicrosoft.com/b2capi/user_impersonation&response_type=id_token&prompt=login.
Please note that scopes are present as roles depending on the flow
type.

How to add roles claim in access_token , currently it is coming in id_token?

I am following Authentication code flow with PKCE and my Identity provider is Azure Active directory.
I have created a App , "client-app" from App Registrations. In the manifest I have added appRoles like the following.
"appRoles": [
{
"allowedMemberTypes": [
"User"
],
"displayName": "StoreGroupManager",
"id": "47fbb575-859a-4941-89c9-0f7a6c30beac",
"isEnabled": true,
"description": "Consumer apps have access to the consumer data.",
"value": "StoreGroupManager"
}
]
I am assigning this role StoreGroupManager to Users. Now when I follow Authorization code flow with PKCE and obtain the id_token , refresh token and access_token. I can see that the id_token has a claim roles but not the access_token.
I need to have roles claim claim in the access_token. Can this be possible?
The following is the decoded id_token.
Roles will be in the access token if the app registration for the API that the access token is for defines those roles and they are assigned to the user.
So if you use the same app registration for the client and API, they should be there.
But if you have separate app registrations for the client and API, you will need to define the role in both apps and assign the user to it on both of them as well.

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 AD remove permissions for registered app

I am using Azure AD to secure my service to service calls. (Each service having an application identity in Azure AD).
Example: Application A wants to access Application B.
I noticed that when requesting an accesstoken from Application A using Client Credential Flow (with Certificate), an accesstoken is issued without having me to explicitly set the permissions to access Application B.
This seems odd to me because the token returned has its audience set to Application B even thought I haven't explicitly given it access.
If I understand correctly, all registered app have access to each other by default?
Is there a way in Azure AD to explicitly require permissions to be set in order for application to access each other?
Below is a screenshot of Application A required permissions. As you can see, Application B is not listed here.
In the following screenshot, I assigned TodoListService (aka Application B) to the required permissions of Application A
I noticed that when requesting an accesstoken from Application A using Client Credential Flow (with Certificate), an accesstoken is issued without having me to explicitly set the permissions to access Application B.
Yeah, that one can be a bit surprising and I'm not sure why that is the case either.
What you need to do is define application permissions on the API, and then assign it on the client.
Then you need to check the caller has the required app permission in the token.
I have an article on this topic: Defining permission scopes and roles offered by an app in Azure AD.
To define an app permission on the API, you'll have to edit its manifest in Azure AD, and add an app role with member type of Application, something like:
{
"appRoles": [
{
"allowedMemberTypes": [
"Application"
],
"displayName": "Read all todo items",
"id": "f8d39977-e31e-460b-b92c-9bef51d14f98",
"isEnabled": true,
"description": "Allow the application to read all todo items as itself.",
"value": "Todo.Read.All"
}
]
}
IIRC you have to generate a GUID for the id.
After defining this permission on the API, go to your client app, and add the app permission in the Required permissions.
Then you should press Grant permissions to grant the app permission.
Now then when the client acquires a token with client credentials, the token will contain:
{
"roles": [
"Todo.Read.All"
]
}
So you'll have to check that that is present.

Delegating Azure Active Directory Roles When Calling API from SPA

I have a single page application (SPA) and an API. Both are secured using Azure Active Directory using role based access control (RBAC). I can login and viewview my SPA using ADAL. I can also login, call my API and see the role claims I have given myeself.
I want to call the API from the SPA. I have added the API delegated permissions to the SPA. I have also hit the 'Grant Permissions' button so I don't see a consent screen.
The problem is when the SPA calls the API, no role claims appear, so the API always returns a 403 Forbidden response. How can I solve this?
Update
This is the manifest for my API:
{
"appId": "[API Client ID]",
"appRoles": [
{
"allowedMemberTypes": [
"User"
],
"displayName": "Read Device",
"id": "b2e6f6c2-c3d5-4721-ad49-0eea255ccf45",
"isEnabled": true,
"description": "Can read a device.",
"value": "Device.Read.All"
}
],
...
}
In my SPA, I'm using ADAL and adal-angular like so:
var azureActiveDirectory = {
'instance': 'https://login.microsoftonline.com/',
'tenant': '[My Tenant ID]',
'clientId': '[SPA Client ID]',
'redirectUri': 'http://localhost:8080/',
'endpoints': {
'http://localhost:5000': '[API Client ID]'
}
adalAuthenticationServiceProvider.init(azureActiveDirectory, $httpProvider);
Apparently, roles in nested groups are not transitive i.e. If I am a member of Group 2, I do not have the Role granted to Group 1, even though Group 2 is a member of Group 2:
Group 1
Has a Role from Application 1
Has a Member called Group 2
This is absolutely unbelievable that such a feature has not been implemented. I've raised a suggestion on UserVoice. Please upvote the suggestion.
you should create the appRole in your API app, when your spa call API, it will get access token with the role in api app that the login user belongs to. so to make sure you create role and verify role in api app, not spa app.

Resources