Files
motovaultpro/mvp-platform-services/tenants/AUTH0-CONFIG.md
Eric Gullickson a052040e3a Initial Commit
2025-09-17 16:09:15 -05:00

9.0 KiB

Auth0 Multi-Tenant Configuration Guide

This document provides step-by-step instructions for configuring Auth0 for the multi-tenant MotoVaultPro platform.

Overview

The multi-tenant architecture requires:

  • Landing Page: motovaultpro.com - Entry point with tenant selection
  • Admin Tenant: admin.motovaultpro.com - Admin access to all tenants
  • Regular Tenants: {tenant-id}.motovaultpro.com - Isolated tenant access
  • Signup Workflow: Tenant-specific signup with admin approval

Auth0 Application Configuration

1. Application Settings

Application Type: Single Page Application (SPA)

Allowed Callback URLs:

# Development URLs
http://localhost:3002/callback
http://admin.motovaultpro.local/callback
http://demo-tenant.motovaultpro.local/callback

# Production URLs  
https://motovaultpro.com/callback
https://admin.motovaultpro.com/callback
https://demo-tenant.motovaultpro.com/callback

# Add additional tenant subdomains as needed:
https://{tenant-id}.motovaultpro.com/callback

Allowed Logout URLs:

# Development
http://localhost:3002
http://admin.motovaultpro.local
http://demo-tenant.motovaultpro.local

# Production
https://motovaultpro.com
https://admin.motovaultpro.com  
https://demo-tenant.motovaultpro.com
https://{tenant-id}.motovaultpro.com

Allowed Web Origins:

# Development
http://localhost:3002
http://admin.motovaultpro.local:3000
http://demo-tenant.motovaultpro.local:3000

# Production
https://motovaultpro.com
https://admin.motovaultpro.com
https://demo-tenant.motovaultpro.com  
https://{tenant-id}.motovaultpro.com

2. JWT Configuration

JWT Signature Algorithm: RS256

OIDC Conformant: Enabled

3. Advanced Settings

Grant Types:

  • Authorization Code
  • Refresh Token
  • Implicit (for development only)

Auth0 Rules Configuration

Rule 1: Add Tenant Context to JWT

Create a new Rule in Auth0 Dashboard > Auth Pipeline > Rules:

function addTenantContext(user, context, callback) {
  const namespace = 'https://motovaultpro.com/';
  
  // Extract tenant_id from user metadata (set during signup)
  let tenantId = user.user_metadata && user.user_metadata.tenant_id;
  
  // For existing users without tenant metadata, default to admin
  if (!tenantId) {
    tenantId = 'admin';
    // Optionally update user metadata
    user.user_metadata = user.user_metadata || {};
    user.user_metadata.tenant_id = tenantId;
  }
  
  // Check signup status for non-admin tenants
  const signupStatus = user.user_metadata && user.user_metadata.signup_status;
  
  if (tenantId !== 'admin' && signupStatus !== 'approved') {
    // Block login for unapproved users
    return callback(new UnauthorizedError('Account pending approval'));
  }
  
  // Add tenant context to tokens
  context.idToken[namespace + 'tenant_id'] = tenantId;
  context.accessToken[namespace + 'tenant_id'] = tenantId;
  context.idToken[namespace + 'signup_status'] = signupStatus || 'approved';
  
  callback(null, user, context);
}

Rule 2: Tenant-Specific User Metadata

function setTenantMetadata(user, context, callback) {
  const namespace = 'https://motovaultpro.com/';
  
  // If this is a signup and connection is Username-Password-Authentication
  if (context.stats.loginsCount === 1 && context.connection === 'Username-Password-Authentication') {
    
    // Extract tenant from redirect_uri or state parameter
    const redirectUri = context.request.query.redirect_uri || '';
    const tenantMatch = redirectUri.match(/([a-z0-9-]+)\.motovaultpro\.(com|local)/);
    
    if (tenantMatch) {
      const tenantId = tenantMatch[1];
      
      // Set initial user metadata
      user.user_metadata = user.user_metadata || {};
      user.user_metadata.tenant_id = tenantId;
      
      // Set signup status (pending for regular tenants, approved for admin)
      user.user_metadata.signup_status = tenantId === 'admin' ? 'approved' : 'pending';
      
      // Update user metadata in Auth0
      auth0.users.updateUserMetadata(user.user_id, user.user_metadata);
    }
  }
  
  callback(null, user, context);
}

Tenant Signup Flow Configuration

1. Signup URLs

Tenant-Specific Signup:

https://motovaultpro.com/signup/{tenant-id}

Process:

  1. User visits tenant-specific signup URL
  2. Landing page validates tenant exists
  3. Redirects to Auth0 with tenant context
  4. Auth0 Rule sets tenant_id in user metadata
  5. User account created with status="pending"
  6. Tenant admin receives notification
  7. Admin approves/rejects via tenant management API

