MSAL Angular provides an Interceptor
class that automatically acquires tokens for outgoing requests that use the Angular http
client to known protected resources. This doc provides more information about the configuring and using the MsalInterceptor
.
While we recommend using the MsalInterceptor
instead of the acquireTokenSilent
API directly, please note that using the MsalInterceptor
is optional. You may wish to explicitly acquire tokens using the acquireToken APIs instead.
Please note that the MsalInterceptor
is provided for your convenience and may not fit all use cases. We encourage you to write your own interceptor if you have specific needs that are not addressed by the MsalInterceptor
.
The MsalInterceptor
can be added to your application as a provider in the app.module.ts, with its configuration. The imports takes in an instance of MSAL, as well as two Angular-specific configuration objects. The third argument is a MsalInterceptorConfiguration
object, which contain the values for interactionType
, a protectedResourceMap
, and an optional authRequest
.
Your configuration may look like the below. See our configuration doc on other ways to configure MSAL Angular for your app.
import { NgModule } from '@angular/core';
import { HTTP_INTERCEPTORS, HttpClientModule } from "@angular/common/http";
import { AppComponent } from './app.component';
import { MsalModule, MsalRedirectComponent, MsalGuard, MsalInterceptor } from '@azure/msal-angular'; // Import MsalInterceptor
import { InteractionType, PublicClientApplication } from '@azure/msal-browser';
@NgModule({
declarations: [
AppComponent,
],
imports: [
MsalModule.forRoot( new PublicClientApplication({
// MSAL Configuration
}), {
// MSAL Guard Configuration
}, {
// MSAL Interceptor Configurations
interactionType: InteractionType.Redirect,
protectedResourceMap: new Map([
['Enter_the_Graph_Endpoint_Here/v1.0/me', ['user.read']]
])
})
],
providers: [
{
provide: HTTP_INTERCEPTORS, // Provides as HTTP Interceptor
useClass: MsalInterceptor,
multi: true
},
MsalGuard
],
bootstrap: [AppComponent, MsalRedirectComponent]
})
export class AppModule { }
While the MsalInterceptor
is designed to acquire tokens silently, in the event that a silent request fails, it will fall back to acquiring tokens interactively. The InteractionType
can be imported from @azure/msal-browser
and set to Popup
or Redirect
.
{
interactionType: InteractionType.Redirect,
protectedResourceMap: new Map([
['Enter_the_Graph_Endpoint_Here/v1.0/me', ['user.read']]
])
}
The protected resources and corresponding scopes are provided as a protectedResourceMap
in the MsalInterceptor
configuration.
The URLs you provide in the protectedResourceMap
collection are case-sensitive. For each resource, add scopes being requested to be returned in the access token.
For example:
["user.read"]
for Microsoft Graph["<Application ID URL>/scope"]
for custom web APIs (that is,api://<Application ID>/access_as_user
)
Scopes can be specified for a resource in the following ways:
-
An array of scopes, which will be added to every HTTP request to that resource, regardless of HTTP method.
{ interactionType: InteractionType.Redirect, protectedResourceMap: new Map<string, Array<string> | null>([ ["https://graph.microsoft.com/v1.0/me", ["user.read", "profile"]], ["https://myapplication.com/user/*", ["customscope.read"]] ]), }
-
An array of
ProtectedResourceScopes
, which will attach scopes only for specific HTTP methods.{ interactionType: InteractionType.Redirect, protectedResourceMap: new Map<string, Array<string|ProtectedResourceScopes> | null>([ ["https://graph.microsoft.com/v1.0/me", ["user.read"]], ["http://myapplication.com", [ { httpMethod: "POST", scopes: ["write.scope"] } ]] ]) }
Note that scopes for a resource can contain a combination of strings and
ProtectedResourceScopes
. In the below example, aGET
request will have the scopes"all.scope"
and"read.scope"
, whereas asPUT
request would just have"all.scope"
.{ interactionType: InteractionType.Redirect, protectedResourceMap: new Map<string, Array<string|ProtectedResourceScopes> | null>([ ["http://myapplication.com", [ "all.scope", { httpMethod: "GET", scopes: ["read.scope"] }, { httpMethod: "POST", scopes: ["info.scope"] } ]] ]) }
-
A scope value of
null
, indicating that a resource is to be unprotected and will not get tokens. Resources not included in theprotectedResourceMap
are not protected by default. Specifying a particular resource to be unprotected can be useful when some routes on a resource are to be protected, and some are not. Note that the order inprotectedResourceMap
matters, so null resource should be put before any similar base urls or wildcards.{ interactionType: InteractionType.Redirect, protectedResourceMap: new Map<string, Array<string> | null>([ ["https://graph.microsoft.com/v1.0/me", ["user.read", "profile"]], ["https://myapplication.com/unprotected", null], ["https://myapplication.com/unprotected/post", [{ httpMethod: 'POST', scopes: null }]], ["https://myapplication.com", ["custom.scope"]] ]), }
Other things to note regarding the protectedResourceMap
:
- Wildcards:
protectedResourceMap
supports using*
for wildcards. When using wildcards, if multiple matching entries are found in theprotectedResourceMap
, the first match found will be used (based on the order of theprotectedResourceMap
). - Relative paths: If there are relative resource paths in your application, you may need to provide the relative path in the
protectedResourceMap
. This also applies to issues that may arise with ngx-translate. Be aware that the relative path in yourprotectedResourceMap
may or may not need a leading slash depending on your app, and may need to try both.
For more information on the optional authRequest
that can be set in the MsalInterceptorConfiguration
, please see our multi-tenant doc here.
- Note that the
unprotectedResourceMap
in MSAL Angular v1'sMsalAngularConfiguration
has been deprecated and no longer works. protectedResourceMap
has been moved to theMsalInterceptorConfiguration
object, and can be passed asMap<string, Array<string|ProtectedResourceScopes>>
.MsalAngularConfiguration
has been deprecated and no longer works.- Putting the root domain in the
protectedResourceMap
to protect all routes is no longer supported. Please use wildcard matching instead.