Skip to content

Authentication Module

The Suite Framework includes an AuthenticationModule which has support for OpenID Connect through a third party lib angular-simple-oidc

Before configuring auth for your UI, ensure you have followed the Identity Data Seeding to provide OIDC clients for your BFF and UI.

Using the AuthenticationModule

Authentication is configured at the application level, instead of module / lib level.

In your app's root module, declare the configuration object for authentication:

TypeScript
1
2
3
4
5
6
7
import { AuthenticationConfiguration } from '@itsynch/suite/authentication';
// ..
const authConfig: AuthenticationConfiguration = {
    clientId: 'admin-center',
    clientSecret: 'F5646584-202D-49AD-8CBF-69EED6D2F57B',
    scope: 'openid profile offline_access'
};

Note

It is OK for this to be hard-codded: The client id does not change between environments. Adding scopes means changing code to consume the endpoints of that scopes, and we will not really use this since we will only use our BFF. The secret is not really a secret since it is exposed in the UI, but our backend, IdentityServer4 actually, requires it.

Then we need to use our configuration when importing the AuthenticationModule:

TypeScript
import {
    AuthenticationConfiguration,
    SuiteAuthenticationModule
} from '@itsynch/suite/authentication';
//..

@NgModule({
    imports: [
        SuiteApplicationModule.forRoot(AdminCenterConfiguration),
        AdminCenterNgrxModule,
        BrowserAnimationsModule,
        BrowserModule,
        SuiteAuthenticationModule.forRoot(authConfig),
    ]
})
//..

Once we have done this, we have added support for authentication to our app. When developing Suite Apps, authentication is evaluated at the routing level. Meaning that, before we route to certain view, we validate that we can access the route and then do the actual routing.

Currently, none of our routes require authentication, hence nothing is being restricted.

Using the AuthGuard

To make a route require authentication, we need to add the AuthGuard to it.

If our app requires authentication for all views, which is the case of most (all?) LTS apps, we can create an empty route with the AuthGuard, and have all our routes as children:

TypeScript
const applicationRoutes: Routes = [
    {
        path: '',
        canActivate: [AuthGuard],
        children: [
            createAdminCenterUsersRoute('users'),
            createInspectionsTemplateRoute('templates')
            //...
        ]
    }
];

Creating effects when the user logs in

If we want to execute code when a user logs in, we need to do so using effects, as usual.

The AuthenticationModule exposes a userLoggedIn action that we can listen to wait for the login process to be done.

TypeScript
import { userLoggedIn } from '@itsynch/suite/authentication';

// ..

init$ = createEffect(() =>
    this.actions$.pipe(
        ofType(userLoggedIn),
        tap(({ decodedIdentityToken }) => console.info(`${decodedIdentityToken.sub} has logged in`))
        fetch(/* .. */)
    )
    );

You can also use the AuthService which includes observables for the current user id. This is more useful for feature components.

Creating effects when the user's profile is ready

The user's profile is the result of executing the me query. Currently it returns user information and it's position, if any.

TypeScript
import { userProfileObtained } from '@itsynch/suite/user-profile';

// ..

init$ = createEffect(() =>
    this.actions$.pipe(
        ofType(userProfileObtained),
        tap(({ userProfile }) => console.info(userProfile))
        fetch(/* .. */)
    )
    );

You can also use the UserProfileService to get an observable for using in feature components.