Skip to content

Auth0 Implementation Plan for REC Verifiable Credentialing Platform

Overview

This document outlines the implementation plan for integrating Auth0 as the identity management solution for the REC Verifiable Credentialing Platform. Auth0 is a flexible, drop-in solution to add authentication and authorization services to applications. It provides a universal authentication & authorization platform for web, mobile, and legacy applications.

Alignment with Current Requirements

Auth0 directly addresses several key authentication and security requirements from the REC Platform specifications:

Requirement How Auth0 Addresses It
OAuth 2.0 / OpenID Connect Auth0 is built on OAuth 2.0 and OpenID Connect standards
Multi-factor Authentication Auth0 provides robust MFA options including SMS, email, authenticator apps, and WebAuthn
Passkey Implementation Auth0 supports WebAuthn/FIDO2 which enables passkey authentication
Security Auth0 provides enterprise-grade security with features like anomaly detection and brute force protection
Audit Logs Auth0 maintains detailed, immutable audit logs of all authentication events

Architecture Integration

System Architecture with Auth0

flowchart TB
    subgraph "Client Layer"
        WebBrowser["Web Browser"]
        MobileApp["Mobile App"]
        AdminDashboard["Admin Dashboard"]
    end

    subgraph "Auth0 Tenant"
        Auth0["Auth0 Authentication"]
        Auth0Rules["Auth0 Rules & Actions"]
        Auth0MFA["Multi-factor Authentication"]
        Auth0Logs["Audit Logs"]
    end

    subgraph "NestJS Application"
        subgraph "Static File Serving"
            ReactApp["React Frontend (Built)"]
        end

        subgraph "API Layer"
            APIController["API Controllers"]
            AuthGuard["Auth Guards"]
        end

        subgraph "Application Services Layer"
            AuthService["Authentication Service"]
            IssuerService["Credential Issuer Service"]
            VerificationService["Credential Verification Service"]
            UserService["User Management Service"]
            AdminService["Admin Service"]
            PaymentService["Payment Processing Service"]
        end
    end

    subgraph "Data Storage Layer"
        PostgreSQL[(PostgreSQL Database)]
    end

    %% Client to Auth0 connections
    WebBrowser --> Auth0
    MobileApp --> Auth0
    AdminDashboard --> Auth0

    %% Auth0 to Application connections
    Auth0 --> ReactApp
    Auth0 --> AuthGuard

    %% API Guards to Services
    AuthGuard --> APIController
    APIController --> AuthService
    APIController --> IssuerService
    APIController --> VerificationService
    APIController --> UserService
    APIController --> AdminService
    APIController --> PaymentService

    %% Services to Database
    AuthService --> PostgreSQL
    IssuerService --> PostgreSQL
    VerificationService --> PostgreSQL
    UserService --> PostgreSQL
    AdminService --> PostgreSQL
    PaymentService --> PostgreSQL

Authentication Flow

sequenceDiagram
    participant User
    participant Frontend as React Frontend
    participant Auth0
    participant Backend as NestJS Backend
    participant DB as Database

    User->>Frontend: Access Application
    Frontend->>Auth0: Redirect to Auth0 Login
    Auth0->>User: Present Login UI
    User->>Auth0: Enter Credentials

    alt MFA Required
        Auth0->>User: Request MFA
        User->>Auth0: Provide MFA
    end

    Auth0->>Auth0: Validate Credentials
    Auth0->>Frontend: Return Access & ID Tokens
    Frontend->>Frontend: Store Tokens

    User->>Frontend: Request Protected Resource
    Frontend->>Backend: API Request with Access Token
    Backend->>Backend: Validate Token
    Backend->>DB: Query Data
    DB->>Backend: Return Data
    Backend->>Frontend: Return Protected Resource
    Frontend->>User: Display Protected Resource

Implementation Details

