Developer Documentation
  • Documentation Overview
  • Development Introduction
  • Getting Started
  • Fundamentals
    • Deploy an App via Pre-defined Sidecar
      • Sidecar Tutorial: Server-side
      • Sidecar Tutorial: Client-side
      • Sidecar Tutorial: Docker & Deploy
    • Deploy an App with Eureka
    • Design Guidance
  • Authentication
    • Accessing data exposed by the platform
    • Single Sign-On
      • Angular
      • Vue
      • Java Spring: Accepting JWT
      • Python Django: Accepting JWT
    • User and Role Identification
  • APIs | Data Integration
    • Submodel Index
    • Masterdata
    • Transactional data
  • Docker Information
    • Ruby Stack
    • Golang Stack
    • Node JS Stack
    • Java Spring Stack
    • Python Stack
  • Connect to the Platform
    • Integrate using Eureka Rest APIs
    • Use our Pre-built sidecar
    • Production deployment
  • Add-on Features
    • IApps-Navigation
  • Testing
  • FAQs | Troubleshooting
  • Registration
    • Application pre-requisites
      • Basic Requirements
    • Register Developer Account
    • Submit basic application info
    • Onboard Application
      • Submit Appstore details
        • App basic information
      • Configure Application
        • App Permission
        • App Data
        • AAS Instance
        • Licensing
        • Access Rights
        • Account Info
        • Terms Of Use
        • Pricing
      • Publish and test
        • Deploy
        • Register into Service Discovery
    • Publish to Marketplace
  • User Experience
  • The business model - How do I get paid?
  • References
    • IndustryApps - Intro
    • What is an Asset Administration Shell?
    • What is ECLASS?
      • How is ECLASS and Concept dictionary are used
    • Industry 4.0 standards
    • Customer Terms of Use
      • Subscription Order
    • Solution provider Terms of Use
      • Contract regions
      • Submission Form ( Solution provider)
Powered by GitBook
On this page
  • Integrating SSO with Angular
  • Angular Guide for SSO OpenID-Connect
  1. Authentication
  2. Single Sign-On

Angular

How to integrate Single Sign-on with Angular and Java Spring 5 frameworks

PreviousSingle Sign-OnNextVue

Last updated 2 years ago

Integrating SSO with Angular

The following example illustrates how SSO can be integrated within your applications' code. The example shows how would an application using Angular enable the SSO feature via OpenID-Connect.

Angular Guide for SSO OpenID-Connect

This Angular guide requires the following dependency via npm:

  • angular-oauth2-oidc

Run in terminal:

npm install angular-oauth2-oidc --save

Add an environment.ts file to your project directory. This will contain the required credentials to connect to IndustryApps Keycloak OpenID-Connect.

environment.ts
export const environment = {
  production: true,
  envName: 'local',
  keycloak: {
    // Url of the Identity Provider
    issuer: 'https://auth.uat.industryapps.net/auth/realms/IndustryApps',

    // URL of the SPA to redirect the user to after login (Development Env)
    redirectUri: 'https://democustomer.uat.industryapps.net/<APPCODE>/',

    // The SPA's id. 
    // The SPA is registerd with this id at the auth-serverß
    clientId: 'APPID',

    responseType: 'code',
    // set the scope for the permissions the client should request
    // The first three are defined by OIDC.
    scope: 'openid profile email',
    // Remove the requirement of using Https to simplify the demo
    // THIS SHOULD NOT BE USED IN PRODUCTION
    // USE A CERTIFICATE FOR YOUR IDP
    // IN PRODUCTION
    requireHttps: false,
    // at_hash is not present in JWT token
    showDebugInformation: true,
    disableAtHashCheck: true
  }
};

Include an authconfig sub-directory in your project directory. Create an authconfig.module.ts file which initialises an oauth2-oidc module as illustrated below:

authconfig.module.ts
import { NgModule, APP_INITIALIZER } from '@angular/core';
import { HttpClientModule } from '@angular/common/http';
import { OAuthModule, AuthConfig } from 'angular-oauth2-oidc';

import { AuthConfigService } from './auth-config.service';
import { authConfig, OAuthModuleConfig } from './auth.config';

export function init_app(authConfigService: AuthConfigService) {
    return () => authConfigService.initAuth();
}

@NgModule({
  imports: [ HttpClientModule, OAuthModule.forRoot() ],
  providers: [
    AuthConfigService,
    { provide: AuthConfig, useValue: authConfig },
    OAuthModuleConfig,
    { 
      provide: APP_INITIALIZER, 
      useFactory: init_app, 
      deps: [ AuthConfigService ], 
      multi: true
    }
  ]
})
export class AuthConfigModule { }

