Installing the pacakage
Install the angular-oauth2-oidc package using npm.
npm i angular-oauth2-oidc --save
Setting up the NgModule (app.module)
When package installation has been done then import the OAuthModule in the app.modulefile.
import { OAuthModule } from 'angular-oauth2-oidc';
[...]
@NgModule({
imports: [
[...] HttpModule,
OAuthModule.forRoot()
],
........export classAppModule{}
Implicit Flow configuration & Login page
This is the OAuth2/OIDC flow best suitable for SPA. It sends the user to the IdentityProvider's login page (Identity Server). After logging in, the SPA gets tokens. This alsoallows for single sign on as well as single sign off.
To configure the library just have to set some properties (AuthConfig) on startup as requiredby OAuthService i.e. on the constructor of the AppComponent which is called before therouting kicks in.
import { AuthConfig } from'angular-oauth2-oidc';
export const authConfig: AuthConfig = {
// Url of the Identity Provider
issuer: 'https://demo.identityserver.com/identity',
// Login Url of the Identity Provider
loginurl: 'https://demo.identityserver.com/identity/connect/authorize',
// Login Url of the Identity Provider
logouturl: 'https://demo.identityserver.com/identity/connect/endsession',
// URL of the SPA to redirect the user to after login
redirectUri: window.location.origin + '/dashboard.html',
// The SPA's id. The SPA is registerd with this id at the auth-server
clientId: 'billing_demo',
// set the scope for the permissions the client should request
// The first three are defined by OIDC. Also provide user sepecific
scope: 'openid profile email billing_demo_api',
}
When the AuthConfig properties has been set then configure the OAuthService for loadingidentity server's discovery document & if access token is invalid then trigger implicit flow for presenting users with the identity server's login page .
import { OAuthService } from 'angular-oauth2-oidc';
import { JwksValidationHandler } from 'angular-oauth2-oidc';
import { authConfig } from './auth.config';
import { Component } from '@angular/core';
@Component({
selector: 'billing-app',
templateUrl: './app.component.html'
})
exportclassAppComponent{
constructor(private oauthService: OAuthService) {
this.ConfigureImplicitFlowAuthentication();
}
private ConfigureImplicitFlowAuthentication() {
this.oauthService.configure(authConfig);
this.oauthService.tokenValidationHandler =
new JwksValidationHandler();
this.oauthService.loadDiscoveryDocument().then(doc) => {
this.oauthService.tryLogin().catch(err => {
console.error(err);
}).then(() => {
if (!this.oauthService.hasValidAccessToken()) {
this.oauthService.initImplicitFlow()
}
});
});
}
}
The discovery endpoint can be used to retrieve metadata about your IdentityServer - it returns information like the issuer name, key material, supported scopes etc.The discovery endpoint is available via /.well-known/openid-configuration relative to the base address
https://demo.identityserver.com/.well-known/openid-configuration
Automatically refreshing a token when/ before it expires (silent refresh)
To automatically refresh a token when/ some time before it expires, just call the following method after configuring the OAuthService in the AppComponent.
this.oauthService.setupAutomaticSilentRefresh();
By default, this event is fired after 75% of the token's life time is over. You can adjust this factor by setting the property timeoutFactor to a value between 0 and 1. For instance, 0.5means, that the event is fired after half of the life time is over and 0.33 triggers the event after a third
Passing Bearer access token when calling Web API
1. Passing directly by using the class HttpHeaders of new HttpClient
var headers = new HttpHeaders({"Authorization": "Bearer " + this.oauthService.getAccessToken()});
2. By setting allowedUrls to an array with prefixes for the respective urls. Use lower case forthe prefixes.
OAuthModule.forRoot({
resourceServer: {
allowedUrls: ['https://billing_demo_api.com/api'],
sendAccessToken: true
}
}
Logout configuration
In order to log out from the application, just need to call the logout() method of theOAuthService. It will end the session & redirects the user to the post logout redirect url associated to the client.
this.oauthService.logout();
Access Token & Identity Claims
To get the access token & identity claims, just need to call the getAccessToken() andgetIdentityClaims() methods of the OAuthService
this.oauthService.getIdentityClaims();
this.oauthService.getAccessToken()
Implementing AuthGuard
If you want to restrict some pages from unauthorized access, create AuthGuard class which further implements CanActivate that return either true if the user can access a route or false if they can’t based on the validity of the access token
import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot } from '@angular/router';
import { OAuthService } from 'angular-oauth2-oidc';
@Injectable() export class AuthGuard implements CanActivate {
constructor(private oauthService: OAuthService, private router: Router) {
}
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
if (this.oauthService.hasValidAccessToken()) {
return true;
} this.router.navigate(['']);
}
}
Then add the AuthGuard to the routing configuation as
const routes: Routes = [
{ path: 'home', component: HomeComponent },
{
path: 'search', component: SearchComponent,
canActivate: [AuthGuard]
},
{
path: 'bill/:billId', component: BillingComponent,
canActivate: [AuthGuard], children: [
{ path: '', redirectTo: 'ledger' }
]
}];
Top comments (7)
Thank you. I am having issues authentication my app against my api. My client app config looks just like yours. I assume my resource api has not been configured correctly. Would you share please how you have your resource api configured? Thank you
Informative post. Thanks for sharing bro! ❤️✌🏻
Thanks bro 😊✌️
Thank you
Hi Deekshith , I am trying to oidc with angular but my app is reloading again and again after trylogin method there by increasing uri size and stopping my angular app,please help!
Hey Gagan Deep, did you tried the entire process that I have explained above?
Do you have codebase for it