> For the complete documentation index, see [llms.txt](https://docs.industryapps.net/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.industryapps.net/authentication/single-sign-on/angular.md).

# Angular

## Integrating SSO with <img src="/files/azOBoR1uFisSB8TL0NMR" alt="" data-size="line">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.

{% code title="environment.ts" overflow="wrap" lineNumbers="true" %}

```javascript
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
  }
};

```

{% endcode %}

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

{% code title="authconfig.module.ts" overflow="wrap" lineNumbers="true" %}

```javascript
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 { }

```

{% endcode %}

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.

{% code title="auth.config.ts" overflow="wrap" lineNumbers="true" %}

```javascript
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;
}
```

{% endcode %}

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.

{% code title="auth-config.service.ts" overflow="wrap" lineNumbers="true" %}

```javascript
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();
    }

}
```

{% endcode %}

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

{% code title="auth-config.service.spec.ts" overflow="wrap" lineNumbers="true" %}

```javascript
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();
  });
});

```

{% endcode %}

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

{% code title="authconfig" %}

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

{% endcode %}

Be sure to import the environment into the `main.ts` file in your app directory. e.g.&#x20;

{% code overflow="wrap" lineNumbers="true" %}

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

{% endcode %}

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.

{% code title="main.ts" overflow="wrap" lineNumbers="true" %}

```javascript
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));

```

{% endcode %}

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

{% embed url="<https://github.com/IndustryApps/SSODemo-Angular>" %}