Add an auth.config.ts file in the authconfig sub-directory. auth.config.ts would utilise the environment variables configured in the environment.ts file made previously.

auth.config.ts
import { AuthConfig } from 'angular-oauth2-oidc';
import { environment } from '../../environments/environment';

export const authConfig: AuthConfig = {

    // Url of the Identity Provider
    issuer: environment.keycloak.issuer,

    // URL of the SPA to redirect the user to after login
    redirectUri: environment.keycloak.redirectUri,

    // The SPA's id. 
    // The SPA is registerd with this id at the auth-serverß
    clientId: environment.keycloak.clientId,

    responseType: environment.keycloak.responseType,
    // set the scope for the permissions the client should request
    // The first three are defined by OIDC.
    scope: environment.keycloak.scope,
    // Remove the requirement of using Https to simplify the demo
    // THIS SHOULD NOT BE USED IN PRODUCTION
    // USE A CERTIFICATE FOR YOUR IDP
    // IN PRODUCTION
    requireHttps: environment.keycloak.requireHttps,
    // at_hash is not present in JWT token
    showDebugInformation: environment.keycloak.showDebugInformation,
    disableAtHashCheck: environment.keycloak.disableAtHashCheck
};


export class OAuthModuleConfig {
    resourceServer: OAuthResourceServerConfig = {sendAccessToken: false};
}

export class OAuthResourceServerConfig {
    /**
     * Urls for which calls should be intercepted.
     * If there is an ResourceServerErrorHandler registered, it is used for them.
     * If sendAccessToken is set to true, the access_token is send to them too.
     */
    allowedUrls?: Array<string>;
    sendAccessToken = true;
    customUrlValidation?: (url: string) => boolean;
}

Add an auth-config.service.ts file to the authconfig sub-directory which sets up OAuthService. auth-config.service.ts initialises a login page if authorisation is required otherwise initialises the app instance.

auth-config.service.ts
import { Injectable } from '@angular/core';
import { AuthConfig, NullValidationHandler, OAuthService } from 'angular-oauth2-oidc';
import { filter } from 'rxjs/operators';

@Injectable()
export class AuthConfigService {
    
    private _decodedAccessToken: any;
    private _decodedIDToken: any;
    get decodedAccessToken() { return this._decodedAccessToken; }
    get decodedIDToken() { return this._decodedIDToken; }

    constructor(
      private readonly oauthService: OAuthService,
      private readonly authConfig: AuthConfig,
    ) {}

    async initAuth(): Promise<any> {
      return new Promise<void>((resolveFn, rejectFn) => {
        // setup oauthService
        this.oauthService.configure(this.authConfig);
        this.oauthService.setStorage(localStorage);
        this.oauthService.tokenValidationHandler = new NullValidationHandler();
  
        // subscribe to token events
        this.oauthService.events
          .pipe(filter((e: any) => {
            return e.type === 'token_received';
          }))
          .subscribe(() => this.handleNewToken());
          
        // continue initializing app or redirect to login-page
        
        this.oauthService.loadDiscoveryDocumentAndLogin().then(isLoggedIn => {
          if (isLoggedIn) {
            this.oauthService.setupAutomaticSilentRefresh();
            resolveFn();
          } else {
            this.oauthService.initImplicitFlow();
            rejectFn();
          }
        });
        
      });
    }
  
    private handleNewToken() {
      this._decodedAccessToken = this.oauthService.getAccessToken();
      this._decodedIDToken = this.oauthService.getIdToken();
    }

}

Add auth-config.service.spec.ts to the authconfig sub-directory which is the last requirement to be added in the authconfig sub-directory.

auth-config.service.spec.ts
import { TestBed } from '@angular/core/testing';

import { AuthConfigService } from './auth-config.service';

describe('AuthConfigService', () => {
  let service: AuthConfigService;

  beforeEach(() => {
    TestBed.configureTestingModule({});
    service = TestBed.inject(AuthConfigService);
  });

  it('should be created', () => {
    expect(service).toBeTruthy();
  });
});

So far the addition of the authconfig sub-directory includes:

authconfig
.
├── auth-config.service.spec.ts
├── auth-config.service.ts
├── auth.config.ts
└── authconfig.module.ts

Be sure to import the environment into the main.ts file in your app directory. e.g.

import { environment } from './environments/environment';

A full main.ts file example is illustrated below, given you've designated both an environment.prod.ts version and environment.ts file in an environments sub-directory.

main.ts
import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

import { AppModule } from './app/app.module';
import { environment } from './environments/environment';

if (environment.production) {
  enableProdMode();
}

platformBrowserDynamic().bootstrapModule(AppModule)
  .catch(err => console.error(err));

A full demo sample client-side Angular app is available below provided as a reference.

https://github.com/IndustryApps/SSODemo-Angulargithub.com