/** * Shared inbound-credential resolution. * * Consumed by both `SdkDispatcher` (kernel envelope) and `mountAuxiliaryRoutes` * (View / RemoteFunction routes). Centralises the auth-policy three-way * (`'required'` / `'optional'` / `'public'`) and the wrap of underlying * verification errors into canonical `AuthMissingError` / `AuthInvalidError`. */ import type { AuthPolicy } from '@astrale-os/kernel-api/routed' import type { AuthContext, Authenticated, CredentialInput, IdentityId, } from '@astrale-os/kernel-core' import { isKernelErrorClassifiable } from '@astrale-os/kernel-api' import type { AuthenticateResult } from './authenticate.js' import type { RemoteIdentityConfig } from './identity.js' import { authenticateRequest } from './authenticate.js' import { AuthInvalidError, AuthMissingError } from './errors.js' export type ResolvedAuth = { auth: AuthContext | null kernel: AuthenticateResult['kernel'] } export async function resolveInboundAuth( credential: CredentialInput, policy: AuthPolicy | undefined, identity: RemoteIdentityConfig, ): Promise { const effective = policy ?? 'required' if (effective === 'public') return { auth: null, kernel: null } if (effective === 'optional' && !credential) return { auth: null, kernel: null } if (effective === 'required' && !credential) throw new AuthMissingError() try { const result = await authenticateRequest(credential, identity) return { auth: buildAuthContext(result.authenticated), kernel: result.kernel } } catch (err) { // kernel-core auth errors (UntrustedIssuerError, TrustPolicyDeniedError, …) // already self-classify with a discriminating `data.type`. Rethrow them // unchanged so that classification survives to the wire; only wrap // genuinely unclassified errors into the generic AuthInvalidError. if (isKernelErrorClassifiable(err)) throw err throw new AuthInvalidError(err instanceof Error ? err.message : 'Authentication failed', err) } } export function buildAuthContext(authenticated: Authenticated): AuthContext { return { credential: authenticated.credential, principal: authenticated.credential.verified.sub as unknown as IdentityId, grant: authenticated.grant!, attestation: authenticated.attestation, delegation: authenticated.delegation, } }