Implicit flow authentication using angular-oauth2-oidc (Angular)
Tags: angular, authentication, oauth2, typescript
Published: 2020-09-22 08:01:14

###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' }
    ]
  }];

```