/** * Authentication and authorization middleware */ import { verify } from 'jsonwebtoken'; import { DIDResolver } from '@the-order/auth'; import { getEnv } from './env'; import { AppError } from './error-handler'; import fetch from 'node-fetch'; /** * JWT authentication middleware */ export async function authenticateJWT(request, _reply) { const authHeader = request.headers.authorization; if (!authHeader || !authHeader.startsWith('Bearer ')) { throw new AppError(401, 'UNAUTHORIZED', 'Missing or invalid authorization header'); } const token = authHeader.substring(7); const env = getEnv(); if (!env.JWT_SECRET) { throw new AppError(500, 'CONFIG_ERROR', 'JWT secret not configured'); } try { const decoded = verify(token, env.JWT_SECRET); request.user = decoded; } catch (error) { throw new AppError(401, 'INVALID_TOKEN', 'Invalid or expired token'); } } /** * DID-based authentication middleware */ export async function authenticateDID(request, _reply) { const didHeader = request.headers['x-did']; const signatureHeader = request.headers['x-did-signature']; const messageHeader = request.headers['x-did-message']; if (!didHeader || !signatureHeader || !messageHeader) { throw new AppError(401, 'UNAUTHORIZED', 'Missing DID authentication headers'); } try { const resolver = new DIDResolver(); const isValid = await resolver.verifySignature(didHeader, messageHeader, signatureHeader); if (!isValid) { throw new AppError(401, 'INVALID_SIGNATURE', 'Invalid DID signature'); } request.user = { id: didHeader, did: didHeader, }; } catch (error) { if (error instanceof AppError) { throw error; } throw new AppError(401, 'AUTH_ERROR', 'DID authentication failed'); } } /** * Role-based access control middleware */ export function requireRole(...allowedRoles) { return async (request, _reply) => { if (!request.user) { throw new AppError(401, 'UNAUTHORIZED', 'Authentication required'); } const userRoles = request.user.roles || []; const hasRole = allowedRoles.some((role) => userRoles.includes(role)); if (!hasRole) { throw new AppError(403, 'FORBIDDEN', `Required role: ${allowedRoles.join(' or ')}`); } }; } /** * OIDC token validation middleware */ export async function authenticateOIDC(request, _reply) { const authHeader = request.headers.authorization; if (!authHeader || !authHeader.startsWith('Bearer ')) { throw new AppError(401, 'UNAUTHORIZED', 'Missing authorization header'); } const token = authHeader.substring(7); const env = getEnv(); // Validate token with OIDC issuer if (!env.OIDC_ISSUER) { throw new AppError(500, 'CONFIG_ERROR', 'OIDC issuer not configured'); } try { // Introspect token with issuer const introspectionUrl = `${env.OIDC_ISSUER}/introspect`; const response = await fetch(introspectionUrl, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', Authorization: `Basic ${Buffer.from(`${env.OIDC_CLIENT_ID}:${env.OIDC_CLIENT_SECRET}`).toString('base64')}`, }, body: new URLSearchParams({ token, token_type_hint: 'access_token', }), }); if (!response.ok) { throw new AppError(401, 'INVALID_TOKEN', 'Token introspection failed'); } const tokenInfo = (await response.json()); if (!tokenInfo.active) { throw new AppError(401, 'INVALID_TOKEN', 'Token is not active'); } // Get user info from userinfo endpoint const userInfoUrl = `${env.OIDC_ISSUER}/userinfo`; const userInfoResponse = await fetch(userInfoUrl, { headers: { Authorization: `Bearer ${token}`, }, }); if (userInfoResponse.ok) { const userInfo = (await userInfoResponse.json()); request.user = { id: userInfo.sub, email: userInfo.email, }; } else { // Fallback to token info request.user = { id: tokenInfo.sub || 'oidc-user', email: tokenInfo.email, }; } } catch (error) { if (error instanceof AppError) { throw error; } throw new AppError(401, 'AUTH_ERROR', 'OIDC token validation failed'); } } //# sourceMappingURL=auth.js.map