2. Auth0 Hosted Login Customization

Add custom CSS and JavaScript to Auth0 Universal Login to support tenant context:

Custom CSS (Dashboard > Universal Login > Advanced Options):

.tenant-signup-info {
  background: #f8f9fa;
  padding: 15px;
  border-radius: 5px;
  margin-bottom: 20px;
  border-left: 4px solid #007bff;
}

Custom JavaScript:

// Extract tenant from URL parameters
const urlParams = new URLSearchParams(window.location.search);
const redirectUri = urlParams.get('redirect_uri') || '';
const tenantMatch = redirectUri.match(/([a-z0-9-]+)\.motovaultpro\.(com|local)/);

if (tenantMatch && tenantMatch[1] !== 'admin') {
  const tenantName = tenantMatch[1].replace('-', ' ').toUpperCase();
  
  // Add tenant information to signup form
  const container = document.querySelector('.auth0-lock-header');
  if (container) {
    const info = document.createElement('div');
    info.className = 'tenant-signup-info';
    info.innerHTML = `
      <strong>Signing up for: ${tenantName}</strong><br>
      <small>Your account will require admin approval before you can access the system.</small>
    `;
    container.appendChild(info);
  }
}

JWT Token Format

After successful authentication, JWT tokens will include:

ID Token Claims:

{
  "sub": "auth0|user-123",
  "email": "user@example.com",
  "https://motovaultpro.com/tenant_id": "demo-tenant",
  "https://motovaultpro.com/signup_status": "approved",
  "iat": 1699123456,
  "exp": 1699127056
}

Access Token Claims:

{
  "sub": "auth0|user-123", 
  "https://motovaultpro.com/tenant_id": "demo-tenant",
  "scope": "openid profile email",
  "iat": 1699123456,
  "exp": 1699127056
}

Backend JWT Validation

Services should validate JWT tokens and extract tenant context:

// Example JWT validation middleware
import jwt from 'jsonwebtoken';
import jwksClient from 'jwks-rsa';

const client = jwksClient({
  jwksUri: `https://${AUTH0_DOMAIN}/.well-known/jwks.json`
});

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

export const validateJWT = (token: string): Promise<any> => {
  return new Promise((resolve, reject) => {
    jwt.verify(token, getKey, {
      audience: process.env.AUTH0_AUDIENCE,
      issuer: `https://${process.env.AUTH0_DOMAIN}/`,
      algorithms: ['RS256']
    }, (err, decoded) => {
      if (err) return reject(err);
      resolve(decoded);
    });
  });
};

// Extract tenant from validated JWT
export const getTenantFromToken = (decodedToken: any): string => {
  return decodedToken['https://motovaultpro.com/tenant_id'] || 'admin';
};

Environment Variables

Configure the following environment variables for each service:

Platform Services:

AUTH0_DOMAIN=your-domain.auth0.com
AUTH0_AUDIENCE=https://api.motovaultpro.com

Landing Page Service:

VITE_AUTH0_DOMAIN=your-domain.auth0.com
VITE_AUTH0_CLIENT_ID=your-client-id
VITE_TENANTS_API_URL=http://mvp-platform-tenants:8000

Admin/Tenant Services:

REACT_APP_AUTH0_DOMAIN=your-domain.auth0.com  
REACT_APP_AUTH0_CLIENT_ID=your-client-id
REACT_APP_AUTH0_AUDIENCE=https://api.motovaultpro.com
REACT_APP_TENANT_ID=admin  # or specific tenant ID

Testing the Configuration

1. Test Admin Login

# Visit admin tenant
open http://admin.motovaultpro.local

# Should redirect to Auth0, login, then return to admin app

2. Test Tenant Signup

# Visit tenant signup
open http://motovaultpro.local/signup/demo-tenant

# Complete signup, verify pending status
curl -H "Authorization: Bearer admin-token" \
  http://localhost:8001/api/v1/signups

3. Test Approval Workflow

# Approve signup
curl -X PUT -H "Authorization: Bearer admin-token" \
  http://localhost:8001/api/v1/signups/1/approve

# User should now be able to login to tenant
open http://demo-tenant.motovaultpro.local

Production Deployment Notes

  1. SSL Certificates: Ensure wildcard SSL certificate for *.motovaultpro.com
  2. DNS Configuration: Set up wildcard DNS or individual A records per tenant
  3. Auth0 Environment: Use production Auth0 tenant with proper security settings
  4. Rate Limiting: Configure Auth0 rate limiting for signup endpoints
  5. Monitoring: Set up Auth0 logs monitoring for failed login attempts

This configuration provides a secure, scalable multi-tenant authentication system with proper tenant isolation and admin approval workflows.