1. Auth0 Tenant Setup

  1. Create an Auth0 tenant for the REC Platform
  2. Configure domain settings and branding
  3. Set up appropriate connections (database, social, enterprise)
  4. Configure MFA settings, requiring MFA for admin accounts
  5. Set up email templates for verification and password reset

2. Backend Integration (NestJS)

Install Required Packages

cd backend
npm install @nestjs/passport passport passport-jwt jwks-rsa express-jwt

Configure Auth0 Authentication Module

// backend/src/auth/auth.module.ts
import { Module } from '@nestjs/common';
import { PassportModule } from '@nestjs/passport';
import { JwtStrategy } from './jwt.strategy';
import { ConfigModule, ConfigService } from '@nestjs/config';

@Module({
  imports: [
    PassportModule.register({ defaultStrategy: 'jwt' }),
    ConfigModule,
  ],
  providers: [JwtStrategy],
  exports: [PassportModule],
})
export class AuthModule {}

Create JWT Strategy

// backend/src/auth/jwt.strategy.ts
import { Injectable } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { ExtractJwt, Strategy } from 'passport-jwt';
import { passportJwtSecret } from 'jwks-rsa';
import { ConfigService } from '@nestjs/config';

@Injectable()
export class JwtStrategy extends PassportStrategy(Strategy) {
  constructor(configService: ConfigService) {
    super({
      jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
      secretOrKeyProvider: passportJwtSecret({
        cache: true,
        rateLimit: true,
        jwksRequestsPerMinute: 5,
        jwksUri: `https://${configService.get('auth.domain')}/.well-known/jwks.json`,
      }),
      audience: configService.get('auth.audience'),
      issuer: `https://${configService.get('auth.domain')}/`,
      algorithms: ['RS256'],
    });
  }

  async validate(payload: any) {
    // You can add custom validation logic here
    return payload;
  }
}

Create Auth Guard

// backend/src/auth/jwt-auth.guard.ts
import { Injectable } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';

@Injectable()
export class JwtAuthGuard extends AuthGuard('jwt') {}

Create Role Guard for Admin Access

// backend/src/auth/roles.guard.ts
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { Reflector } from '@nestjs/core';

@Injectable()
export class RolesGuard implements CanActivate {
  constructor(private reflector: Reflector) {}

  canActivate(context: ExecutionContext): boolean {
    const requiredRoles = this.reflector.getAllAndOverride<string[]>('roles', [
      context.getHandler(),
      context.getClass(),
    ]);

    if (!requiredRoles) {
      return true;
    }

    const { user } = context.switchToHttp().getRequest();
    return requiredRoles.some((role) => 
      user.permissions?.includes(role) || 
      user['https://rec-platform.com/roles']?.includes(role)
    );
  }
}

Update Configuration

// backend/src/config/configuration.ts
export default () => ({
  // ... existing config
  auth: {
    domain: process.env.AUTH0_DOMAIN,
    audience: process.env.AUTH0_AUDIENCE,
    clientId: process.env.AUTH0_CLIENT_ID,
    clientSecret: process.env.AUTH0_CLIENT_SECRET,
  },
});

Apply Guards to Controllers

// backend/src/admin/admin.controller.ts
import { Controller, Get, UseGuards } from '@nestjs/common';
import { JwtAuthGuard } from '../auth/jwt-auth.guard';
import { RolesGuard } from '../auth/roles.guard';
import { Roles } from '../auth/roles.decorator';

@Controller('admin')
@UseGuards(JwtAuthGuard, RolesGuard)
export class AdminController {
  @Get()
  @Roles(['admin'])
  findAll() {
    return { message: 'This is protected admin data' };
  }
}

3. Frontend Integration (React)

Install Required Packages

cd frontend
npm install @auth0/auth0-react

Configure Auth0 Provider

// frontend/src/index.tsx
import React from 'react';
import ReactDOM from 'react-dom';
import { Auth0Provider } from '@auth0/auth0-react';
import App from './App';

