Skip to content
reaatechREAATECH

@reaatech/mcp-gateway-auth

npm v1.0.0

Provides Express middleware that validates API keys, JWTs, OAuth2 introspection, or OIDC tokens to secure MCP Gateway requests. It attaches a typed `AuthContext` to the request object and includes utility functions for scope checking and audit-friendly token fingerprinting.

@reaatech/mcp-gateway-auth

npm version License: MIT CI

Status: Pre-1.0 — APIs may change in minor versions. Pin to a specific version in production.

Pluggable authentication middleware for the MCP Gateway. Supports four authentication methods — API key, JWT (with JWKS), OAuth2 token introspection (RFC 7662), and OIDC ID token validation — all orchestrated through a single Express middleware that attaches a typed AuthContext to every request.

Installation

terminal
npm install @reaatech/mcp-gateway-auth
# or
pnpm add @reaatech/mcp-gateway-auth

Feature Overview

  • API key authentication — constant-time comparison with SHA-256 hashed keys
  • JWT validation — JWKS-based RS256/ES256 token verification with jose
  • OAuth2 introspection — RFC 7662 token introspection with LRU caching and automatic cleanup
  • OIDC validation — OpenID Connect ID token validation with nonce replay protection
  • Single Express middlewareauthMiddleware() orchestrates all four methods
  • Tenant-aware — auto-discovers authentication config from the tenant registry
  • Audit-friendly — every auth call produces a token fingerprint for audit trails
  • Dual ESM/CJS output — works with import and require

Quick Start

typescript
import express from "express";
import { authMiddleware } from "@reaatech/mcp-gateway-auth";
 
const app = express();
app.use(authMiddleware());
 
app.get("/protected", (req, res) => {
  // req.authContext is typed — tenantId, userId, scopes, authMethod
  res.json({ tenant: req.authContext?.tenantId });
});

API Reference

Auth Middleware

ExportDescription
authMiddleware(options?)Express middleware — extracts credentials, validates, attaches authContext to req. Returns 401 on failure.
optionalAuthMiddleware()Like authMiddleware but never rejects — attaches context if valid, passes through if not
requireAuth(req)Get auth context from request; throws AuthenticationError if missing
getAuth(req)Get auth context from request; returns undefined if missing
AuthenticationErrorError class with code (e.g. AUTH_REQUIRED, AUTH_FAILED) and statusCode

Auth Context

ExportDescription
AuthContextInterface: tenantId, userId, scopes, authMethod, keyName, subject, issuer, expiresAt, tokenFingerprint
AuthMethodString union: api-key' | 'jwt' | 'oauth' | 'oidc
createAuthContext(opts)Create a minimal auth context
hasScope(context, scope)Check if context has a specific scope (supports wildcard tools:*)
hasAnyScope(context, scopes)Check if context has any of the given scopes
hasAllScopes(context, scopes)Check if context has all given scopes
getRedactedAuthContext(ctx)Return a copy safe for logging (token redacted)
generateTokenFingerprint(token)SHA-256 fingerprint for audit trail

API Key

ExportDescription
hashApiKey(key)SHA-256 hash for storage
validateApiKey(key, config)Validate key against tenant config
findTenantForApiKey(key, tenants)Find which tenant owns this key
ApiKeyValidationResult{ valid, context?, error? }

JWT

ExportDescription
validateJwt(token, config)Validate JWT against issuer/audience/JWKS
decodeJwtUnsafe(token)Decode without verification (debug only)
isJwtExpired(token)Check token expiration
JwtValidationResult{ valid, context?, error? }

OAuth2

ExportDescription
introspectToken(token, config)RFC 7662 introspection
clearIntrospectionCache()Clear cached introspection results
getIntrospectionCacheStats()Get cache size
shutdownOAuthIntrospection()Stop background cache cleanup
IntrospectionResult{ valid, context?, error? }

OIDC

ExportDescription
validateOidcIdToken(token, config)Validate OIDC ID token
validateNonce(payload, nonce)Replay protection check
extractUserInfoFromIdToken(token)Extract standard OIDC claims
OidcValidationResult{ valid, context?, error? }

Usage Patterns

Tenant-aware auth with YAML config

typescript
import { authMiddleware, AuthenticationError } from "@reaatech/mcp-gateway-auth";
import type { Request, Response, NextFunction } from "express";
 
const auth = authMiddleware({
  onFailure: (error: AuthenticationError, req: Request) => {
    console.warn(`Auth failed: ${error.code} from ${req.ip}`);
  },
});
 
app.post("/mcp", auth, (req, res) => {
  // req.authContext is guaranteed non-null here
  const { tenantId, userId, scopes } = req.authContext!;
  console.log(`Tenant ${tenantId} using ${req.authContext!.authMethod}`);
});

Scope-based access control

typescript
import { getAuth, hasScope } from "@reaatech/mcp-gateway-auth";
 
app.delete("/admin/:id", (req, res, next) => {
  const ctx = getAuth(req);
  if (!ctx || !hasScope(ctx, "admin:*")) {
    return res.status(403).json({ error: "Forbidden" });
  }
  next();
});

Custom auth flow with optional middleware

typescript
import { optionalAuthMiddleware, getAuth } from "@reaatech/mcp-gateway-auth";
 
app.use(optionalAuthMiddleware());
 
app.get("/public", (req, res) => {
  const ctx = getAuth(req);
  res.json({ authenticated: !!ctx, tenant: ctx?.tenantId });
});

License

MIT