import type { SignedPassport } from '../../types/passport.js'; import type { CoreVerifyClockOptions } from '../../types/policy.js'; /** Why a request was denied at the gate. Closed set, ordered: a missing * passport is reported before signature, signature before issuer trust, * issuer trust before scope. */ export type GateDenyReason = 'NO_PASSPORT' | 'PASSPORT_INVALID' | 'UNTRUSTED_ISSUER' | 'MISSING_SCOPE'; export interface GateDecision { /** True iff the request is authorized to proceed to application logic. */ admit: boolean; /** Set iff admit is false. */ reason?: GateDenyReason; /** Suggested HTTP status for the deny response. 401 for credential * problems, 403 for an authenticated agent lacking scope. Undefined on * admit. The adapter is free to override. */ status?: 401 | 403; /** Human-readable detail for logs and the deny body. Never leaks key * material; names the failing check only. */ detail?: string; /** Verifier errors from the passport check, when applicable. Useful for * audit logs; not sent to the caller by default. */ errors?: string[]; /** Verifier warnings, carried through rather than dropped. The * self-signed acceptance warning arrives here on an admit made under * allowSelfSigned, so an operator can see on what basis a request was * let through. */ warnings?: string[]; } export interface GateOptions { /** Trust anchors: issuer public keys whose countersignature the gate * accepts. When this list is NON-EMPTY the passport MUST carry a valid * countersignature from one of them, and allowSelfSigned does not * override that. * * An EMPTY list, or omitting the option, means the gate holds no trust * anchors. It does not mean "trust anyone": with no anchor and no * explicit allowSelfSigned the gate denies with UNTRUSTED_ISSUER. */ trustedIssuers?: string[]; /** Explicit wildcard trust. Set true to admit a passport whose only * authority is its own signature, i.e. a self-signed credential where * the subject and the issuer are the same key. This is a real posture * for a closed network or a development gate, and the decision carries * a warning saying so, but it has to be asked for by name: a signature * that verifies under a key the passport itself supplied is not an * authorization by a trusted issuer. Default false. Ignored when * trustedIssuers is non-empty. */ allowSelfSigned?: boolean; /** Uniform clock-skew option, threaded into verifyPassport. Reuses the * one millisecond-based skew option the SDK exposes. */ clock?: CoreVerifyClockOptions; /** Scopes the request requires. ALL listed scopes must be present in the * passport's capabilities[] for admission (logical AND). Empty or * omitted means "any valid passport admits" (authentication only). */ requiredScopes?: string[]; /** When true, a required scope is satisfied if the passport carries ANY * one of requiredScopes (logical OR) instead of all. Default false. */ anyScope?: boolean; } /** * The gate decision. Pure and offline: it runs verifyPassport (signature, * validity window, issuer countersignature against the configured anchors), * then the trust-anchor posture check, then the scope check, in that order, * and returns admit/deny. No network, no mutation, no I/O. * * `presented` is whatever the transport adapter extracted. `undefined` or * a malformed value denies with NO_PASSPORT rather than throwing, so a * missing credential is a clean 401, not a 500. * * TRUST POSTURE. A passport signature verifies under the public key carried * inside the passport, so on its own it proves only that the holder of that * key wrote the passport, including whatever capabilities it claims. That is * not an authorization by anyone the gate trusts. The gate therefore requires * one of two explicit postures and refuses to guess: * * trustedIssuers: [keys] the passport must carry a valid countersignature * from one of those issuers. * allowSelfSigned: true self-signed credentials are accepted, and every * admit says so in `warnings`. * * Neither one configured, or trustedIssuers set to an empty array, denies * with UNTRUSTED_ISSUER. This used to admit: verifyPassport's 'self-signed * passports are accepted' warning had nowhere to go on the old GateDecision * and was discarded, so an attacker's self-signed passport claiming * admin:everything came back as {"admit": true}. */ export declare function evaluateRequest(presented: SignedPassport | undefined | null, opts?: GateOptions): GateDecision; /** Minimal request surface the gate reads. The adapter supplies a * getPassport that knows where the credential lives on the transport * (a header, the parsed body, a verified session). */ export interface GateRequestLike { getPassport: () => SignedPassport | undefined | null; } /** Minimal response surface the gate writes on deny. */ export interface GateResponseLike { /** Send a deny response with the given status and JSON body, then end. */ deny: (status: number, body: { error: GateDenyReason; detail?: string; }) => void; } /** * Run the gate against a transport-shaped request/response. On admit, * calls `proceed()` (the framework's next()/handler). On deny, writes the * deny response and does NOT call proceed - unauthorized traffic is * dropped before application logic. * * Returns the decision so an adapter or test can assert on it. */ export declare function runGate(req: GateRequestLike, res: GateResponseLike, proceed: () => void, opts?: GateOptions): GateDecision; //# sourceMappingURL=middleware.d.ts.map