Skip to main content

Version 11 to 12

Version 12 introduces a big new feature with supporting multiple configurations and with that multiple identity provider. With that the configuration and the interface for the users changes.

We also introduced an easier way of configuring the lib from the start to align in best practices.

Bootstrapping the lib#

To make the configuration at the start easier and to be able to pass multiple configs we re-wrote the bootstrapping process of the lib.

Static configuration#

Old:

import { APP_INITIALIZER, NgModule } from '@angular/core';
import { AuthModule, OidcConfigService } from 'angular-auth-oidc-client';
// ...
export function configureAuth(oidcConfigService: OidcConfigService) {
return () =>
oidcConfigService.withConfig({
/* your config here */
});
}
@NgModule({
// ...
imports: [
// ...
AuthModule.forRoot(),
],
providers: [
OidcConfigService,
{
provide: APP_INITIALIZER,
useFactory: configureAuth,
deps: [OidcConfigService],
multi: true,
},
],
// ...
})
export class AppModule {}

New:

import { NgModule } from '@angular/core';
import { AuthModule } from 'angular-auth-oidc-client';
// ...
@NgModule({
// ...
imports: [
// ...
AuthModule.forRoot({
config: {
/* your config here */
},
}),
],
// ...
})
export class AppModule {}

Loading config from endpoint (http)#

Old

import { HttpClient } from '@angular/common/http';
import { APP_INITIALIZER, NgModule } from '@angular/core';
import { AuthModule, OidcConfigService, OidcSecurityService } from 'angular-auth-oidc-client';
import { map, switchMap } from 'rxjs/operators';
export function configureAuth(oidcConfigService: OidcConfigService, httpClient: HttpClient) {
const setupAction$ = httpClient.get<any>(`https://...`).pipe(
map((customConfig) => {
return {
/* your config mapping here */
};
}),
switchMap((config) => oidcConfigService.withConfig(config))
);
return () => setupAction$.toPromise();
}
@NgModule({
imports: [AuthModule.forRoot()],
providers: [
OidcSecurityService,
OidcConfigService,
{
provide: APP_INITIALIZER,
useFactory: configureAuth,
deps: [OidcConfigService, HttpClient],
multi: true,
},
],
exports: [AuthModule],
})
export class AuthConfigModule {}

New

import { HttpClient } from '@angular/common/http';
import { NgModule } from '@angular/core';
import { AuthModule, StsConfigHttpLoader, StsConfigLoader } from 'angular-auth-oidc-client';
import { map } from 'rxjs/operators';
export const httpLoaderFactory = (httpClient: HttpClient) => {
const config$ = httpClient
.get<any>(`https://...`)
.pipe(
map((customConfig: any) => {
return {
/* your config mapping here */
};
})
)
.toPromise();
return new StsConfigHttpLoader(config$);
};
@NgModule({
imports: [
AuthModule.forRoot({
loader: {
provide: StsConfigLoader,
useFactory: httpLoaderFactory,
deps: [HttpClient],
},
}),
],
exports: [AuthModule],
})
export class AuthConfigModule {}

Configuration#

authWellknownEndpoint renamed to authWellknownEndpointUrl#

Old:

export interface OpenIdConfiguration {
authWellknownEndpoint?: string;
// ...
}

New:

export interface OpenIdConfiguration {
authWellknownEndpointUrl?: string;
// ...
}

AuthWellKnownEndpoints are now part of the config#

In the previous version, authWellKnownEndpoints was a separate parameter you could provide alongside the config in withConfig to configure your Security Token Service's Well-Known Endpoints. This parameter still exists, and it is of the same type, but it's now a parameter on the config object rather than being a separate parameter on withConfig(..., authwellKonwn)

Old:

const config = { ... };
const authWellknownEndpoints = { ... };

New:

const config = {
authWellknownEndpoints: { ... }
// other values...
};

autoUserinfo --> autoUserInfo#

The casing was corrected in the config.

Old:

export interface OpenIdConfiguration {
autoUserinfo?: boolean;
// ...
}

New:

export interface OpenIdConfiguration {
autoUserInfo?: boolean;
// ...
}

Custom Params to pass to requests have been renamed#

  • customParams --> customParamsAuthRequest
  • customParamsRefreshToken --> customParamsRefreshTokenRequest
  • customParamsEndSession --> customParamsEndSessionRequest
  • customTokenParams --> customParamsCodeRequest

Old:

export interface OpenIdConfiguration {
customParams?: { [key: string]: string | number | boolean };
customParamsRefreshToken?: { [key: string]: string | number | boolean };
customParamsEndSession?: { [key: string]: string | number | boolean };
customTokenParams?: { [key: string]: string | number | boolean };
// ...
}

New:

