UNPKG

@accounter/server

Version:
112 lines 4.51 kB
import { useExtendContext } from 'graphql-yoga'; import { handleDevBypassAuth } from '../modules/auth/providers/auth-context.provider.js'; import { BUSINESS_SCOPE_HEADER, parseBusinessScopeHeader } from './business-scope-header.js'; /** * AuthPlugin - Extracts authentication credentials from request headers. * * This plugin is part of the Auth0 authentication system. * It ONLY handles credential extraction. Verification and context creation * are delegated to the AuthContextProvider. * * Responsibilities: * 1. Extract `X-Dev-Auth: <user-id>` (Dev Bypass, gated by ALLOW_DEV_AUTH=1) * 1. Extract `Authorization: Bearer <token>` (JWT) * 2. Extract `X-API-Key: <key>` (API Key) * 3. Add `rawAuth` object to Yoga context */ export const authPlugin = () => { const allowDevAuth = process.env.ALLOW_DEV_AUTH === '1'; if (allowDevAuth) { // eslint-disable-next-line no-console console.warn('⚠️ DEV AUTH BYPASS ENABLED'); } return useExtendContext(async (yogaContext) => { const request = yogaContext.request; const devAuthHeader = request.headers.get('x-dev-auth'); const authHeader = request.headers.get('authorization'); const apiKeyHeader = request.headers.get('x-api-key'); const gatewayCpTokenHeader = request.headers.get('x-gateway-cp-token'); // Parse the requested read scope once. Attach it only when the header was // actually sent, so requests without it keep the original rawAuth shape. const parsedScope = parseBusinessScopeHeader(request.headers.get(BUSINESS_SCOPE_HEADER)); const scopeFields = parsedScope.kind === 'absent' ? {} : { requestedBusinessScope: parsedScope }; // Dev bypass takes precedence when explicitly enabled and user is resolvable. if (allowDevAuth && devAuthHeader) { const userId = devAuthHeader.trim(); if (userId.length > 0) { const pool = yogaContext.pool; if (pool) { const db = { query: async (queryStatement, values) => { const result = await pool.query(queryStatement, values); return { ...result, rowCount: typeof result.rowCount === 'number' ? result.rowCount : 0, }; }, }; const context = await handleDevBypassAuth(db, userId); if (context) { return { rawAuth: { authType: 'devBypass', token: userId, ...scopeFields, }, }; } } } } // Gateway control-plane service identity (no tenant context) if (gatewayCpTokenHeader) { const token = gatewayCpTokenHeader.trim(); if (token.length > 0) { return { rawAuth: { authType: 'gatewayControlPlane', token, ...scopeFields, }, }; } } // JWT takes precedence (e.g., user operations) if (authHeader?.startsWith('Bearer ')) { const token = authHeader.substring(7).trim(); if (token.length > 0) { return { rawAuth: { authType: 'jwt', token, ...scopeFields, }, }; } } // Fallback to API key (e.g., automated tools) if (apiKeyHeader) { const token = apiKeyHeader.trim(); if (token.length > 0) { return { rawAuth: { authType: 'apiKey', token, ...scopeFields, }, }; } } // Unauthenticated or malformed headers return { rawAuth: { authType: null, token: null, ...scopeFields, }, }; }); }; //# sourceMappingURL=auth-plugin.js.map