RegisterLogin
DocsPricing
RegisterLogin
  • Getting Started
  • Introduction
  • Quick Start
  • SDKs
  • React
  • TypeScript
  • Next.js
  • Express
  • NestJS
  • Python
  • API Reference
  • Support and Resources
  • FAQ
  • Contact Support

AuthSafe

Product

HighlightFeatureIntegrationPricingFAQ

Company

AboutBlogContactSitemap

Developer

DashboardDocumentation

Legal

Terms & ConditionsPrivacyComplianceShippingCancellation

© 2026 AuthSafe. All rights reserved.

We value your privacy

This website uses cookies for anonymous analytics to help us improve your experience. No personal information is stored or shared. You can allow or reject analytics tracking at any time. See our Privacy Policy.

We use cookies for anonymous analytics. No personal info is stored. See our Privacy Policy.

Middleware

Express middleware for authentication, authorization, and scope-based access control.

Overview

AuthSafe provides middleware functions for protecting routes and managing authentication state in Express applications:
  1. initAuthSafe() - Initialize global configuration
  2. requireAuth() - Require authentication
  3. optionalAuth() - Optional authentication
  4. requireScope() - Require specific scopes
  5. requireAnyScope() - Require any of specified scopes

initAuthSafe()

Initialize AuthSafe with global configuration. Call this once during app setup.
function initAuthSafe(config: AuthSafeConfig): void;

Usage

import { initAuthSafe } from 'authsafe-express';

initAuthSafe({
  clientId: process.env.AUTHSAFE_CLIENT_ID!,
  clientSecret: process.env.AUTHSAFE_CLIENT_SECRET!,
  domain: process.env.AUTHSAFE_DOMAIN!,
  redirectUri: `${process.env.APP_URL}/auth/callback`,
});
Call Before Middleware
initAuthSafe() must be called before using any authentication middleware.

requireAuth()

Middleware that requires authentication. Blocks requests if user is not authenticated.
function requireAuth(options?: {
  autoRefresh?: boolean;
  onUnauthorized?: (req: Request, res: Response) => void;
}): RequestHandler;

Parameters

OptionTypeDefaultDescription
autoRefreshbooleanfalseAutomatically refresh expired tokens
onUnauthorizedfunction-Custom handler for unauthorized requests

Basic Usage

import { requireAuth } from 'authsafe-express';

app.get('/dashboard', requireAuth(), (req, res) => {
  res.json({
    message: `Welcome ${req.auth.email}`,
    user: req.auth,
  });
});

With Auto Refresh

app.get('/profile', requireAuth({ autoRefresh: true }), (req, res) => {
  res.json({ user: req.auth });
});

Custom Unauthorized Handler

app.get(
  '/dashboard',
  requireAuth({
    onUnauthorized: (req, res) => {
      res.redirect('/login');
    },
  }),
  (req, res) => {
    res.json({ user: req.auth });
  },
);

TypeScript Usage

import type { AuthenticatedRequest } from 'authsafe-express';

app.get('/profile', requireAuth(), (req: AuthenticatedRequest, res) => {
  // req.auth is fully typed
  const { userId, email, scopes, organizationId } = req.auth;

  res.json({ userId, email, scopes, organizationId });
});

optionalAuth()

Middleware that optionally attaches authentication session. Does not block if user is not authenticated.
function optionalAuth(options?: { autoRefresh?: boolean }): RequestHandler;

Usage

import { optionalAuth } from 'authsafe-express';

app.get('/home', optionalAuth(), (req, res) => {
  if (req.auth) {
    res.json({ message: `Welcome back, ${req.auth.email}` });
  } else {
    res.json({ message: 'Welcome, guest!' });
  }
});

Conditional Rendering

app.get('/blog', optionalAuth(), (req, res) => {
  const posts = getPosts();

  if (req.auth) {
    // Include private posts for authenticated users
    const privatePosts = getPrivatePosts(req.auth.userId);
    res.json({ posts: [...posts, ...privatePosts] });
  } else {
    res.json({ posts });
  }
});

requireScope()

Middleware to require specific scopes. Must be used after requireAuth().
function requireScope(...scopes: string[]): RequestHandler;

Usage

import { requireAuth, requireScope } from 'authsafe-express';

app.delete(
  '/admin/users/:id',
  requireAuth(),
  requireScope('admin:delete'),
  (req, res) => {
    res.json({ message: 'User deleted' });
  },
);

Multiple Scopes

All specified scopes must be present:
app.post(
  '/admin/settings',
  requireAuth(),
  requireScope('admin:read', 'admin:write'),
  (req, res) => {
    res.json({ message: 'Settings updated' });
  },
);

Error Response

If scopes are missing, returns 403 with:
{
  "error": "forbidden",
  "message": "Insufficient permissions",
  "required_scopes": ["admin:delete"]
}

requireAnyScope()

Middleware to require any of the specified scopes. Must be used after requireAuth().
function requireAnyScope(...scopes: string[]): RequestHandler;

Usage

import { requireAuth, requireAnyScope } from 'authsafe-express';

app.get(
  '/reports',
  requireAuth(),
  requireAnyScope('reports:read', 'admin:read'),
  (req, res) => {
    res.json({ reports: getReports() });
  },
);

Multiple Alternative Scopes

User needs at least one of the specified scopes:
app.post(
  '/content',
  requireAuth(),
  requireAnyScope('content:create', 'editor', 'admin'),
  (req, res) => {
    res.json({ message: 'Content created' });
  },
);

