UNPKG

@trifrost/core

Version:

Blazingly fast, runtime-agnostic server framework for modern edge and node environments

70 lines (69 loc) 3.3 kB
import { isNeString } from '@valkyriestudios/utils/string'; import { Sym_TriFrostDescription, Sym_TriFrostFingerPrint, Sym_TriFrostName } from '../../types/constants'; import { Sym_TriFrostMiddlewareAuth } from './types'; /* Specific symbol attached to auth mware to identify them by */ export const Sym_TriFrostMiddlewareApiKeyAuth = Symbol('TriFrost.Middleware.ApiKeyAuth'); /** * API Key Authentication middleware. * * This middleware checks for an API key either in the request headers or * query parameters, using configurable names. It then calls the provided * validate() function. If valid, the `$auth` state is set on the context. * * @see https://swagger.io/docs/specification/authentication/api-keys/ * * @example * .use(ApiKeyAuth({ * apiKey: {header: 'x-api-key'}, * apiClient: {header: 'x-api-id'}, * validate: (ctx, key) => key === ctx.env.MY_API_KEY * })) */ export function ApiKeyAuth(opts) { if (typeof opts?.validate !== 'function') throw new Error('TriFrostMiddleware@ApiKeyAuth: A validate function must be provided'); const hasApiKeyHeader = isNeString(opts.apiKey?.header); const hasApiKeyQuery = isNeString(opts.apiKey?.query); if (!hasApiKeyHeader && !hasApiKeyQuery) { throw new Error('TriFrostMiddleware@ApiKeyAuth: You must configure apiKey header or query'); } /* Determine key behavior */ const apiKeyHeader = hasApiKeyHeader ? opts.apiKey.header : null; const apiKeyQuery = hasApiKeyQuery ? opts.apiKey.query : null; /* Determine client behavior */ const apiClientHeader = isNeString(opts.apiClient?.header) ? opts.apiClient.header : null; const apiClientQuery = isNeString(opts.apiClient?.query) ? opts.apiClient.query : null; const apiClientEnabled = apiClientHeader || apiClientQuery; const mware = async function TriFrostApiKeyAuth(ctx) { /* Api Client */ let apiClient = null; if (apiClientEnabled) { if (apiClientHeader) apiClient = ctx.headers[apiClientHeader]; if (!apiClient && apiClientQuery) apiClient = ctx.query.get(apiClientQuery); if (typeof apiClient !== 'string' || !apiClient.length) return ctx.status(401); } /* Get value from header, falling back to query */ let apiKey = null; if (apiKeyHeader) apiKey = ctx.headers[apiKeyHeader]; if (!apiKey && apiKeyQuery) apiKey = ctx.query.get(apiKeyQuery); if (typeof apiKey !== 'string' || !apiKey.length) return ctx.status(401); /* Validate, if not valid return 401 */ const result = await opts.validate(ctx, { apiKey, apiClient }); if (!result) return ctx.status(401); const authenticated = result === true ? { apiKey, apiClient } : result; return ctx.setState({ $auth: authenticated }); }; /* Add symbols for introspection/use further down the line */ Reflect.set(mware, Sym_TriFrostName, 'TriFrostApiKeyAuth'); Reflect.set(mware, Sym_TriFrostDescription, 'API Key Authentication middleware'); Reflect.set(mware, Sym_TriFrostMiddlewareAuth, true); Reflect.set(mware, Sym_TriFrostFingerPrint, Sym_TriFrostMiddlewareApiKeyAuth); return mware; }