Skip to content

Signatures quoted from source. Usage: Authenticate, Trust. Related: PassportRules.

Entry points

Import fromExports
@assistant-ui/passportcreatePassport, PassportUnauthorized, Passport types

@assistant-ui/passport

createPassport

const createPassport: (config: Passport.Config, options?: Passport.Options) => Passport.Instance;

Validates the config at construction and returns { validate(request) }. validate tries every staticToken provider first, then the others in config order. It returns null when the request carries no credential, a static token matches no key, or a JWT's iss matches no JWT provider; it throws PassportUnauthorized on a credential a provider claimed and rejected. Config errors throw Error with a passport: prefix.

Passport.*Shape
Secretstring | { env: string }: { env: "NAME" } resolves from options.env, else process.env; an unset or empty variable throws env var NAME (for <field>) is not set. Only secret, key, keys[].token, and auth.bearer take it
Credential{ bearer: true } | { cookie: string } | { header: string }: defaults to { bearer: true }; exactly one of the three
ProviderJwtProvider | StaticTokenProvider | IntrospectProvider
Config{ providers: Provider[] }
Options{ fetch?: (request: Request) => Promise<Response>; now?: () => number; env?: Record<string, string | undefined> }
Principal{ sub: string; scopes: string[]; claims: Record<string, unknown> }
Instance{ validate(request: Request): Promise<Principal | null> }
UnauthorizedPassportUnauthorized

Passport.JwtProvider

NameTypeDefaultMeaning
type"jwt"requiredProvider kind
idstringrequiredUnique label used in logs and errors
issuerstringrequiredExact iss match; the OIDC discovery base when no key source is set
jwksUrl?string—JWKS endpoint, HTTPS without userinfo; accepts RS256, ES256, EdDSA; at most one of jwksUrl, key, secret
key?Secret—SPKI PEM public key; requires alg
alg?"RS256" | "ES256" | "EdDSA"—Algorithm for key; set without key throws alg is only valid with key
secret?Secret—HS256 shared secret
audiencestring[]requiredToken aud must contain one of these
scopes?string[][]Scopes used when the token's scope claim is absent or not a string; a non-empty list of non-empty strings
credential?Credential{ bearer: true }Where the token is read from

A token needs integer exp and iat and a non-empty string sub; exp, nbf, and iat get 30 s of clock tolerance. A string scope claim, space-separated, sets the scopes; any other type is ignored in favor of scopes. The principal's claims is the whole verified payload (errors). A { header } credential name matches case-insensitively.

Passport.StaticTokenProvider

NameTypeDefaultMeaning
type"staticToken"requiredProvider kind
idstringrequiredUnique label used in logs and errors
keys{ name; token?; hash?; scopes?; claims? }[]requiredNon-empty; key names are unique
keys[].namestringrequiredKey label; becomes the principal's sub
keys[].token?Secret | Secret[]—Raw credential, hashed at construction; exactly one of token or hash
keys[].hash?string | string[]—"sha256:<64 hex>" of the credential
keys[].scopes?string[][]Scopes granted to this key; a non-empty list of non-empty strings
keys[].claims?Record<string, unknown>—Claims attached to the principal
credential?Credential{ bearer: true }Where the token is read from

token and hash take an array, and any entry authenticates as that key. List the current and the next secret, roll every deployment, drop the old entry. A credential repeated across keys, in any provider, throws duplicate static token credential.

Passport.IntrospectProvider

NameTypeDefaultMeaning
type"introspect"requiredProvider kind
idstringrequiredUnique label used in logs and errors; sent to the endpoint as client_id
urlstringrequiredRFC 7662 endpoint; non-empty HTTPS, set at construction
issuer?stringthe endpoint originExact iss match for active responses; an HTTPS URL
audience?string[]—Active responses must target one of these
auth?{ bearer: Secret }—Credential sent to the endpoint
cacheTtlMs?number30000Positive number; cache lifetime for active responses, capped at the response exp. Inactive responses cache 5 s; transport and parse failures never. The principal's claims is the response minus active; scopes come from its scope string, else []
credential?Credential{ bearer: true }Where the token is read from

Discovery, JWKS, and introspection requests time out after 5 s. A JWKS is cached 10 min, with a 30 s cooldown after a failed fetch.

PassportUnauthorized

class PassportUnauthorized extends Error {
  readonly reason: string;
  constructor(reason: string);
}

message is invalid credential: ${reason}, name is "PassportUnauthorized". reason is safe to log.

Passport

Type-only namespace; shapes above. Registry roles, claims.pinboard scoping, and the 401/403 bodies: Registry and operators.