|
| 1 | +--- |
| 2 | +title: Use role-based access control in your Node.js web application |
| 3 | +description: Learn how to configure groups and user roles in your customer's tenant, so you can receive them as claims in a security token for your Node.js application |
| 4 | +services: active-directory |
| 5 | +author: kengaderdus |
| 6 | +manager: mwongerapk |
| 7 | + |
| 8 | +ms.author: kengaderdus |
| 9 | +ms.service: active-directory |
| 10 | +ms.workload: identity |
| 11 | +ms.subservice: ciam |
| 12 | +ms.topic: how-to |
| 13 | +ms.date: 06/16/2023 |
| 14 | +ms.custom: developer |
| 15 | +--- |
| 16 | + |
| 17 | +# Use role-based access control in your Node.js web application |
| 18 | + |
| 19 | +Role-based access control (RBAC) is a mechanism to enforce authorization in applications. Azure Active Directory (Azure AD) for customers allows you to define application roles for your application and assign those roles to users and groups. The roles you assign to a user or group define their level of access to the resources and operations in your application. When Azure AD for customers issues a security token for an authenticated user, it includes the names of the roles you've assigned the user or group in the security token's roles claim. |
| 20 | + |
| 21 | +You can also configure your Azure AD for customers tenant to return the group memberships of the user. Developers can then use security groups to implement RBAC in their applications, where the memberships of the user in specific groups are interpreted as their role memberships. |
| 22 | + |
| 23 | +Once you assign users and groups to roles, the *roles* claim is emitted in your security token. However, to emit the *groups* membership claim in security tokens, you need additional configuration in your customer's tenant. |
| 24 | + |
| 25 | +In this article, you learn how to receive user roles or group membership or both as claims in a security token for your Node.js web app. |
| 26 | + |
| 27 | +## Prerequisites |
| 28 | + |
| 29 | +- A security group in your customer's tenant. If you've not done so, [create one](../../roles/groups-create-eligible.md#azure-portal). |
| 30 | + |
| 31 | +- If you've not done so, complete the steps in [Using role-based access control for applications](how-to-use-app-roles-customers.md) article. This article shows you how to create roles for your application, how to assign users and groups to those roles, how to add members to a group and how to add a group claim to a to security token. Learn more about [ID tokens](../../develop/id-tokens.md) and [access tokens](../../develop/access-tokens.md). |
| 32 | + |
| 33 | +- If you've not done so, complete the steps in [Sign in users in your own Node.js web application](how-to-web-app-node-sign-in-overview.md) |
| 34 | + |
| 35 | +## Receive groups and roles claims in your Node.js web app |
| 36 | + |
| 37 | +Once you configure your customer's tenant, you can retrieve your *roles* and *groups* claims in your client app. The *roles* and *groups* claims are both present in the ID token and the access token, but your client app only needs to check for these claims in the ID token to implement authorization in the client side. The API app can also retrieve these claims when it receives the access token. |
| 38 | + |
| 39 | +You check your *roles* claim value as shown in the following code snippet example: |
| 40 | + |
| 41 | +```javascript |
| 42 | +const msal = require('@azure/msal-node'); |
| 43 | +const { msalConfig, TENANT_SUBDOMAIN, REDIRECT_URI, POST_LOGOUT_REDIRECT_URI } = require('../authConfig'); |
| 44 | + |
| 45 | +... |
| 46 | +class AuthProvider { |
| 47 | +... |
| 48 | + async handleRedirect(req, res, next) { |
| 49 | + const authCodeRequest = { |
| 50 | + ...req.session.authCodeRequest, |
| 51 | + code: req.body.code, // authZ code |
| 52 | + codeVerifier: req.session.pkceCodes.verifier, // PKCE Code Verifier |
| 53 | + }; |
| 54 | + |
| 55 | + try { |
| 56 | + const msalInstance = this.getMsalInstance(this.config.msalConfig); |
| 57 | + const tokenResponse = await msalInstance.acquireTokenByCode(authCodeRequest, req.body); |
| 58 | + let roles = tokenResponse.idTokenClaims.roles; |
| 59 | + |
| 60 | + //Check roles |
| 61 | + if (roles && roles.includes("Orders.Manager")) { |
| 62 | + //This user can view the ID token claims page. |
| 63 | + res.redirect('/id'); |
| 64 | + } |
| 65 | + |
| 66 | + //User can only view the index page. |
| 67 | + res.redirect('/'); |
| 68 | + } catch (error) { |
| 69 | + next(error); |
| 70 | + } |
| 71 | + } |
| 72 | +... |
| 73 | +} |
| 74 | + |
| 75 | +``` |
| 76 | + |
| 77 | +If you assign a user to multiple roles, the `roles` string contains all roles separated by a comma, such as `Orders.Manager,Store.Manager,...`. Make sure you build your application to handle the following conditions: |
| 78 | + |
| 79 | +- absence of `roles` claim in the token |
| 80 | +- user hasn't been assigned to any role |
| 81 | +- multiple values in the `roles` claim when you assign a user to multiple roles |
| 82 | + |
| 83 | +You can also check your *groups* claim value as shown in the following code snippet example: |
| 84 | + |
| 85 | +```javascript |
| 86 | +const tokenResponse = await msalInstance.acquireTokenByCode(authCodeRequest, req.body); |
| 87 | +let groups = tokenResponse.idTokenClaims.groups; |
| 88 | +``` |
| 89 | +The groups claim value is the group's *objectId*. If a user is a member of multiple groups, the `groups` string contains all groups separated by a comma, such as `7f0621bc-b758-44fa-a2c6-...,6b35e65d-f3c8-4c6e-9538-...`. |
| 90 | + |
| 91 | +> [!NOTE] |
| 92 | +> If you assign a user [Azure AD in-built roles](../../roles/permissions-reference.md) or commonly known as directory roles, those roles appear in the *groups* claim of the security token. |
| 93 | +
|
| 94 | +## Handle groups overage |
| 95 | + |
| 96 | +To ensure that the size of the security token doesn’t exceed the HTTP header size limit, Azure AD for customers limits the number of object IDs that it includes in the *groups* claim. The overage limit is **150 for SAML tokens and 200 for JWT tokens**. It's possible to exceed this limit if a user belongs to many groups, and you request for all the groups. |
| 97 | + |
| 98 | +### Detect group overage in your source code |
| 99 | + |
| 100 | +If you can't avoid groups overages, then you need to handle it in your code. When you exceed the overage limit, the token doesn't contain the *groups* claim. Instead, the token contains a *_claim_names* claim that contains a *groups* member of the array. So, you need to check the existence of *_claim_names* claim to tell that an overage has occurred. The following code snippet shows you how to detect a groups overage: |
| 101 | + |
| 102 | +```javascript |
| 103 | +const tokenResponse = await msalInstance.acquireTokenByCode(authCodeRequest, req.body); |
| 104 | + |
| 105 | +if(tokenResponse.idTokenClaims.hasOwnProperty('_claim_names') && tokenResponse.idTokenClaims['_claim_names'].hasOwnProperty('groups')) { |
| 106 | + //overage has occurred |
| 107 | +} |
| 108 | +``` |
| 109 | + |
| 110 | +Use the instructions in [Configuring group claims and app roles in tokens](/security/zero-trust/develop/configure-tokens-group-claims-app-roles#group-overages) article to learn how request for the full groups list when groups overage occurs. |
| 111 | + |
| 112 | +## How to use groups and roles values in your Node.js web app |
| 113 | + |
| 114 | +In the client app, you can verify whether a signed-in user has the necessary role(s) to access a protected route or call an API endpoint. This can be done by checking the `roles` claim in the ID token. To implement this protection in your app, you can build guards by using a custom middleware. |
| 115 | + |
| 116 | +In your service app (API app), you can also protect the API endpoints. After you [validate the access token](../../develop/access-tokens.md#validate-tokens) sent by the client app, you can check for the *roles* or *groups* claims in the payload claims of the access token. |
| 117 | + |
| 118 | +## Do I use App Roles or Groups? |
| 119 | + |
| 120 | +In this article, you have learned that you can use *App Roles* or *Groups* to implement RBAC in your application. The preferred approach is to use app roles as app roles provide more granular control when managing access/permissions at the application level. For more information on how to choose an approach, see [Choose an approach](../../develop/custom-rbac-for-developers.md#choose-an-approach). |
| 121 | + |
| 122 | +## Next steps |
| 123 | + |
| 124 | +- Learn more about [Configuring group claims and app roles in tokens](/security/zero-trust/develop/configure-tokens-group-claims-app-roles). |
0 commit comments