Sample for Angular

This sample is ideal for developers looking to explore both the Angular and the OLAF SDK in a real-world scenario


Install OLAF SDK

npm install @olafsh/olaf-sdk-js

Create and configure auth service

You need to create an auth.service.ts file to manage user authentication functionalities, including login and session management. This service centralizes authentication logic, making it modular and reusable across your application.

// auth.service.ts
import {Injectable} from "@angular/core";
import {environment} from "../environments/environment";
import {BehaviorSubject} from "rxjs";
import OLAFSDK from "@olafsh/olaf-sdk-js";

@Injectable({
    providedIn: "root",
})
export class AuthService {
    private OLAFSDK: any;

    isAuthenticated$$: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
    accessToken$$: BehaviorSubject<string> = new BehaviorSubject<string>("");
    user$$: BehaviorSubject<any | undefined> = new BehaviorSubject<any | undefined>(undefined);

    constructor() {
        // initialize OLAF SDK
        this.OLAFSDK = new OLAFSDK(environment.OLAF_PUBLIC_ENDPOINT);
    }

    get _isAuthenticated(): boolean {
        return this.isAuthenticated$$.value;
    }

    get _user(): any {
        return this.user$$.value;
    }

    /**
     * Fetch config
     */
    public fetchConfig() {
        return this.OLAFSDK.fetchConfig();
    }

    /**
     * Get config from localstorage
     */
    public config() {
        return this.OLAFSDK.config;
    }

    /**
     * Get access token from localstorage once user is logged in
     */
    public accessToken() {
        return this.OLAFSDK.accessToken;
    }

    /**
     * Check if user is authenticated
     */
    public async isAuthenticated() {
        return await this.OLAFSDK.isAuthenticated;
    }

    /**
     * Build authorize url and redirect user to login page
     */
    public async loginWithRedirect() {
        await this.OLAFSDK.loginWithRedirect();
    }

    /**
     * Handle redirect callback URL
     */
    public async handleRedirectCallback() {
        await this.OLAFSDK.handleRedirectCallback();
    }

    /**
     * Logout user
     */
    public async logout() {
        await this.OLAFSDK.logout();
    }

    /**
     * Retrieves the data of the logged-in user
     */
    public async me() {
        return await this.OLAFSDK.me();
    }

    /**
     * Set is authenticated
     */
    setIsAuthenticated(isAuthenticated: boolean) {
        this.isAuthenticated$$.next(isAuthenticated);
    }

    /**
     * Set access token
     */
    setAccessToken() {
        this.accessToken$$.next(this.OLAFSDK.accessToken);
    }

    /**
     * Set user
     *
     * @param user
     */
    setUser(user: any) {
        this.user$$.next(user);
    }
}

export function initializeApp(authService: AuthService) {
    return async () => {
        try {
            // fetch app config
            await authService.fetchConfig();
            // check if user is authenticated
            const isAuthenticated = await authService.isAuthenticated();
            authService.setIsAuthenticated(isAuthenticated);
            if (isAuthenticated) {
                // set access token
                authService.setAccessToken();
                // retrieves the data of the logged-in user
                await authService.me().then((user: any) => {
                    authService.setUser(user);
                });
            } else {
                console.log("Authentication failed");
            }
        } catch (err) {
            console.error("Error during configuration", err);
        }
    };
}

To ensure the authentication service is initialized before your Angular application starts, add a provider in the app.config.ts file. This leverages Angular's dependency injection system, allowing authentication logic to run before the app fully initializes.

// app.config.ts
import {AuthService, initializeApp} from "./auth.service";

export const appConfig: ApplicationConfig = {
    providers: [
        ...
        {
            provide: APP_INITIALIZER,
            useFactory: initializeApp,
            multi: true,
            deps: [AuthService],
        }
    ]
};

Add login to your application

Now that you have configured your application and the OLAF SDK, you need to implement login for your project. Use the SDK’s loginWithRedirect() method from the AuthService class to redirect users to the OLAF Login page for authentication. After successful login, users will be redirected back to your application and the callback URL you set up earlier.

// login.component.ts
import {Component} from "@angular/core";
import {AuthService} from "../auth.service";

@Component({
    selector: "app-login-button",
    standalone: true,
    imports: [],
    templateUrl: "./login-button.component.html",
    styleUrl: "./login-button.component.scss"
})
export class LoginButtonComponent {
    constructor(private authService: AuthService) {
    }

    async login() {
        await this.authService.loginWithRedirect();
    }
}

Add logout to your application

Users who log into your project will also require an option to log out. The SDK includes a logout() method in the AuthService class for this purpose. Upon logging out, users will be signed out of all active sessions. You can also set a redirect URL to control where they are taken after the logout process.

// logout.component.ts
import {Component} from "@angular/core";
import {AuthService} from "../auth.service";

@Component({
    selector: "app-logout-button",
    standalone: true,
    imports: [],
    templateUrl: "./logout-button.component.html",
    styleUrl: "./logout-button.component.scss"
})
export class LogoutButtonComponent {
    constructor(private authService: AuthService) {
    }

    async logout() {
        await this.authService.logout().then(() => {
            window.location.href = "/";
        });
    }
}

Add callback URL handler to your application

A callback URL is the URL in your application to which OLAF redirects users after authentication. If this is not set, users will not be returned to your application after logging in.

// authorize.component.ts
import {Component} from "@angular/core";
import {AuthService} from "../auth.service";

@Component({
    selector: "app-authorize",
    standalone: true,
    imports: [],
    templateUrl: "./authorize.component.html",
    styleUrl: "./authorize.component.scss"
})
export class AuthorizeComponent {
    constructor(private authService: AuthService) {
        this.authorize().then(() => {
            window.location.href = "/";
        });
    }

    async authorize() {
        await this.authService.handleRedirectCallback()
            .catch((err) => {
                console.log(err);
            });
    }
}

You need to create a callback route in your application, which can be named as you wish, such as callback or authorize. This route will handle redirection from OLAF after user authentication.

// app.routes.ts
import {Routes} from "@angular/router";
import {AuthorizeComponent} from "./authorize/authorize.component";

export const routes: Routes = [
    ...
    {
        path: "authorize",
        component: AuthorizeComponent,
    },
];

Add user profile to your application

Now that users can log in and log out, you’ll likely want to retrieve their profile information. This allows you to personalize the user interface by displaying the logged-in user’s name, for example.

The OLAF SDK provides user information via the user method in the AuthService class. Since this observable contains sensitive identity information, its availability is tied to the user's authentication status.

// profile.component.ts
import {Component} from "@angular/core";
import {AuthService} from "../auth.service";

@Component({
    selector: "app-profile",
    standalone: true,
    imports: [],
    templateUrl: "./profile.component.html",
    styleUrl: "./profile.component.scss"
})
export class ProfileComponent {
    user: any;

    constructor(private authService: AuthService) {
        this.user = this.authService.user;
    }
}

Add protected route to your application

To add a protected route to your application, implement an authentication guard auth.guard.ts that restricts access to certain paths, such as a dashboard

// auth.guard.ts
import {inject, Injectable} from "@angular/core";
import {CanActivateFn, Router} from "@angular/router";
import {AuthService} from "./auth.service";

@Injectable({
    providedIn: "root",
})
export class AuthGuard {
    async canActivate(router: Router, authService: AuthService): Promise<any> {
        const _isAuthenticated = await authService.isAuthenticated();
        if (_isAuthenticated) {
            return true;
        }
        return router.parseUrl("/");
    }
}

export const CanActivate: CanActivateFn = () => {
    return inject(AuthGuard).canActivate(inject(Router), inject(AuthService));
};

In your routing configuration, apply the auth guard to the desired route, ensuring that only authenticated users can access it.

// app.routes.ts

import {Routes} from "@angular/router";
import {DashboardComponent} from "./dashboard/dashboard.component";
import {CanActivate} from "./auth.guard";

export const routes: Routes = [
    ...
    {
        path: "dashboard",
        component: DashboardComponent,
        canActivate: [CanActivate],
    },
];

Download Sample app

Download the sample app here to see a functional implementation of OLAF user authentication, including login, logout, and protected routes.