Angular oauth2 OIDC
install oauth2 in Angular
npm i angular-oauth2-oidc --save
npm i angular-oauth2-oidc-jwks --save
add service --AuthGuard
\app ng g service shared/services/authguard --skip-tests
import { Injectable } from '@angular/core';
import { OAuthService } from 'angular-oauth2-oidc';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, Router } from '@angular/router';
@Injectable({
providedIn: 'root'
})
export class AuthguardService implements CanActivate {
constructor(
private oauthService: OAuthService,
private router: Router) { }
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean {
// Check to see if we have an application user
// If we dont, we navigate to [/]
if (this.oauthService.hasValidAccessToken()) {
return true;
}
this.router.navigate(['/']);
return false;
};
}
add service
ng g service shared/services/globals --skip-tests
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class GlobalsService {
constructor() { }
IdentityServer_Http_URI: string = 'http://localhost:5000';
IdentityServer_Https_URI: string = 'https://localhost:5001';
WebAPI_Http_URI: string = 'http://localhost:5002';
WebAPI_Https_URI: string = 'https://localhost:5003';
WebApp_URI: string = 'http://localhost:4200';
WebApp_Redirect_URI: string = 'http://localhost:4200';
WebApp_Post_Logout_Redirect_URI: string = 'http://localhost:4200';
Client_Id: string = 'WWWebUI'; ///<<<<
Client_Scopes: string = 'openid profile roles api.resource.scope';
}
add service
ng g service shared/services/http.service --skip-tests
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable, Subject } from 'rxjs';
import { GlobalsService } from './globals.service';
@Injectable({
providedIn: 'root'
})
export class HttpService {
response: string = '';
private $apiSubject = new Subject<string>();
constructor(private httpClient: HttpClient,
private globalsService: GlobalsService) {
}
requestWeatherForecast() {
this.httpClient.get<string>(`${this.globalsService.WebAPI_Https_URI}/WeatherForecast`)
.subscribe((response: string) => {
this.$apiSubject.next(JSON.stringify(response));
});
}
getWeatherForecast(): Observable<string> {
return this.$apiSubject.asObservable();
}
}
importing the NgModule
app.module.ts
@NgModule({
imports: [
// etc.
HttpClientModule,
OAuthModule.forRoot() <<<< add this
login / logout - app.component.ts
app.component.ts
import { Component, OnDestroy, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { OAuthService, OAuthEvent } from 'angular-oauth2-oidc';
import { JwksValidationHandler } from 'angular-oauth2-oidc-jwks';
import { Subscription } from 'rxjs';
import { AuthConfig } from 'angular-oauth2-oidc';
import { GlobalsService } from './services/globals.service';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit, OnDestroy {
claims: any;
accessToken = '';
$oauthSubscription: Subscription;
authConfig: AuthConfig = {
issuer: this.globalsService.IdentityServer_Https_URI,
redirectUri: window.location.origin,
clientId: this.globalsService.Client_Id,
scope: this.globalsService.Client_Scopes,
postLogoutRedirectUri: this.globalsService.WebApp_Post_Logout_Redirect_URI
}
constructor(private oauthService: OAuthService,
private router: Router,
private globalsService: GlobalsService) {
this.$oauthSubscription = this.oauthService.events.subscribe((event: OAuthEvent) => {
this.accessToken = this.oauthService.getAccessToken();
});
}
ngOnInit() {
this.configureWithNewConfigApi();
}
ngOnDestroy() {
this.$oauthSubscription.unsubscribe();
}
private configureWithNewConfigApi() {
this.oauthService.configure(this.authConfig);
this.oauthService.tokenValidationHandler = new JwksValidationHandler(); //<<
// skipping login
this.oauthService.loadDiscoveryDocumentAndTryLogin().then(_ => {
if (!this.oauthService.hasValidIdToken() ||
!this.oauthService.hasValidAccessToken()) {
this.oauthService.initImplicitFlow(); //<< initialize
} else {
this.router.navigate(['/']);
}
})
}
logout() {
this.oauthService.logOut(); //<<<<< logout
}
get isAuthenticated(): boolean {
this.claims = this.oauthService.getIdentityClaims();
return this.claims !== undefined &&
this.claims !== null;
}
}
login / logout - app.component.html
<div *ngIf="isAuthenticated">
<button [routerLink]="['/data']" class="btn btn-primary">Get Data from WebAPI</button>
<button (click)="logout()" class="btn btn-primary">Log Out</button>
<h1>Welcome to your Angular Application!</h1>
<p>access token: {{accessToken}}</p>
</div>
<router-outlet></router-outlet>
app-routing.module.ts
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { DataComponent } from './data/data.component';
import { HomeComponent } from './home/home.component';
import { AuthguardService } from './services/authguard.service';
const routes: Routes = [
{ path: '', component: HomeComponent },
{ path: 'data', component: DataComponent, canActivate: [AuthguardService], runGuardsAndResolvers: "always" },
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule]
})
export class AppRoutingModule { }
References
Documentation:
https://openbase.com/js/angular-oauth2-oidc/documentation
Community-provided sample implementation
https://github.com/manfredsteyer/angular-oauth2-oidc
Angular Authentication with OpenID Connect and Okta in 20 Minutes
https://developer.okta.com/blog/2017/04/17/angular-authentication-with-oidc
Example angular-oauth2-oidc with AuthGuard
https://github.com/jeroenheijmans/sample-angular-oauth2-oidc-with-auth-guards/
Configuring for Implicit Flow
https://manfredsteyer.github.io/angular-oauth2-oidc/docs/additional-documentation/using-implicit-flow.html
Last updated