export interface OpenIdConfiguration {
customParamsAuthRequest?: { [key: string]: string | number | boolean };
customParamsRefreshTokenRequest?: { [key: string]: string | number | boolean };
customParamsEndSessionRequest?: { [key: string]: string | number | boolean };
customParamsCodeRequest?: { [key: string]: string | number | boolean };
// ...
}

Service OidcSecurityService#

Getter for configuration replaced by method and object PublicConfiguration deleted#

The getter for the active configuration was removed as well as the object PublicConfiguration as return type. Since the AuthWellKnownEndpoints parameter is now part of the config, the property was replaced with methods to get the configuration directly. Please read below on how to get the currently used configuration.

Old:

export class OidcSecurityService {
get configuration(): PublicConfiguration {}
}

used with

const configuration = this.oidcSecurityService.configuration;

New:

getConfigurations(): OpenIdConfiguration[] { }
getConfiguration(configId?: string): OpenIdConfiguration { }

used with

const configurations = this.oidcSecurityService.getConfigurations();
const configuration = this.oidcSecurityService.getConfiguration();
// or
const configuration = this.oidcSecurityService.getConfiguration('configId');

getToken() renamed to getAccessToken()#

Old

const accessToken = this.oidcSecurityService.getToken();

New

const accessToken = this.oidcSecurityService.getAccessToken();

checkAuth() returning LoginResponse instead of boolean#

The checkAuth() method no longer returns a boolean value denoting the authentication status. Instead, an object is returned containing:

{
isAuthenticated: boolean;
userData: any;
accessToken: string;
idToken: string;
configId: string;
errorMessage?: string;
}

Old:

this.oidcSecurityService.checkAuth().subscribe((isAuthenticated) => {});

New:

this.oidcSecurityService.checkAuth().subscribe(({ isAuthenticated }) => {});

Or

this.oidcSecurityService.checkAuth().subscribe(({ isAuthenticated, userData, accessToken, idToken, configId }) => {
// ...use data
});

checkAuthIncludingServer() returning LoginResponse instead of boolean#

See checkAuth() returning LoginResponse instead of boolean.

Same applies for checkAuthIncludingServer()

forceRefreshSession() returning LoginResponse instead of TokenResponse#

See checkAuth() returning LoginResponse instead of boolean.

Same return value applies for forceRefreshSession().

Old:

this.oidcSecurityService.forceRefreshSession().subscribe((isAuthenticated) => {});

New:

this.oidcSecurityService.checkAuth().subscribe(({ isAuthenticated }) => {});

isAuthenticated$ returning AuthenticatedResult instead of boolean only#

Old:

this.oidcSecurityService.isAuthenticated$.subscribe((isAuthenticated) => {});

New:

this.oidcSecurityService.isAuthenticated$.subscribe(({ isAuthenticated, allConfigsAuthenticated }) => {});

userData$ returning UserDataResult instead of any only#

Old:

this.oidcSecurityService.userData$.subscribe((userData) => {});

New:

Single Config:

this.oidcSecurityService.userData$.subscribe(({ userData }) => {});

Multiple Configs:

this.oidcSecurityService.userData$.subscribe(({ allUserData }) => {});

authorize(...) has new configId as first parameter#

Because V12 introduces multiple configs, the first parameter is now configId.

Old:

const authOptions = {...}
this.oidcSecurityService.authorize(authOptions)

New:

const authOptions = {...}
const configIdOrNull = ./*...*/;
this.oidcSecurityService.authorize(configIdOrNull, authOptions)

logoffAndRevokeTokens(...) has new configId as first parameter#

Because V12 introduces multiple configs, the first parameter is now configId.

Old:

const authOptions = {...}
this.oidcSecurityService.logoffAndRevokeTokens(authOptions)

New:

const authOptions = {...}
const configIdOrNull = ./*...*/;
this.oidcSecurityService.logoffAndRevokeTokens(configIdOrNull, authOptions)

logoff(...) has new parameters#

Because V12 introduces multiple configs, the first parameter is now configId and the second parameter is AuthOptions.

Old:

logoff(urlHandler?: (url: string) => any) { }

called with

const urlHandler = () => {};
service.logoff(urlHandler);

New:

const authOptions = { urlHandler = () => {}, ...}
const configIdOrNull = ./*...*/;
this.oidcSecurityService.logoff(configIdOrNull, authOptions)

Interface AuthorizationResult changed and renamed to AuthStateResult#

The old interface AuthorizationResult had the following structure:

export interface AuthorizationResult {
authorizationState: AuthorizedState;
validationResult: ValidationResult;
isRenewProcess: boolean;
}

The interface was renamed and the authorizationState: AuthorizedState; was converted into a boolean and renamed.

Old:

export interface AuthorizationResult {
authorizationState: AuthorizedState;
validationResult: ValidationResult;
isRenewProcess: boolean;
}
this.eventService
.registerForEvents()
.pipe(filter((notification) => notification.type === EventTypes.NewAuthorizationResult))
.subscribe((result: OidcClientNotification<AuthorizationResult>) => {
console.log('isAuthenticated', result.value.authorizationState === AuthorizedState.Authorized);
});

