0

I have registered both an angular app and an Asp.Net core web API to Azure Active Directory. I've add an app role to the registration of the Angular. I also assigned the role to one user.

When I log the user in, the I don't see the roles property in the Access Token. All I see this "scp": "Directory.Read.All openid profile User.Read email",.

The role property appears in the id token. like this:

"roles": [
    "can_read_own_application"
],

Why is this role appearing in the id_token instead of the access_token, given that the access_token is the one the API is expecting.

By the way, there are countless documentation on the subject. I just watched this video made by MS employees. I can't find where it says whether the app roles should be added to the client app or the API app. Maybe my that's why the roles is not appearing in the access token. However, the app roles added to the API registration are not even coming in the token.

Thanks for helping.

EDIT

  1. I added a scopes in the API enter image description here

  2. I updated the API manifest with the Client "ID"

"knownClientApplications": ["351d2a1d-fb5f-4527-b614-edb6d7277043" ]

  1. I updated the permission to the API for the client

enter image description here

  1. I updated my angular code

enter image description here

Now when I log in, the above scope is nowhere to be found. The access token has this value:

{
   "app_displayname": "MyApplication-Client-Local",
    //..
    "scp": "openid profile User.Read email",
}

I don't even remember to have asked for the openid and email. The scope I mentioned are User.Read and access_as_user.

Richard77
  • 20,343
  • 46
  • 150
  • 252
  • 1
    You set graph api `user.read` and your custom api `api"//xxx/access_as_user` together, it's not allowed. You can only set one kind of api permission once. You may try to put `api://xxxx/access_as_user` before `user.read`, then you'll find the scp contained you custom api permission but no graph api permission. – Tiny Wang Dec 15 '21 at 05:43
  • @TinyWang, I knew that I didn't really understood this entire concept. Thanks for your patience. I still have more to learn, but at least I can build on something concrete now. +1 for your help – Richard77 Dec 16 '21 at 04:59
  • Fine. Thanks for your reply and vote : ) – Tiny Wang Dec 16 '21 at 05:20

2 Answers2

1

I think I can answer part of your questions here.

For access token, it's generated with the help of azure ad applications. You can register an azure ad in azure portal -> azure ad, and you can also set api permissions to this app.

Let's assume an scenario here, you need to call an api that can return users' information in your tenant, then you need to call the get user graph api provided by microsoft (this api is similar to your own api). And calling this api requires an access token in the http request headers and the token should contain the permission to read user information. And just like the api document described, when calling the api, the application used to generate access token should have User.Read permission type : delegate or User.Read.All permission type : application first for example. Then after adding the api permission, the access token comes from this application will contain scp:User.Read or roles:User.Read.All.

The differences between application & delegate type, can simply know as the way generated access token. There're 2 typical flows to generate access token, auth code flow and client credential flow. One required users to sign in(delegate, means represent user, will return scp claim) while another one only used azure ad application's client-id and client-secret(application, means represent the application, always using in daemon app or api app, will return roles claim).

Now you access token contains correct permissions, and the user api will decode the token can find it has scp:User.Read or roles:User.Read.All, then the api returns response to the http request. It's the same to your own api. Your api should decode access token first to check if the incoming request has correct permission to access the api itself, for example it requires User.Richard.Read permission, but you can't find this kind of api permission in azure ad as this api permission is defined by yourself, so you need to register another azure ad application to play the role of api, and in this application, you should expose an api with the custom api permission. Then go back to the application which generate the access token, then assign api permission to it. Then you can generate access token via this application with the scope User.Richard.Read.

Tiny Wang
  • 10,423
  • 1
  • 11
  • 29
  • I read all the links you provided in your response. I went through this tutorial as well https://github.com/Azure-Samples/ms-identity-javascript-angular-tutorial/blob/main/5-AccessControl/2-call-api-groups/README.md. Either I'm doing something wrong or I don't understand yet the whole concept – Richard77 Dec 15 '21 at 04:04
  • maybe you can update your requirement in your question so that someone can help you design how to realize the feature.... – Tiny Wang Dec 15 '21 at 04:31
  • please take a look I just update the question. Hopefully you can see all I did. – Richard77 Dec 15 '21 at 04:39
0

After following this tutorial step by step. I realize that requesting/obtaining a tokens from Azure AD is not a one time operation.

  1. I registered 2 applications: the client app (angular) and the API (asp.net core web api).

  2. When the user logs in, the token he/she gets is coming from the Client Registration. Which makes sense because the information provided during the login process are those of the client app.

No wonder now that the access token doesn't contain the permission I register with the API. Btw, the value of the property audience in the token is that of the Graph itself 00000003-0000-0000-c000-000000000000. Therefore, this token is meant to query the user identity and so forth.

  1. It's only when I make a call to the API that Angular makes another POST request to Azure AD for a token usable by the API, using among others the refresh token and the url to the scope I'm mentioned here

    export const protectedResources = { todoListApi: { endpoint: "https://localhost:44351/api/todolist", scopes: ["api://8755d178-93a7-4a30-95ea-b59177e85d7f/access_as_user"], }, }

    protectedResourceMap.set(protectedResources.todoListApi.endpoint, protectedResources.todoListApi.scopes);

When this token arrives, it contains the value "aud": "the_api_guid" and the "scp": "access_as_user".

Richard77
  • 20,343
  • 46
  • 150
  • 252