AuthSession Interface

The req.auth object attached by middleware:
interface AuthSession {
  /** User ID (extracted from 'sub' claim) */
  userId: string;

  /** User email */
  email: string;

  /** User full name */
  name?: string;

  /** Email verified status */
  emailVerified: boolean;

  /** Organization ID */
  organizationId: string;

  /** Token scopes */
  scopes: string[];

  /** Issued at timestamp (seconds) */
  issuedAt: number;

  /** Expires at timestamp (seconds) */
  expiresAt: number;
}

Complete Examples

Protected API Routes

import express from 'express';
import { requireAuth, requireScope, requireAnyScope } from 'authsafe-express';

const app = express();

// Public endpoint
app.get('/api/public', (req, res) => {
  res.json({ message: 'Public data' });
});

// Authenticated endpoint
app.get('/api/user/profile', requireAuth(), (req, res) => {
  res.json({ user: req.auth });
});

// Scope-protected endpoint
app.post(
  '/api/admin/users',
  requireAuth(),
  requireScope('admin:create'),
  (req, res) => {
    res.json({ message: 'User created' });
  },
);

// Multiple scope options
app.get(
  '/api/analytics',
  requireAuth(),
  requireAnyScope('analytics:read', 'admin:read'),
  (req, res) => {
    res.json({ analytics: getAnalytics() });
  },
);

Role-Based Access Control

// Middleware to check user roles
function requireRole(...roles: string[]) {
  return (req: any, res: any, next: any) => {
    if (!req.auth) {
      return res.status(401).json({ error: 'Unauthorized' });
    }

    const hasRole = roles.some((role) =>
      req.auth.scopes.includes(`role:${role}`),
    );

    if (!hasRole) {
      return res.status(403).json({
        error: 'Forbidden',
        required_roles: roles,
      });
    }

    next();
  };
}

// Use role middleware
app.get(
  '/admin/dashboard',
  requireAuth(),
  requireRole('admin', 'moderator'),
  (req, res) => {
    res.json({ message: 'Admin dashboard' });
  },
);

REST API with Scopes

const router = express.Router();

// List resources (read permission)
router.get('/', requireAuth(), requireScope('resources:read'), (req, res) => {
  res.json({ resources: getResources() });
});

// Create resource (write permission)
router.post('/', requireAuth(), requireScope('resources:write'), (req, res) => {
  const resource = createResource(req.body);
  res.json({ resource });
});

// Update resource (write permission)
router.put(
  '/:id',
  requireAuth(),
  requireScope('resources:write'),
  (req, res) => {
    const resource = updateResource(req.params.id, req.body);
    res.json({ resource });
  },
);

// Delete resource (delete permission)
router.delete(
  '/:id',
  requireAuth(),
  requireScope('resources:delete'),
  (req, res) => {
    deleteResource(req.params.id);
    res.json({ message: 'Deleted' });
  },
);

app.use('/api/resources', router);

Multi-Tenant Application

app.get('/api/organizations/:orgId/data', requireAuth(), (req, res) => {
  const { orgId } = req.params;

  // Verify user belongs to organization
  if (req.auth.organizationId !== orgId) {
    return res.status(403).json({
      error: 'Access denied to this organization',
    });
  }

  res.json({
    organization: orgId,
    data: getOrganizationData(orgId),
  });
});

Error Handling

Unauthorized (401)

Returned when user is not authenticated:
{
  "error": "unauthorized",
  "message": "Authentication required"
}

Forbidden (403)

Returned when user lacks required scopes:
{
  "error": "forbidden",
  "message": "Insufficient permissions",
  "required_scopes": ["admin:delete"]
}

Global Error Handler

app.use((err: any, req: any, res: any, next: any) => {
  console.error('Auth error:', err);

  if (err.status === 401) {
    return res.status(401).json({
      error: 'Unauthorized',
      message: 'Please sign in',
    });
  }

  if (err.status === 403) {
    return res.status(403).json({
      error: 'Forbidden',
      message: 'Insufficient permissions',
    });
  }

  res.status(500).json({ error: 'Internal server error' });
});

Best Practices

  1. Always use requireAuth() before scope middleware - Scope checks require auth
  2. Use optionalAuth() for public routes - Enhance UX for logged-in users
  3. Implement custom unauthorized handlers - Better user experience
  4. Use TypeScript - Type-safe request handling
  5. Enable autoRefresh for long sessions - Prevent token expiration
  6. Centralize permission logic - Create reusable middleware
  7. Log authentication failures - Monitor security issues

Troubleshooting

Middleware Not Working

Ensure initAuthSafe() is called before using middleware:
// ✅ Correct order
initAuthSafe(config);
app.get('/dashboard', requireAuth(), handler);

// ❌ Wrong order
app.get('/dashboard', requireAuth(), handler);
initAuthSafe(config);

req.auth is undefined

Use requireAuth() to ensure auth session exists:
// ✅ Correct
app.get('/profile', requireAuth(), (req, res) => {
  console.log(req.auth.email);
});

// ❌ Wrong - auth might be undefined
app.get('/profile', (req, res) => {
  console.log(req.auth?.email);
});

Related

  • Setup - Initial configuration
  • Route Handlers - OAuth handlers
  • Session Management - Cookie handling
  • JWT Utilities - Token verification