New

export interface AuthStateResult {
isAuthenticated: boolean;
validationResult: ValidationResult;
isRenewProcess: boolean;
}
this.eventService
.registerForEvents()
.pipe(filter((notification) => notification.type === EventTypes.NewAuthenticationResult))
.subscribe((result: OidcClientNotification<AuthStateResult>) => {
console.log('isAuthenticated', result.isAuthenticated);
});

NewAuthorizationResult was renamed to NewAuthenticationResult#

The event has changed from NewAuthorizationResult to NewAuthenticationResult

Old:

this.eventService
.registerForEvents()
.pipe(filter((notification) => notification.type === EventTypes.NewAuthorizationResult))
.subscribe((result: OidcClientNotification<AuthorizationResult>) => {});

New:

this.eventService
.registerForEvents()
.pipe(filter((notification) => notification.type === EventTypes.NewAuthenticationResult))
.subscribe((result: OidcClientNotification<AuthStateResult>) => {});

AutoLoginGuard --> AutoLoginAllRoutesGuard and AutoLoginPartialRoutesGuard#

Due to a lot of feedback about the AutoLoginGuard and usage we did not expect in that way we decided to give the AuthGuard a brush and divided it into a AutoLoginAllRoutesGuard when you want to secure your complete app and an AutoLoginPartialRoutesGuard if some of your routes are publicly accessible.

Please refer to the docs about more information.

Old (securing the whole app)

import { AutoLoginGuard } from 'angular-auth-oidc-client';
const appRoutes: Routes = [
{ path: '', pathMatch: 'full', redirectTo: 'home' },
{ path: 'home', component: HomeComponent, canActivate: [AutoLoginGuard] },
{ path: 'protected', component: ProtectedComponent, canActivate: [AutoLoginGuard] },
{ path: 'forbidden', component: ForbiddenComponent, canActivate: [AutoLoginGuard] },
{
path: 'customers',
loadChildren: () => import('./customers/customers.module').then((m) => m.CustomersModule),
canLoad: [AutoLoginGuard],
},
{ path: 'unauthorized', component: UnauthorizedComponent },
];

New (securing the whole app)

import { AutoLoginAllRoutesGuard } from 'angular-auth-oidc-client';
const appRoutes: Routes = [
{ path: '', pathMatch: 'full', redirectTo: 'home' },
{ path: 'home', component: HomeComponent, canActivate: [AutoLoginAllRoutesGuard] },
{ path: 'protected', component: ProtectedComponent, canActivate: [AutoLoginAllRoutesGuard] },
{ path: 'forbidden', component: ForbiddenComponent, canActivate: [AutoLoginAllRoutesGuard] },
{
path: 'customers',
loadChildren: () => import('./customers/customers.module').then((m) => m.CustomersModule),
canLoad: [AutoLoginAllRoutesGuard],
},
{ path: 'unauthorized', component: UnauthorizedComponent },
];

Old (securing parts of the app)

import { AutoLoginGuard } from 'angular-auth-oidc-client';
const appRoutes: Routes = [
{ path: '', pathMatch: 'full', redirectTo: 'home' },
{ path: 'home', component: HomeComponent },
{ path: 'protected', component: ProtectedComponent, canActivate: [AutoLoginGuard] },
{ path: 'forbidden', component: ForbiddenComponent, canActivate: [AutoLoginGuard] },
{
path: 'customers',
loadChildren: () => import('./customers/customers.module').then((m) => m.CustomersModule),
canLoad: [AutoLoginGuard],
},
{ path: 'unauthorized', component: UnauthorizedComponent },
];

New (securing parts of the app)

import { AutoLoginPartialRoutesGuard } from 'angular-auth-oidc-client';
const appRoutes: Routes = [
{ path: '', pathMatch: 'full', redirectTo: 'home' },
{ path: 'home', component: HomeComponent },
{ path: 'protected', component: ProtectedComponent, canActivate: [AutoLoginPartialRoutesGuard] },
{ path: 'forbidden', component: ForbiddenComponent, canActivate: [AutoLoginPartialRoutesGuard] },
{
path: 'customers',
loadChildren: () => import('./customers/customers.module').then((m) => m.CustomersModule),
canLoad: [AutoLoginPartialRoutesGuard],
},
{ path: 'unauthorized', component: UnauthorizedComponent },
];

stsServer --> authority#

Renaming the stsServer to authority. The authority issues tokens. Sometimes this is called secure token service, auth server, identity provider. The authority can also be the issuer but does not have to be.

Old:

export interface OpenIdConfiguration {
stsServer: string;
// ...
}

New:

export interface OpenIdConfiguration {
authority: string;
// ...
}