Custom scopes are created and managed in Azure (Entra ID / Azure AD B2C) on the API’s app registration, then requested from the Angular SPA using MSAL.
1. Create custom scopes on the API app registration
- In the Azure portal, open the web API app registration (the resource the Angular app will call).
- Go to Expose an API.
- Set the Application ID URI (for example,
api://<api-client-id> or a custom URI like https://contoso.com/api) and Save.
- Under Scopes defined by this API, select Add a scope.
- Fill in:
- Scope name (for example,
tasks.read, tasks.write)
- Consent display name/description fields
- Who can consent (Admins and users or Admins only)
- Select Add scope.
The full scope string is:
<Application ID URI>/<Scope name>
For example:
-
api://<api-client-id>/tasks.read
-
https://contoso.com/api/Employees.Read.All
This matches the pattern described for web APIs:
- Application ID URI acts as the prefix
- Scope name is appended to form the full scope string.
2. Grant the Angular app permission to those scopes
- Open the Angular SPA app registration.
- Go to API permissions → Add a permission.
- Choose My APIs, select the API app.
- Under the API’s permission set, select the scopes created earlier (for example,
tasks.read, tasks.write).
- Add permissions and, if needed, select Grant admin consent.
- Optionally copy the full scope name from the configured permissions list for use in the Angular app.
This is the same pattern shown for an Angular SPA and API with scopes like tasks.read and tasks.write.
3. Use scopes in Angular MSAL (MsalGuard)
In MSAL Angular, MsalGuardConfiguration can include an authRequest with scopes. The scopes array must contain the full scope strings created above, not just the short names.
Example MsalGuard configuration:
import { InteractionType } from '@azure/msal-browser';
import { MsalGuardConfiguration } from '@azure/msal-angular';
export function MSALGuardConfigFactory(): MsalGuardConfiguration {
return {
interactionType: InteractionType.Redirect,
authRequest: {
scopes: [
'api://<api-client-id>/tasks.read',
'api://<api-client-id>/tasks.write'
]
},
loginFailedRoute: './login-failed',
};
}
Key points:
-
authRequest.scopes should be the full scope URIs, e.g. api://<api-client-id>/<scope-name>.
-
authRequest is optional but recommended so consent is obtained up front and users are not prompted multiple times.
-
MsalGuard will use these scopes when prompting the user to sign in.
If dynamic scopes are needed per route, authRequest can be a function that returns different scopes based on the route state, as shown in the dynamic example:
authRequest: (authService, state) => {
return {
scopes: state.root.url.some(x => x.path === 'calendar')
? ['user.read', 'Calendars.Read']
: ['user.read']
};
}
4. Summary
- Custom scopes are defined on the API app registration under Expose an API.
- The full scope is
Application ID URI + / + Scope name.
- The Angular SPA must be granted those scopes under API permissions.
- In MSAL Angular, configure
MsalGuard with authRequest.scopes set to the full scope strings like api://<api-client-id>/tasks.read.
References: