How to Integrate Fabrixly-IDS with Angular and Node.js

This guide explains how to secure an Angular frontend application and a Node.js / Express backend using Fabrixly-IDS OIDC authentication.


๐Ÿ—๏ธ Architecture Overview

  1. Frontend (Angular): Uses the industry-standard angular-oauth2-oidc package to trigger PKCE redirects and store tokens in sessionStorage.
  2. Identity Server (Fabrixly-IDS): Standard OIDC authentication portal.
  3. Backend (Node.js): Validates incoming tokens using JSON Web Key Sets (JWKS).

Part A: Frontend Setup (Angular)

1. Install Dependencies

npm install angular-oauth2-oidc --save

2. Configure Angular OAuth Module

Configure the authentication provider in your src/app/auth.config.ts configuration file:

import { AuthConfig } from 'angular-oauth2-oidc';

export const authCodeFlowConfig: AuthConfig = {
  issuer: 'https://ids.fabrixly.com/oidc',
  redirectUri: window.location.origin + '/index.html',
  clientId: 'your-angular-client-id', // Registered in Admin Console
  responseType: 'code',
  scope: 'openid profile email offline_access',
  showDebugInformation: true, // Set to false in production
  useSilentRefresh: true,
};

Import and configure the module in src/app/app.config.ts:

import { ApplicationConfig, importProvidersFrom } from '@angular/core';
import { provideRouter } from '@angular/router';
import { HttpClientModule } from '@angular/common/http';
import { OAuthModule } from 'angular-oauth2-oidc';
import { routes } from './app.routes';

export const appConfig: ApplicationConfig = {
  providers: [
    provideRouter(routes),
    importProvidersFrom(
      HttpClientModule,
      OAuthModule.forRoot({
        resourceServer: {
          allowedUrls: ['http://localhost:3000/api'], // Automatically attaches access token
          sendAccessToken: true
        }
      })
    )
  ]
};

3. Implement Auth Logic in Component

Create src/app/app.component.ts:

import { Component } from '@angular/core';
import { OAuthService } from 'angular-oauth2-oidc';
import { authCodeFlowConfig } from './auth.config';
import { HttpClient } from '@angular/common/http';

@Component({
  selector: 'app-root',
  template: `
    <div style="padding: 40px;">
      <h1>Angular + Fabrixly-IDS ๐Ÿ›ก๏ธ</h1>
      
      <div *ngIf="!isAuthenticated()">
        <button (click)="login()">Sign In with Fabrixly</button>
      </div>

      <div *ngIf="isAuthenticated()">
        <p>Welcome, {{ getGivenName() }}!</p>
        <button (click)="logout()">Log Out</button>
        <hr />
        <button (click)="callBackend()">Call Protected API</button>
        <p *ngIf="backendResponse">Response: <strong>{{ backendResponse }}</strong></p>
      </div>
    </div>
  `
})
export class AppComponent {
  backendResponse = '';

  constructor(private oauthService: OAuthService, private http: HttpClient) {
    this.oauthService.configure(authCodeFlowConfig);
    this.oauthService.loadDiscoveryDocumentAndTryLogin();
  }

  login() {
    this.oauthService.initLoginFlow();
  }

  logout() {
    this.oauthService.logOut();
  }

  isAuthenticated(): boolean {
    return this.oauthService.hasValidAccessToken();
  }

  getGivenName(): string {
    const claims: any = this.oauthService.getIdentityClaims();
    return claims ? claims.name : 'User';
  }

  callBackend() {
    this.http.get<any>('http://localhost:3000/api/protected').subscribe({
      next: (res) => this.backendResponse = res.message,
      error: (err) => this.backendResponse = 'Failed to load protected resource'
    });
  }
}

Part B: Backend Setup (Node.js + Express)

The backend authenticates incoming REST requests by parsing and checking the cryptographic signatures of JWT tokens issued by Fabrixly-IDS.

1. Install Dependencies

npm install express cors jsonwebtoken jwks-rsa

2. Implement JWT Validation Middleware

Create server.js:

const express = require('express');
const cors = require('cors');
const jwt = require('jsonwebtoken');
const jwksClient = require('jwks-rsa');

const app = express();
app.use(cors());
app.use(express.json());

const IDS_ISSUER = "https://ids.fabrixly.com/oidc";

const client = jwksClient({
  jwksUri: `${IDS_ISSUER}/jwks`,
  cache: true,
  rateLimit: true
});

function getKey(header, callback) {
  client.getSigningKey(header.kid, (err, key) => {
    if (err) return callback(err);
    const signingKey = key.getPublicKey();
    callback(null, signingKey);
  });
}

const requireAuth = (req, res, next) => {
  const authHeader = req.headers.authorization;
  if (!authHeader || !authHeader.startsWith("Bearer ")) {
    return res.status(401).json({ error: "Missing authorization token" });
  }

  const token = authHeader.split(" ")[1];

  jwt.verify(token, getKey, {
    issuer: IDS_ISSUER,
    algorithms: ["RS256"]
  }, (err, decoded) => {
    if (err) {
      return res.status(403).json({ error: "Token validation failed: " + err.message });
    }
    req.user = decoded;
    next();
  });
};

app.get("/api/protected", requireAuth, (req, res) => {
  res.json({
    message: `Greetings from Node.js! Your user ID is ${req.user.sub}.`
  });
});

app.listen(3000, () => console.log("Backend running on http://localhost:3000"));

Part C: Registering the Client in Admin Console

  1. Open your Fabrixly-IDS Admin Console -> navigate to Clients.
  2. Click Create Client:
    • Client Name: Angular SPA
    • Grant Types: authorization_code, refresh_token
    • Response Types: code
    • Redirect URIs: http://localhost:4200/index.html (Angular local dev environment)
    • Token Endpoint Auth Method: none (required for SPA clients)
  3. Save the changes. You are ready to run and test!

Subscribe to The Fabrixly Blog

Donโ€™t miss out on the latest issues. Sign up now to get access to the library of members-only issues.
jamie@example.com
Subscribe