ReactDOM.render(
  <Auth0Provider
    domain={process.env.REACT_APP_AUTH0_DOMAIN || ''}
    clientId={process.env.REACT_APP_AUTH0_CLIENT_ID || ''}
    authorizationParams={{
      redirect_uri: window.location.origin,
      audience: process.env.REACT_APP_AUTH0_AUDIENCE,
    }}
  >
    <App />
  </Auth0Provider>,
  document.getElementById('root')
);

Create Authentication Hook

// frontend/src/hooks/useAuth.ts
import { useAuth0 } from '@auth0/auth0-react';
import { useEffect, useState } from 'react';

export const useAuth = () => {
  const {
    isAuthenticated,
    loginWithRedirect,
    logout,
    getAccessTokenSilently,
    user,
    isLoading,
  } = useAuth0();

  const [token, setToken] = useState<string | null>(null);

  useEffect(() => {
    const getToken = async () => {
      if (isAuthenticated) {
        try {
          const accessToken = await getAccessTokenSilently();
          setToken(accessToken);
        } catch (error) {
          console.error('Error getting token', error);
        }
      }
    };

    getToken();
  }, [isAuthenticated, getAccessTokenSilently]);

  return {
    isAuthenticated,
    isLoading,
    user,
    token,
    login: loginWithRedirect,
    logout: () => logout({ logoutParams: { returnTo: window.location.origin } }),
  };
};

Create Protected Route Component

// frontend/src/components/ProtectedRoute.tsx
import React from 'react';
import { Navigate } from 'react-router-dom';
import { useAuth } from '../hooks/useAuth';

interface ProtectedRouteProps {
  children: React.ReactNode;
  requiredRole?: string;
}

export const ProtectedRoute: React.FC<ProtectedRouteProps> = ({ 
  children, 
  requiredRole 
}) => {
  const { isAuthenticated, isLoading, user } = useAuth();

  if (isLoading) {
    return <div>Loading...</div>;
  }

  if (!isAuthenticated) {
    return <Navigate to="/login" replace />;
  }

  if (requiredRole) {
    const userRoles = user?.['https://rec-platform.com/roles'] || [];
    if (!userRoles.includes(requiredRole)) {
      return <Navigate to="/unauthorized" replace />;
    }
  }

  return <>{children}</>;
};

Create API Service with Auth Token

// frontend/src/services/api.ts
import { useAuth } from '../hooks/useAuth';

export const useApi = () => {
  const { token } = useAuth();

  const apiUrl = process.env.REACT_APP_API_URL || '';

  const fetchWithAuth = async (
    endpoint: string,
    options: RequestInit = {}
  ) => {
    if (!token) {
      throw new Error('No token available');
    }

    const headers = {
      ...options.headers,
      Authorization: `Bearer ${token}`,
      'Content-Type': 'application/json',
    };

    const response = await fetch(`${apiUrl}${endpoint}`, {
      ...options,
      headers,
    });

    if (!response.ok) {
      throw new Error(`API error: ${response.statusText}`);
    }

    return response.json();
  };

  return {
    get: (endpoint: string) => fetchWithAuth(endpoint),
    post: (endpoint: string, data: any) => 
      fetchWithAuth(endpoint, {
        method: 'POST',
        body: JSON.stringify(data),
      }),
    put: (endpoint: string, data: any) => 
      fetchWithAuth(endpoint, {
        method: 'PUT',
        body: JSON.stringify(data),
      }),
    delete: (endpoint: string) => 
      fetchWithAuth(endpoint, {
        method: 'DELETE',
      }),
  };
};

4. Environment Configuration

Backend Environment Variables (.env)

AUTH0_DOMAIN=your-tenant.auth0.com
AUTH0_AUDIENCE=https://api.rec-platform.com
AUTH0_CLIENT_ID=your-backend-client-id
AUTH0_CLIENT_SECRET=your-backend-client-secret

Frontend Environment Variables (.env)

