I'm integrating Microsoft Entra ID into Svelte SPA and ASP.NET Core Web API. The goal is to secure the API and implement user-specific permissions dynamically.
Current configuration:
Authentication setup in Entra ID
- Added Single-Page Application (SPA) platform with redirect URI:
http://localhost:3000/auth-callback
.
- Added Single-Page Application (SPA) platform with redirect URI:
Expose an API setup in Entra ID:
- Defined Application ID URI:
api://fxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
. - Created a scope
AdminTool.Read
- Added client application under "Authorized client applications" with the same client id since both FE and BE use the same Entra ID application
- Defined Application ID URI:
ASP.NET Core Web API configuration:
Startup (in
Program.cs
):builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"));
appsettings.json
:"AzureAd": { "Instance": "/", "TenantId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", "ClientId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", "ClientCredentials": [ { "SourceType": "ClientSecret", "ClientSecret": "xxxxxxxxxxxxxxxxxxx" } ], "Scopes": "api://fxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/AdminTool.Read" }
Frontend (Svelte):
When requesting a token, I pass the following scopes:
const scopes = ['openid', 'profile', 'api://fxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/AdminTool.Read'];
If I don't include the custom scope (
AdminTool.Read
), the API rejects the request.
Questions
What exactly do these API scopes do?
- Are they only for controlling access to the API at an application level, or can they be used for per-user permissions?
How can I implement user-specific permissions dynamically?
- I want to introduce scopes per user, such as Dashboard.Read, which I can add/remove through Graph API per user.
Is there a way to manage these scopes dynamically for individual users rather than defining them statically under "Expose an API"? Best Practices?
I'm integrating Microsoft Entra ID into Svelte SPA and ASP.NET Core Web API. The goal is to secure the API and implement user-specific permissions dynamically.
Current configuration:
Authentication setup in Entra ID
- Added Single-Page Application (SPA) platform with redirect URI:
http://localhost:3000/auth-callback
.
- Added Single-Page Application (SPA) platform with redirect URI:
Expose an API setup in Entra ID:
- Defined Application ID URI:
api://fxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
. - Created a scope
AdminTool.Read
- Added client application under "Authorized client applications" with the same client id since both FE and BE use the same Entra ID application
- Defined Application ID URI:
ASP.NET Core Web API configuration:
Startup (in
Program.cs
):builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"));
appsettings.json
:"AzureAd": { "Instance": "https://login.microsoftonline.com/", "TenantId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", "ClientId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx", "ClientCredentials": [ { "SourceType": "ClientSecret", "ClientSecret": "xxxxxxxxxxxxxxxxxxx" } ], "Scopes": "api://fxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/AdminTool.Read" }
Frontend (Svelte):
When requesting a token, I pass the following scopes:
const scopes = ['openid', 'profile', 'api://fxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/AdminTool.Read'];
If I don't include the custom scope (
AdminTool.Read
), the API rejects the request.
Questions
What exactly do these API scopes do?
- Are they only for controlling access to the API at an application level, or can they be used for per-user permissions?
How can I implement user-specific permissions dynamically?
- I want to introduce scopes per user, such as Dashboard.Read, which I can add/remove through Graph API per user.
Is there a way to manage these scopes dynamically for individual users rather than defining them statically under "Expose an API"? Best Practices?
Share Improve this question edited Feb 5 at 16:09 marc_s 755k184 gold badges1.4k silver badges1.5k bronze badges asked Feb 5 at 14:10 nopnop 6,3319 gold badges53 silver badges161 bronze badges 5 |1 Answer
Reset to default 3Note: API scopes in Entra ID control access at an application level, but user-specific permissions can be managed dynamically using app roles.
- Scopes grant access to specific resources or operations on your backend API.
- When your SPA requests a token, it specifies the desired scopes to Azure AD. In response, Azure AD issues a token that contains claims regarding the user's identity and their associated permissions.
Scopes are primarily used to manage access to the API at the application level, but they can also be applied on a per-user basis by checking the claims in the JWT token that is sent to your backend API.
- Although scopes like
AdminTool.Read
are defined at the application level, you can dynamically manage user-specific permissions by including app roles in the user's token. - For instance, a user with the
Dashboard.Read
role will be granted access to the dashboard feature in your app.
To implement it, check the below:
Created API app and exposed and API:
In SPAapp, granted API permissions like below:
As you are making use of two applications (API app and SPA app), you need to create app roles in both the applications and assign the user to it on both of them.
Create app role Dashboard.Read
in both API app and SPA app:
Now assign users to the app role in both applications in Enterprise application under users and groups blade:
For sample, I generated access token by using below parameters:
https://login.microsoftonline.com/TenantID/oauth2/v2.0/token
client_id: ClientID
grant_type: authorization_code
code: Code
redirect_uri: RedirectURL
code_verifier: xxx
scope: api://xxx/AdminTool.Read
When decoded, the access token will be containing both scp and roles claim:
This depicts that the user with scope AdminTool.Read
with role Dashboard.Read
will be able to read the dashboard.
- The user has the scope
AdminTool.Read
, which grants them permission to access the AdminTool in your API. - The user also has the role
Dashboard.Read
, which grants them permission to read the dashboard.
I tried to generate access token and did not assign the role to the user:
- The access token does not contain role claim with value
Dashboard.Read
, hence the user will not be able to read the dashboard.
Reference:
azure - How to add roles claim in access_token , currently it is coming in id_token? - Stack Overflow by juunas
Dashboard.Read
,Dashboard.Write
, etc., which I can add to a specific user via Graph API, and they'll get added to the JWT token as well. Question 1: How can I add these user-specific claims to the token? Question 2: What does it look like to integrate Graph API to assign these claims to a specific user? – nop Commented Feb 5 at 14:25