How do you read Roles/Permissions using MSAL-ANGULAR
Asked Answered
I

6

8

So I've successfully integrated Azure AD authentication in my angular site as per the instructions in msal-angular and now I'm at the point where I'm looking to define and leverage roles and permissions to provide more granular control of what a user can and can't do.

From what I've been able to determine I can define roles by following this set of instructions (https://learn.microsoft.com/en-us/azure/architecture/multitenant-identity/app-roles) but msal-angular doesn't seem to expose this upon logging in - or at least I haven't found instructions on how to do this just yet.

Perhaps I'm missing something. Any suggestions would be appreciated

Izettaizhevsk answered 8/5, 2019 at 12:44 Comment(0)
H
4

To get the groups a user belongs to, you will need to add directory.read.all to your scope in your Angular app and also in the API permissions in the Azure app settings.

let graphUser = await graphClient.api('/me').get();
let graphUserGroups = await graphClient.api(`/users/${graphUser.id}/memberOf`).get();

let user = new User();
user.id = graphUser.id;
user.displayName = graphUser.displayName;
// Prefer the mail property, but fall back to userPrincipalName
user.email = graphUser.mail || graphUser.userPrincipalName;

graphUserGroups.value.forEach(group => {
    user.groups.push({
        group_id: group.id,
        group_name: group.displayName
    });
});
Hagiology answered 8/5, 2019 at 21:7 Comment(3)
Thanks - that's the path that I went along. Do you have any tips on how to get around the 'requires admin consent' prompt related to directory.read.all permission? I've been banging my head against this and have yet to find a solution to getting admin consent workingIzettaizhevsk
In my case, I had to ask my admin on our account to grant that permission.Hagiology
Ah yes - that was my findings as well. ThanksIzettaizhevsk
S
5

You can read user roles defined in Azure App Registrations and assigned in Enterprise Application using MsalService:

let allAccounts = this.msalService.instance.getAllAccounts();
if (allAccounts.length > 0) {
  let account = allAccounts[0];
  let roles = account.idTokenClaims.roles;
}

MSAL Angular version:

"@azure/msal-angular": "^2.0.5",
"@azure/msal-browser": "^2.19.0",
Solemn answered 1/12, 2021 at 17:24 Comment(1)
Did you do something particular to have the roles at that point? I see a lot of group memberships but not the roles defined in App Registration and assigned in Enterprise Application... thanks!Apron
H
4

To get the groups a user belongs to, you will need to add directory.read.all to your scope in your Angular app and also in the API permissions in the Azure app settings.

let graphUser = await graphClient.api('/me').get();
let graphUserGroups = await graphClient.api(`/users/${graphUser.id}/memberOf`).get();

let user = new User();
user.id = graphUser.id;
user.displayName = graphUser.displayName;
// Prefer the mail property, but fall back to userPrincipalName
user.email = graphUser.mail || graphUser.userPrincipalName;

graphUserGroups.value.forEach(group => {
    user.groups.push({
        group_id: group.id,
        group_name: group.displayName
    });
});
Hagiology answered 8/5, 2019 at 21:7 Comment(3)
Thanks - that's the path that I went along. Do you have any tips on how to get around the 'requires admin consent' prompt related to directory.read.all permission? I've been banging my head against this and have yet to find a solution to getting admin consent workingIzettaizhevsk
In my case, I had to ask my admin on our account to grant that permission.Hagiology
Ah yes - that was my findings as well. ThanksIzettaizhevsk
I
2

(Thanks goes to stillatmylinux)

FYI: Here's my working angular 7 solution (simplified for the sake of readability):

import { MsalService, BroadcastService } from '@azure/msal-angular';
import { Client } from '@microsoft/microsoft-graph-client';

private subscription: Subscription;
private graphClient: Client;
private memberRoles: any[];

constructor(
  readonly auth: MsalService,
  readonly broadcast: BroadcastService
) {
  // Initialize Microsoft Graph client
  this.graphClient = Client.init({
    authProvider: async (done) => {
      let token = await this.auth.acquireTokenSilent(["User.Read", "Directory.Read.All"])
        .catch((reason) => {
          done(reason, null);
        });

      if (token) {
        done(null, token);
      } else {
        done("Could not get an access token", null);
      }
    }
  });

  this.subscription = broadcast.subscribe("msal:loginSuccess",
    () => {
      //Get associated member roles
      this.graphClient.api('/me/memberOf').get()
        .then((response) => {
          this.memberRoles = response.value;
        }, (error) => {
          console.log('getMemberRoles() - error');
      });
  });
}
Izettaizhevsk answered 8/5, 2019 at 12:55 Comment(0)
M
2

You can change the manifest to get these delivered in the token itself.

The sample (its for .NET though), explains this in detail

Mclaughlin answered 9/5, 2019 at 9:1 Comment(2)
We've tried setting the appRoles and also have passed the authority url consisting of the tenantId. Also we've got the admin consent for Directory.Read.All, still the roles / groups are not being fetched in idToken. Any idea if anything more is required?Jasmin
@PavanKumarKattamuri You need to set the authority to https://login.microsoftonline.com/<your azure tenant id>. The authority that most of the samples come with use https://login.microsoftonline.com/common which doesn't return the groups or roles.Citreous
E
1

You only needs User.Read permission and to use memberof v1. Use import * as MicrosoftGraph from '@microsoft/microsoft-graph-client'; to fix microsoft-graph-client header export bug. uniqueId is your AzureAD user id.

private loginSuccess(uniqueId: string) {
     console.log('LOGIN SUCCESS ', uniqueId);
     (this.graphClient = MicrosoftGraph.Client.init({
      authProvider: async (done) => {
        let param: AuthenticationParameters = { authority:"https://login.microsoftonline.com/{TenantId}",
                                              scopes:["User.Read"]
                      };
        let response = await this.authService.acquireTokenSilent(param)
        .catch((reason) => {
          done(reason, null);
          });

        if (response) {
          done(null, response.accessToken);
        } else {
          done("Could not get an access token", null);
        }
      }
    })).api(`/users/${uniqueId}/memberOf`).get()
    .then((response)=>{
        this.groups = response.value;
        console.log("members ok", this.groups);
    },
    (error)=>{
      console.error('memberOf error');
    });

}
Erinerina answered 6/3, 2020 at 19:26 Comment(0)
M
0

With MSAL-ANGULAR (the current stable version "@azure/msal-angular": "^1.1.2) You can access the roles from the authentication response(key msal.idtoken).

With the modern browsers this can be found in Local storage and for the IE this will stored in cookies. Since the msal.idtoken is Jwt, decoding this should provide the user's role.

const token = localStorage.getItem('msal.idtoken');
const payload = jwt_decode(token); // jwt_decode npm package will help you to decode the payload.
console.log(payload);

Alternatively you can even use https://jwt.io/ to manually decode the data.

Mistrust answered 12/2, 2021 at 5:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.