REACT_APP_AUTH0_DOMAIN=your-tenant.auth0.com
REACT_APP_AUTH0_CLIENT_ID=your-frontend-client-id
REACT_APP_AUTH0_AUDIENCE=https://api.rec-platform.com
REACT_APP_API_URL=https://api.rec-platform.com

Auth0 Rules and Actions

1. Add Role Information to Tokens

// Auth0 Rule: Add roles to tokens
function addRolesToTokens(user, context, callback) {
  const namespace = 'https://rec-platform.com';
  const assignedRoles = (context.authorization || {}).roles || [];

  const idTokenClaims = context.idToken || {};
  const accessTokenClaims = context.accessToken || {};

  idTokenClaims[`${namespace}/roles`] = assignedRoles;
  accessTokenClaims[`${namespace}/roles`] = assignedRoles;

  context.idToken = idTokenClaims;
  context.accessToken = accessTokenClaims;

  callback(null, user, context);
}

2. Enforce MFA for Admin Users

// Auth0 Rule: Enforce MFA for admin users
function enforceMultifactorForAdmins(user, context, callback) {
  const adminRoles = ['admin'];
  const userRoles = (context.authorization || {}).roles || [];

  const isAdmin = userRoles.some(role => adminRoles.includes(role));

  if (isAdmin && !context.multifactor.provider) {
    context.multifactor = {
      provider: 'any',
      allowRememberBrowser: false
    };
  }

  callback(null, user, context);
}

Passkey Implementation

Auth0 supports WebAuthn/FIDO2 which enables passkey authentication. Here's how to implement it:

1. Enable WebAuthn in Auth0 Dashboard

  1. Navigate to Authentication > Multi-factor Auth
  2. Enable WebAuthn (Platform/Cross-Platform)
  3. Configure settings as needed

2. Frontend Implementation

// frontend/src/components/PasskeyButton.tsx
import React from 'react';
import { useAuth0 } from '@auth0/auth0-react';

export const PasskeyButton: React.FC = () => {
  const { loginWithRedirect } = useAuth0();

  const loginWithPasskey = () => {
    loginWithRedirect({
      authorizationParams: {
        prompt: 'login',
        acr_values: 'http://schemas.openid.net/pape/policies/2007/06/multi-factor http://schemas.openid.net/pape/methods/2007/01/webauthn'
      }
    });
  };

  return (
    <button onClick={loginWithPasskey}>
      Sign in with Passkey
    </button>
  );
};

Migration Strategy

If the platform already has existing users, a migration strategy will be needed:

  1. Custom Database Connection: Set up a custom database connection in Auth0 that points to the existing user database
  2. Migration Script: Implement a migration script that transfers users to Auth0 when they log in
  3. Bulk Import: For immediate migration, use Auth0's bulk user import feature

Security Considerations

  1. Token Storage: Store tokens securely in browser memory, not localStorage
  2. PKCE Flow: Use PKCE (Proof Key for Code Exchange) for added security
  3. Token Expiration: Set appropriate token expiration times
  4. Scope Management: Limit token scopes to only what's needed
  5. Regular Audits: Regularly review Auth0 logs for suspicious activity

Implementation Timeline

Phase Tasks Timeline
Planning & Setup Create Auth0 tenant, configure connections Week 1
Backend Integration Implement JWT validation, guards, and roles Week 2
Frontend Integration Implement Auth0 provider, hooks, and protected routes Week 3
Testing & Refinement Test authentication flows, role-based access Week 4
Production Deployment Deploy to production, monitor for issues Week 5

Conclusion

Implementing Auth0 for the REC Verifiable Credentialing Platform provides a robust, standards-compliant authentication solution that meets all the specified requirements. The implementation plan outlined in this document provides a clear path forward for integrating Auth0 with the existing NestJS and React architecture.

Auth0's support for OAuth 2.0/OpenID Connect, multi-factor authentication, and WebAuthn (passkeys) makes it an ideal choice for the platform's authentication needs. The detailed implementation steps, code examples, and configuration guidelines provided in this document should enable a smooth integration process.