@hyper.authio/testing 0.7.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +19 -3
- package/dist/index.cjs +171 -54
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +85 -8
- package/dist/index.d.ts +85 -8
- package/dist/index.js +172 -55
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/fake-authio.ts","../src/manual-clock.ts","../src/webhook-delivery.ts"],"names":["randomUUID","SignJWT","decodeJwt","generateKeyPair","exportJWK","createServer","jwtVerify","importJWK","CompactEncrypt","createHash","AuthioWebhookHeaders","computeWebhookSignatureHeader"],"mappings":"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","file":"index.cjs","sourcesContent":["import { createServer, type IncomingMessage, type Server, type ServerResponse } from \"node:http\";\nimport type { AddressInfo } from \"node:net\";\nimport { createHash, randomUUID } from \"node:crypto\";\nimport {\n CompactEncrypt,\n decodeJwt,\n exportJWK,\n generateKeyPair,\n importJWK,\n jwtVerify,\n SignJWT,\n type CryptoKey,\n type JWK,\n type JWTPayload,\n} from \"jose\";\n\n/**\n * How the fake encrypts what it issues to a client, as Authio does once the client registered an encryption key.\n */\nexport interface FakeAuthioClientEncryption {\n /** The client's public encryption key (RSA). */\n key: JWK;\n /** Defaults to `RSA-OAEP-256`. */\n algorithm?: \"RSA-OAEP\" | \"RSA-OAEP-256\";\n /** Defaults to `A256CBC-HS512`. */\n encryptionMethod?: \"A128CBC-HS256\" | \"A192CBC-HS384\" | \"A256CBC-HS512\";\n /** Encrypts the client's access tokens (nested JWT). */\n accessTokens?: boolean;\n /** Encrypts the client's ID tokens. Defaults to `true`. */\n idTokens?: boolean;\n /** Encrypts UserInfo answered as a JWT. Defaults to `true`. */\n userInfo?: boolean;\n /** Encrypts back-channel logout tokens. */\n logoutTokens?: boolean;\n}\n\n/**\n * A client registered in the fake.\n */\nexport interface FakeAuthioClient {\n clientId: string;\n /** For `client_secret_basic` and `client_secret_post`. */\n clientSecret?: string;\n /** The public JWK `private_key_jwt` assertions are verified with. */\n publicKey?: JWK;\n /** Scopes granted when a request names none. */\n defaultScopes?: string[];\n /** Extra claims put into every access token issued to the client. */\n claims?: Record<string, unknown>;\n /** The client this one's tokens are introspectable by, besides itself (a resource server's introspection client). */\n introspectionClients?: string[];\n /** The redirect URIs the authorization endpoint accepts. Any when absent. */\n redirectUris?: string[];\n /** The post-logout redirect URIs the end-session endpoint accepts. Any when absent. */\n postLogoutRedirectUris?: string[];\n /** Where back-channel logout tokens are posted when a session of the client ends. */\n backchannelLogoutUri?: string;\n /** Encrypts what is issued to the client. */\n encryption?: FakeAuthioClientEncryption;\n}\n\n/**\n * A person the fake knows, for the password grant, authorization codes and UserInfo.\n */\nexport interface FakeAuthioUser {\n sub: string;\n username: string;\n password?: string;\n /** Claims put into the person's access tokens: `*_resource_access`, `org_id`, mapper claims… */\n claims?: Record<string, unknown>;\n /** What UserInfo answers besides `sub`. */\n userInfo?: Record<string, unknown>;\n /** The sign-in's methods. Defaults to `[\"pwd\"]`. */\n amr?: string[];\n /** The sign-in's level. Defaults to `1`, or the `acr_values` asked for. */\n acr?: string;\n}\n\n/**\n * A personal access token the fake accepts with the `personal_access_token` grant.\n */\nexport interface FakeAuthioPersonalAccessToken {\n /** The `pat_…` value. */\n token: string;\n /** The credential's id, the token's `sub`. */\n sub: string;\n /** The consumer's client, for a consumer's token; the `authio` client of an account otherwise. */\n clientId?: string;\n /** Claims added to the access token. */\n claims?: Record<string, unknown>;\n}\n\n/**\n * An error the fake answers a request with.\n */\nexport interface FakeAuthioError {\n status: number;\n body?: Record<string, unknown>;\n headers?: Record<string, string>;\n}\n\n/**\n * A request the fake received.\n */\nexport interface FakeAuthioRecordedRequest {\n method: string;\n path: string;\n headers: Record<string, string>;\n form: Record<string, string>;\n /** The query parameters. */\n query: Record<string, string>;\n /** The client the request authenticated as, when it did. */\n clientId?: string;\n}\n\n/**\n * A back-channel logout token the fake posted to a client.\n */\nexport interface FakeAuthioBackchannelDelivery {\n clientId: string;\n uri: string;\n logoutToken: string;\n /** The HTTP status the client answered, or 0 when it could not be reached. */\n status: number;\n}\n\n/**\n * The parameters an authorization ended with, as the fake sent them back.\n */\nexport interface FakeAuthioAuthorizationOutcome {\n /** `code`, `state` and `iss`, or `error`, `error_description`, `state` and `iss`. */\n parameters: Record<string, string>;\n /** The redirect URI with the parameters, for `response_mode=query`. */\n callbackUrl: string | undefined;\n}\n\n/**\n * What the device flow answers to successive polls.\n */\nexport type FakeAuthioDeviceOutcome = \"pending\" | \"slow_down\" | \"approved\" | \"denied\" | \"expired\";\n\n/**\n * Options of the fake.\n */\nexport interface FakeAuthioOptions {\n /** The realm. Defaults to `fake`. */\n realm?: string;\n /** Seconds tokens live. Defaults to 300. */\n accessTokenLifetime?: number;\n clients?: FakeAuthioClient[];\n users?: FakeAuthioUser[];\n personalAccessTokens?: FakeAuthioPersonalAccessToken[];\n}\n\n/**\n * Options of a token minted directly.\n */\nexport interface FakeAuthioTokenOptions {\n sub?: string;\n /** One or several audiences. Defaults to the client id. */\n audience?: string | string[];\n clientId?: string;\n scope?: string;\n /** Seconds. Negative values mint an expired token. */\n expiresIn?: number;\n /** The `typ` claim. Defaults to `Bearer`. */\n type?: string;\n /** Claims added to the payload. */\n claims?: Record<string, unknown>;\n /** Signs with another issuer. */\n issuer?: string;\n /** Signs with another key, so the signature does not verify. */\n untrusted?: boolean;\n /** Encrypts the token (nested JWT) to this public key, as Authio does for a client with an encryption key. */\n encryptTo?: { key: JWK; algorithm?: \"RSA-OAEP\" | \"RSA-OAEP-256\"; encryptionMethod?: string };\n}\n\ninterface IssuedToken {\n claims: JWTPayload;\n clientId: string;\n revoked: boolean;\n}\n\ninterface PendingCode {\n clientId: string;\n sub: string;\n redirectUri: string;\n scope?: string;\n codeVerifier?: string;\n codeChallenge?: string;\n codeChallengeMethod?: string;\n resource?: string;\n nonce?: string;\n sid?: string;\n authTime?: number;\n acr?: string;\n amr?: string[];\n}\n\ninterface FakeSession {\n sub: string;\n sid: string;\n authTime: number;\n acr: string;\n amr: string[];\n clients: Set<string>;\n}\n\ntype Endpoint = \"token\" | \"introspect\" | \"revoke\" | \"userinfo\" | \"device\" | \"discovery\" | \"authorize\" | \"logout\";\n\n/**\n * An in-memory Authio realm served over HTTP on loopback: discovery, JWKS, authorization (PKCE, `state`, `nonce`,\n * `prompt`, `max_age`, `acr_values`, `response_mode=web_message`, RFC 9207 `iss`), token (client credentials,\n * authorization code with ID tokens, refresh, token exchange, password, device code, personal access token),\n * introspection, revocation, UserInfo, device authorization, end session and back-channel logout delivery, with JWE\n * (RSA-OAEP, RSA-OAEP-256) for clients that registered an encryption key.\n */\nexport class FakeAuthio {\n /** Every request received, in order. */\n readonly requests: FakeAuthioRecordedRequest[] = [];\n /** Answers the next requests to an endpoint with these errors, in order, before answering normally. */\n readonly failures = new Map<Endpoint, FakeAuthioError[]>();\n /** Every back-channel logout token posted, in order. */\n readonly backchannelDeliveries: FakeAuthioBackchannelDelivery[] = [];\n /** What successive device-code polls answer; the last value repeats. Defaults to `[\"approved\"]`. */\n deviceOutcomes: FakeAuthioDeviceOutcome[] = [\"approved\"];\n /** Overrides the discovery document's issuer, to test the mismatch check. */\n discoveryIssuer: string | undefined;\n /** Answers UserInfo as `application/jwt`, signed by the realm key (and encrypted for a client with a key). */\n userInfoAsJwt = false;\n /** Leaves `iss` out of authorization responses, to test the RFC 9207 check. */\n omitAuthorizationIssuer = false;\n /** Answers connected-account exchanges. Defaults to granting a token for the provider. */\n connectionResponder: ((form: Record<string, string>) => FakeAuthioError | Record<string, unknown>) | undefined;\n /** The person the authorization endpoint signs in when the request names none with `login_hint`. Defaults to the first user. */\n signInAs: string | undefined;\n\n private readonly clients = new Map<string, FakeAuthioClient>();\n private readonly users = new Map<string, FakeAuthioUser>();\n private readonly personalAccessTokens = new Map<string, FakeAuthioPersonalAccessToken>();\n private readonly codes = new Map<string, PendingCode>();\n private readonly refreshTokens = new Map<string, { clientId: string; sub: string; scope?: string; sid?: string; expiresAt: number }>();\n private readonly issued = new Map<string, IssuedToken>();\n private readonly devicePolls = new Map<string, number>();\n private readonly lifetime: number;\n private session: FakeSession | undefined;\n private server!: Server;\n private signingKey!: CryptoKey;\n private verificationKey!: CryptoKey;\n private untrustedKey!: CryptoKey;\n private publicJwk!: JWK;\n private baseUrl!: string;\n readonly realm: string;\n readonly keyId = \"fake-key-1\";\n\n private constructor(options: FakeAuthioOptions) {\n this.realm = options.realm ?? \"fake\";\n this.lifetime = options.accessTokenLifetime ?? 300;\n\n for (const client of options.clients ?? []) this.clients.set(client.clientId, client);\n for (const user of options.users ?? []) this.users.set(user.username, user);\n for (const pat of options.personalAccessTokens ?? []) this.personalAccessTokens.set(pat.token, pat);\n }\n\n /**\n * Starts the fake on a random loopback port.\n */\n static async start(options: FakeAuthioOptions = {}): Promise<FakeAuthio> {\n const fake = new FakeAuthio(options);\n\n await fake.listen();\n\n return fake;\n }\n\n /** `http://127.0.0.1:{port}`. */\n get authority(): string {\n return this.baseUrl;\n }\n\n /** `{authority}/realms/{realm}`. */\n get issuer(): string {\n return `${this.baseUrl}/realms/${this.realm}`;\n }\n\n /** The realm's public signing key. */\n get jwks(): { keys: JWK[] } {\n return { keys: [this.publicJwk] };\n }\n\n /** The session the authorization endpoint keeps (one browser), or `undefined` when nobody is signed in. */\n get currentSession(): { sub: string; sid: string; authTime: number } | undefined {\n return this.session ? { sub: this.session.sub, sid: this.session.sid, authTime: this.session.authTime } : undefined;\n }\n\n /** Registers a client. */\n addClient(client: FakeAuthioClient): void {\n this.clients.set(client.clientId, client);\n }\n\n /** Registers a person. */\n addUser(user: FakeAuthioUser): void {\n this.users.set(user.username, user);\n }\n\n /** Registers a personal access token. */\n addPersonalAccessToken(token: FakeAuthioPersonalAccessToken): void {\n this.personalAccessTokens.set(token.token, token);\n }\n\n /** Ends the signed-in session without notifying anyone, as if it expired. */\n endSession(): void {\n this.session = undefined;\n }\n\n /**\n * Registers an authorization code for a person, as the authorization endpoint would after sign-in.\n */\n createAuthorizationCode(options: { clientId: string; username: string; redirectUri: string; scope?: string; codeChallengeVerifier?: string; resource?: string; nonce?: string }): string {\n const user = this.requireUser(options.username);\n const code = randomUUID();\n\n this.codes.set(code, {\n clientId: options.clientId,\n sub: user.sub,\n redirectUri: options.redirectUri,\n scope: options.scope,\n codeVerifier: options.codeChallengeVerifier,\n resource: options.resource,\n nonce: options.nonce,\n });\n\n return code;\n }\n\n /**\n * Follows an authorization URL as a browser would, signing in `signInAs` (or the `login_hint`), and returns what\n * Authio sent back: the callback URL for `response_mode=query`, the posted message's parameters for `web_message`.\n */\n async authorize(authorizationUrl: string): Promise<FakeAuthioAuthorizationOutcome> {\n const response = await fetch(authorizationUrl, { redirect: \"manual\" });\n const location = response.headers.get(\"location\");\n\n if (location) {\n const callback = new URL(location);\n\n return { parameters: Object.fromEntries(callback.searchParams), callbackUrl: location };\n }\n\n const html = await response.text();\n const message = /data-authorization-response='([^']*)'/.exec(html)?.[1];\n\n if (!message) throw new Error(`The fake answered the authorization with HTTP ${response.status} and no response.`);\n\n return { parameters: JSON.parse(decodeURIComponent(message)) as Record<string, string>, callbackUrl: undefined };\n }\n\n /**\n * Mints an access token signed by the realm key, recorded so introspection and revocation know it.\n */\n async issueAccessToken(options: FakeAuthioTokenOptions = {}): Promise<string> {\n const now = Math.floor(Date.now() / 1000);\n const clientId = options.clientId ?? \"fake-client\";\n const jti = randomUUID();\n const payload: JWTPayload = {\n typ: options.type ?? \"Bearer\",\n azp: clientId,\n client_id: clientId,\n ...(options.scope ? { scope: options.scope } : {}),\n ...(options.sub ? { sub: options.sub } : {}),\n ...options.claims,\n };\n const signed = await new SignJWT(payload)\n .setProtectedHeader({ alg: \"RS256\", kid: this.keyId, typ: \"JWT\" })\n .setIssuer(options.issuer ?? this.issuer)\n .setAudience(options.audience ?? clientId)\n .setIssuedAt(now)\n .setNotBefore(now)\n .setExpirationTime(now + (options.expiresIn ?? this.lifetime))\n .setJti(jti)\n .sign(options.untrusted ? this.untrustedKey : this.signingKey);\n const token = options.encryptTo ? await encryptTo(signed, options.encryptTo) : signed;\n\n this.issued.set(token, { claims: decodeJwt(signed), clientId, revoked: false });\n\n return token;\n }\n\n /**\n * Mints a back-channel logout token for a client, signed by the realm key. `overrides` replaces claims (`undefined`\n * removes one) and `type` the header `typ`, to build invalid ones in tests.\n */\n async createLogoutToken(options: { clientId: string; sub?: string; sid?: string; type?: string; overrides?: Record<string, unknown> }): Promise<string> {\n const now = Math.floor(Date.now() / 1000);\n const payload: Record<string, unknown> = {\n iss: this.issuer,\n aud: options.clientId,\n iat: now,\n exp: now + 120,\n jti: randomUUID(),\n ...(options.sub ? { sub: options.sub } : {}),\n ...(options.sid ? { sid: options.sid } : {}),\n events: { \"http://schemas.openid.net/event/backchannel-logout\": {} },\n ...options.overrides,\n };\n\n for (const key of Object.keys(payload)) if (payload[key] === undefined) delete payload[key];\n\n const signed = await new SignJWT(payload as JWTPayload).setProtectedHeader({ alg: \"RS256\", kid: this.keyId, typ: options.type ?? \"logout+jwt\" }).sign(this.signingKey);\n const encryption = this.clients.get(options.clientId)?.encryption;\n\n return encryption?.logoutTokens ? encryptTo(signed, encryption) : signed;\n }\n\n /**\n * Posts a back-channel logout token to the client's `backchannelLogoutUri`, as Authio does when a session ends.\n *\n * @returns The HTTP status the client answered, or 0 when it could not be reached.\n */\n async deliverBackchannelLogout(clientId: string, options: { sub?: string; sid?: string } = {}): Promise<number> {\n const client = this.clients.get(clientId);\n\n if (!client?.backchannelLogoutUri) throw new Error(`The fake client ${clientId} has no backchannelLogoutUri.`);\n\n const logoutToken = await this.createLogoutToken({ clientId, sub: options.sub, sid: options.sid });\n let status = 0;\n\n try {\n const response = await fetch(client.backchannelLogoutUri, {\n method: \"POST\",\n headers: { \"content-type\": \"application/x-www-form-urlencoded\" },\n body: new URLSearchParams({ logout_token: logoutToken }).toString(),\n });\n\n status = response.status;\n await response.arrayBuffer();\n } catch {\n status = 0;\n }\n\n this.backchannelDeliveries.push({ clientId, uri: client.backchannelLogoutUri, logoutToken, status });\n\n return status;\n }\n\n /** Marks a token revoked, as Authio would after a sign-out: an access token, or a refresh token, which is then forgotten. */\n revokeToken(token: string): void {\n const issued = this.issued.get(token);\n\n if (issued) issued.revoked = true;\n\n this.refreshTokens.delete(token);\n }\n\n /** Revokes every refresh token of a person, or of one Authio session (`sid`), as Authio does when a session ends. */\n revokeRefreshTokens(options: { sub?: string; sid?: string }): void {\n for (const [token, refresh] of this.refreshTokens)\n if ((options.sid !== undefined && refresh.sid === options.sid) || (options.sid === undefined && options.sub !== undefined && refresh.sub === options.sub))\n this.refreshTokens.delete(token);\n }\n\n /** Forgets the recorded requests. */\n clearRequests(): void {\n this.requests.length = 0;\n }\n\n /** The recorded requests to one endpoint path suffix, such as `/token`. */\n requestsTo(suffix: string): FakeAuthioRecordedRequest[] {\n return this.requests.filter((request) => request.path.endsWith(suffix));\n }\n\n /** Stops the server. */\n close(): Promise<void> {\n return new Promise((resolve, reject) => {\n this.server.closeAllConnections?.();\n this.server.close((error) => (error ? reject(error) : resolve()));\n });\n }\n\n private async listen(): Promise<void> {\n const pair = await generateKeyPair(\"RS256\", { extractable: true });\n const untrusted = await generateKeyPair(\"RS256\");\n\n this.signingKey = pair.privateKey;\n this.verificationKey = pair.publicKey;\n this.untrustedKey = untrusted.privateKey;\n this.publicJwk = { ...(await exportJWK(pair.publicKey)), kid: this.keyId, alg: \"RS256\", use: \"sig\" };\n this.server = createServer((request, response) => {\n this.handle(request, response).catch((error: unknown) => {\n send(response, { status: 500, body: { error: \"server_error\", error_description: String(error) } });\n });\n });\n\n await new Promise<void>((resolve) => this.server.listen(0, \"127.0.0.1\", resolve));\n\n this.baseUrl = `http://127.0.0.1:${(this.server.address() as AddressInfo).port}`;\n }\n\n private async handle(request: IncomingMessage, response: ServerResponse): Promise<void> {\n const url = new URL(request.url ?? \"/\", this.baseUrl);\n const body = await readBody(request);\n const form = Object.fromEntries(new URLSearchParams(request.headers[\"content-type\"]?.includes(\"form\") ? body : \"\"));\n const headers = Object.fromEntries(Object.entries(request.headers).map(([name, value]) => [name, Array.isArray(value) ? value.join(\", \") : (value ?? \"\")]));\n const query = Object.fromEntries(url.searchParams);\n const recorded: FakeAuthioRecordedRequest = { method: request.method ?? \"GET\", path: url.pathname, headers, form, query };\n\n this.requests.push(recorded);\n\n const prefix = `/realms/${this.realm}`;\n const path = url.pathname.startsWith(prefix) ? url.pathname.slice(prefix.length) : url.pathname;\n const endpoint = endpointOf(path);\n const failure = endpoint ? this.failures.get(endpoint)?.shift() : undefined;\n\n if (failure) return send(response, failure);\n\n switch (path) {\n case \"/.well-known/openid-configuration\":\n return send(response, { status: 200, body: this.discovery() });\n case \"/protocol/openid-connect/certs\":\n return send(response, { status: 200, body: this.jwks });\n case \"/protocol/openid-connect/auth\":\n return this.authorizeEndpoint(query, response);\n case \"/protocol/openid-connect/token\":\n return send(response, await this.token(recorded, form));\n case \"/protocol/openid-connect/token/introspect\":\n return send(response, await this.introspect(recorded, form));\n case \"/protocol/openid-connect/revoke\":\n return send(response, await this.revoke(recorded, form));\n case \"/protocol/openid-connect/userinfo\":\n return this.userInfo(headers, response);\n case \"/protocol/openid-connect/auth/device\":\n return send(response, await this.device(recorded, form));\n case \"/protocol/openid-connect/logout\":\n return this.endSessionEndpoint(query, response);\n default:\n return send(response, { status: 404, body: { error: \"not_found\" } });\n }\n }\n\n private discovery(): Record<string, unknown> {\n const base = `${this.issuer}/protocol/openid-connect`;\n\n return {\n issuer: this.discoveryIssuer ?? this.issuer,\n authorization_endpoint: `${base}/auth`,\n token_endpoint: `${base}/token`,\n introspection_endpoint: `${base}/token/introspect`,\n revocation_endpoint: `${base}/revoke`,\n userinfo_endpoint: `${base}/userinfo`,\n end_session_endpoint: `${base}/logout`,\n device_authorization_endpoint: `${base}/auth/device`,\n jwks_uri: `${base}/certs`,\n scopes_supported: [\"openid\", \"profile\", \"email\", \"phone\", \"roles\", \"offline_access\"],\n response_types_supported: [\"code\"],\n response_modes_supported: [\"query\", \"web_message\"],\n grant_types_supported: [\n \"authorization_code\",\n \"refresh_token\",\n \"client_credentials\",\n \"password\",\n \"urn:ietf:params:oauth:grant-type:device_code\",\n \"urn:ietf:params:oauth:grant-type:token-exchange\",\n \"personal_access_token\",\n ],\n subject_types_supported: [\"public\"],\n id_token_signing_alg_values_supported: [\"RS256\"],\n id_token_encryption_alg_values_supported: [\"RSA-OAEP\", \"RSA-OAEP-256\"],\n id_token_encryption_enc_values_supported: [\"A128CBC-HS256\", \"A192CBC-HS384\", \"A256CBC-HS512\"],\n userinfo_signing_alg_values_supported: [\"RS256\"],\n userinfo_encryption_alg_values_supported: [\"RSA-OAEP\", \"RSA-OAEP-256\"],\n userinfo_encryption_enc_values_supported: [\"A128CBC-HS256\", \"A192CBC-HS384\", \"A256CBC-HS512\"],\n token_endpoint_auth_methods_supported: [\"client_secret_basic\", \"client_secret_post\", \"private_key_jwt\", \"none\"],\n code_challenge_methods_supported: [\"S256\", \"plain\"],\n prompt_values_supported: [\"none\", \"login\", \"select_account\", \"consent\"],\n display_values_supported: [\"page\", \"popup\"],\n acr_values_supported: [\"1\", \"2\", \"3\"],\n backchannel_logout_supported: true,\n backchannel_logout_session_supported: true,\n authorization_response_iss_parameter_supported: !this.omitAuthorizationIssuer,\n };\n }\n\n private authorizeEndpoint(query: Record<string, string>, response: ServerResponse): void {\n const client = this.clients.get(query.client_id ?? \"\");\n\n if (!client) return send(response, { status: 400, body: { error: \"invalid_request\", error_description: \"Unknown client_id.\" } });\n if (!query.redirect_uri || (client.redirectUris && !client.redirectUris.includes(query.redirect_uri)))\n return send(response, { status: 400, body: { error: \"invalid_request\", error_description: \"The redirect_uri is not registered.\" } });\n\n const answer = (parameters: Record<string, string | undefined>) => {\n const values: Record<string, string> = {};\n\n for (const [name, value] of Object.entries({ ...parameters, state: query.state, iss: this.omitAuthorizationIssuer ? undefined : this.issuer }))\n if (value !== undefined) values[name] = value;\n\n if (query.response_mode === \"web_message\") {\n const message = encodeURIComponent(JSON.stringify(values));\n\n response.writeHead(200, { \"content-type\": \"text/html; charset=utf-8\" });\n response.end(\n `<!doctype html><html><body data-authorization-response='${message}'><script>window.opener&&window.opener.postMessage({type:\"authorization_response\",response:JSON.parse(decodeURIComponent(document.body.dataset.authorizationResponse))},${JSON.stringify(new URL(query.redirect_uri!).origin)});</script></body></html>`,\n );\n return;\n }\n\n const location = new URL(query.redirect_uri!);\n\n for (const [name, value] of Object.entries(values)) location.searchParams.set(name, value);\n\n response.writeHead(302, { location: location.toString() });\n response.end();\n };\n\n if (query.response_type !== \"code\") return answer({ error: \"unsupported_response_type\", error_description: \"Only code is supported.\" });\n\n const method = query.code_challenge_method ?? (query.code_challenge ? \"plain\" : undefined);\n\n if (method && method !== \"S256\" && method !== \"plain\") return answer({ error: \"invalid_request\", error_description: \"Unsupported PKCE method.\" });\n\n const prompts = (query.prompt ?? \"\").split(\" \").filter(Boolean);\n const now = Math.floor(Date.now() / 1000);\n const maxAge = query.max_age !== undefined ? Number(query.max_age) : undefined;\n const tooOld = this.session !== undefined && maxAge !== undefined && now - this.session.authTime > maxAge;\n const requestedAcr = (query.acr_values ?? \"\").split(\" \").filter(Boolean).sort().at(-1);\n const weaker = this.session !== undefined && requestedAcr !== undefined && Number(this.session.acr) < Number(requestedAcr);\n\n if (prompts.includes(\"none\") && (!this.session || tooOld || weaker)) return answer({ error: \"login_required\", error_description: \"Nobody is signed in.\" });\n\n if (!this.session || prompts.includes(\"login\") || tooOld || weaker || (query.login_hint && this.users.get(query.login_hint)?.sub !== this.session.sub)) {\n const username = (query.login_hint && this.users.has(query.login_hint) ? query.login_hint : undefined) ?? this.signInAs ?? this.users.keys().next().value;\n const user = username ? this.users.get(username) : undefined;\n\n if (!user) return answer({ error: \"access_denied\", error_description: \"The fake has no user to sign in.\" });\n\n const acr = requestedAcr ?? user.acr ?? \"1\";\n\n this.session = {\n sub: user.sub,\n sid: randomUUID().replace(/-/g, \"\"),\n authTime: now,\n acr,\n amr: user.amr ?? (Number(acr) >= 2 ? [\"pwd\", \"otp\", \"mfa\"] : [\"pwd\"]),\n clients: new Set(),\n };\n }\n\n this.session.clients.add(client.clientId);\n\n const code = randomUUID();\n\n this.codes.set(code, {\n clientId: client.clientId,\n sub: this.session.sub,\n redirectUri: query.redirect_uri,\n scope: query.scope,\n codeChallenge: query.code_challenge,\n codeChallengeMethod: method,\n resource: query.resource,\n nonce: query.nonce,\n sid: this.session.sid,\n authTime: this.session.authTime,\n acr: this.session.acr,\n amr: this.session.amr,\n });\n\n answer({ code });\n }\n\n private async endSessionEndpoint(query: Record<string, string>, response: ServerResponse): Promise<void> {\n let clientId = query.client_id;\n\n if (query.id_token_hint) {\n try {\n const { payload } = await jwtVerify(query.id_token_hint, this.verificationKey, { issuer: this.issuer });\n\n clientId ??= [payload.aud ?? []].flat()[0];\n } catch {\n return send(response, { status: 400, body: { error: \"invalid_request\", error_description: \"The id_token_hint is not valid.\" } });\n }\n }\n\n const client = clientId ? this.clients.get(clientId) : undefined;\n const redirect = query.post_logout_redirect_uri;\n\n if (redirect && (!client || (client.postLogoutRedirectUris && !client.postLogoutRedirectUris.includes(redirect))))\n return send(response, { status: 400, body: { error: \"invalid_request\", error_description: \"The post_logout_redirect_uri is not registered.\" } });\n\n const ended = this.session;\n\n this.session = undefined;\n\n if (ended) this.revokeRefreshTokens({ sid: ended.sid });\n\n if (ended)\n for (const id of ended.clients) if (this.clients.get(id)?.backchannelLogoutUri) await this.deliverBackchannelLogout(id, { sub: ended.sub, sid: ended.sid });\n\n if (!redirect) {\n response.writeHead(200, { \"content-type\": \"text/html; charset=utf-8\" });\n response.end(\"<!doctype html><p>You are signed out.</p>\");\n return;\n }\n\n const location = new URL(redirect);\n\n if (query.state) location.searchParams.set(\"state\", query.state);\n\n response.writeHead(302, { location: location.toString() });\n response.end();\n }\n\n private async authenticate(recorded: FakeAuthioRecordedRequest, form: Record<string, string>): Promise<FakeAuthioClient | FakeAuthioError> {\n const invalid = (description: string): FakeAuthioError => ({ status: 401, body: { error: \"invalid_client\", error_description: description } });\n const authorization = recorded.headers.authorization;\n let client: FakeAuthioClient | undefined;\n\n if (authorization?.startsWith(\"Basic \")) {\n const [id, secret] = Buffer.from(authorization.slice(6), \"base64\").toString(\"utf8\").split(\":\").map(decodeURIComponent);\n\n client = this.clients.get(id ?? \"\");\n\n if (!client || !client.clientSecret || client.clientSecret !== secret) return invalid(\"The client credentials are wrong.\");\n } else if (form.client_assertion) {\n client = this.clients.get(form.client_id ?? \"\");\n\n if (!client?.publicKey) return invalid(\"The client has no registered key.\");\n if (form.client_assertion_type !== \"urn:ietf:params:oauth:client-assertion-type:jwt-bearer\") return invalid(\"Wrong assertion type.\");\n\n try {\n const key = await importJWK(client.publicKey, client.publicKey.alg);\n const { payload } = await jwtVerify(form.client_assertion, key, { issuer: client.clientId, subject: client.clientId, audience: this.issuer });\n\n if (!payload.jti) return invalid(\"The assertion has no jti.\");\n } catch (error) {\n return invalid(`The assertion does not verify: ${(error as Error).message}`);\n }\n } else if (form.client_secret !== undefined) {\n client = this.clients.get(form.client_id ?? \"\");\n\n if (!client || client.clientSecret !== form.client_secret) return invalid(\"The client credentials are wrong.\");\n } else {\n client = this.clients.get(form.client_id ?? \"\");\n\n if (!client || client.clientSecret || client.publicKey) return invalid(\"The client must authenticate.\");\n }\n\n recorded.clientId = client.clientId;\n\n return client;\n }\n\n private async token(recorded: FakeAuthioRecordedRequest, form: Record<string, string>): Promise<FakeAuthioError> {\n const grant = (error: string, description: string): FakeAuthioError => ({ status: 400, body: { error, error_description: description } });\n\n if (form.grant_type === \"personal_access_token\") {\n const pat = this.personalAccessTokens.get(form.client_secret ?? \"\");\n\n if (!pat || (form.client_id && pat.clientId && form.client_id !== pat.clientId))\n return { status: 401, body: { error: \"invalid_client\", error_description: \"The personal access token is not valid.\" } };\n\n const clientId = pat.clientId ?? \"authio\";\n\n recorded.clientId = clientId;\n\n return this.tokenAnswer(this.clients.get(clientId) ?? { clientId }, {\n sub: pat.sub,\n scope: form.scope,\n audience: form.resource,\n claims: { amr: \"personal_access_token\", actor_type: \"personal_access_token\", credential_id: pat.sub, ...pat.claims },\n });\n }\n\n const client = await this.authenticate(recorded, form);\n\n if (\"status\" in client) return client;\n\n const scope = form.scope ?? client.defaultScopes?.join(\" \");\n\n switch (form.grant_type) {\n case \"client_credentials\":\n return this.tokenAnswer(client, { sub: client.clientId, scope, audience: form.resource, claims: client.claims });\n case \"password\": {\n const user = this.users.get(form.username ?? \"\");\n\n if (!user || user.password !== form.password) return grant(\"invalid_grant\", \"Wrong username or password.\");\n\n return this.tokenAnswer(client, { sub: user.sub, scope, claims: { ...client.claims, ...user.claims, preferred_username: user.username } }, user);\n }\n case \"authorization_code\": {\n const code = this.codes.get(form.code ?? \"\");\n\n if (!code || code.clientId !== client.clientId || code.redirectUri !== form.redirect_uri) return grant(\"invalid_grant\", \"The code is not valid.\");\n if (code.codeVerifier && code.codeVerifier !== form.code_verifier) return grant(\"invalid_grant\", \"PKCE verification failed.\");\n if (code.codeChallenge && !verifiesChallenge(form.code_verifier, code.codeChallenge, code.codeChallengeMethod ?? \"plain\"))\n return grant(\"invalid_grant\", \"PKCE verification failed.\");\n\n this.codes.delete(form.code!);\n\n const user = [...this.users.values()].find((candidate) => candidate.sub === code.sub)!;\n const signIn = code.sid\n ? { sid: code.sid, auth_time: code.authTime, acr: code.acr, amr: code.amr }\n : { auth_time: Math.floor(Date.now() / 1000), acr: user.acr ?? \"1\", amr: user.amr ?? [\"pwd\"] };\n\n return this.tokenAnswer(\n client,\n {\n sub: user.sub,\n scope: code.scope,\n audience: form.resource ?? code.resource,\n claims: { ...client.claims, ...user.claims, ...signIn, preferred_username: user.username },\n },\n user,\n undefined,\n { nonce: code.nonce, signIn },\n );\n }\n case \"refresh_token\": {\n const refresh = this.refreshTokens.get(form.refresh_token ?? \"\");\n\n if (!refresh || refresh.clientId !== client.clientId) return grant(\"invalid_grant\", \"The refresh token is not valid.\");\n\n this.refreshTokens.delete(form.refresh_token!);\n\n const user = [...this.users.values()].find((candidate) => candidate.sub === refresh.sub);\n\n return this.tokenAnswer(\n client,\n { sub: refresh.sub, scope: form.scope ?? refresh.scope, claims: { ...client.claims, ...user?.claims, ...(refresh.sid ? { sid: refresh.sid } : {}) } },\n user,\n );\n }\n case \"urn:ietf:params:oauth:grant-type:token-exchange\": {\n const subject = this.issued.get(form.subject_token ?? \"\");\n\n if (!subject || subject.revoked) return grant(\"invalid_grant\", \"The subject token is not valid.\");\n\n if (form.requested_token_type === \"urn:authio:params:oauth:token-type:connection-access-token\") {\n const answer = this.connectionResponder?.(form) ?? {\n access_token: `provider-token-${form.connection_provider}`,\n issued_token_type: form.requested_token_type,\n token_type: \"Bearer\",\n expires_in: 3600,\n provider: form.connection_provider,\n };\n\n return \"status\" in answer && typeof answer.status === \"number\" ? (answer as FakeAuthioError) : { status: 200, body: answer as Record<string, unknown> };\n }\n\n const { iss: _issuer, aud: _audience, exp: _expiry, iat: _issuedAt, nbf: _notBefore, jti: _jti, scope: _scope, ...claims } = subject.claims;\n\n return this.tokenAnswer(client, {\n sub: subject.claims.sub,\n scope: form.scope ?? (subject.claims.scope as string | undefined),\n audience: form.resource,\n claims: { ...claims, act: { client_id: client.clientId } },\n }, undefined, form.requested_token_type);\n }\n case \"urn:ietf:params:oauth:grant-type:device_code\": {\n const polls = this.devicePolls.get(form.device_code ?? \"\");\n\n if (polls === undefined) return grant(\"invalid_grant\", \"Unknown device code.\");\n\n this.devicePolls.set(form.device_code!, polls + 1);\n\n const outcome = this.deviceOutcomes[Math.min(polls, this.deviceOutcomes.length - 1)] ?? \"approved\";\n\n switch (outcome) {\n case \"pending\":\n return grant(\"authorization_pending\", \"The user has not approved yet.\");\n case \"slow_down\":\n return grant(\"slow_down\", \"Poll less often.\");\n case \"denied\":\n return grant(\"access_denied\", \"The user denied the request.\");\n case \"expired\":\n return grant(\"expired_token\", \"The device code expired.\");\n default:\n return this.tokenAnswer(client, { sub: \"device-user\", scope, claims: client.claims });\n }\n }\n default:\n return grant(\"unsupported_grant_type\", `The grant ${form.grant_type} is not supported.`);\n }\n }\n\n private async tokenAnswer(\n client: FakeAuthioClient,\n options: { sub?: string; scope?: string; audience?: string; claims?: Record<string, unknown> },\n user?: FakeAuthioUser,\n issuedTokenType?: string,\n idToken?: { nonce?: string; signIn: Record<string, unknown> },\n ): Promise<FakeAuthioError> {\n const encryption = client.encryption;\n const accessToken = await this.issueAccessToken({\n clientId: client.clientId,\n sub: options.sub,\n scope: options.scope,\n audience: options.audience ?? client.clientId,\n claims: options.claims,\n ...(encryption?.accessTokens ? { encryptTo: encryption } : {}),\n });\n const body: Record<string, unknown> = {\n access_token: accessToken,\n token_type: \"Bearer\",\n expires_in: this.lifetime,\n ...(options.scope ? { scope: options.scope } : {}),\n ...(issuedTokenType ? { issued_token_type: issuedTokenType } : {}),\n };\n\n if (user) {\n const refreshToken = randomUUID();\n const sid = typeof options.claims?.sid === \"string\" ? options.claims.sid : undefined;\n\n this.refreshTokens.set(refreshToken, { clientId: client.clientId, sub: user.sub, scope: options.scope, sid, expiresAt: Math.floor(Date.now() / 1000) + 30 * 24 * 3600 });\n body.refresh_token = refreshToken;\n }\n\n if (user && idToken && (options.scope ?? \"\").split(\" \").includes(\"openid\")) {\n const now = Math.floor(Date.now() / 1000);\n const signIn = Object.fromEntries(Object.entries(idToken.signIn).filter(([, value]) => value !== undefined));\n const signed = await new SignJWT({\n typ: \"ID\",\n azp: client.clientId,\n ...signIn,\n ...(idToken.nonce ? { nonce: idToken.nonce } : {}),\n at_hash: halfHash(accessToken),\n preferred_username: user.username,\n ...user.userInfo,\n })\n .setProtectedHeader({ alg: \"RS256\", kid: this.keyId, typ: \"JWT\" })\n .setIssuer(this.issuer)\n .setAudience(client.clientId)\n .setSubject(user.sub)\n .setIssuedAt(now)\n .setExpirationTime(now + this.lifetime)\n .sign(this.signingKey);\n\n body.id_token = encryption && encryption.idTokens !== false ? await encryptTo(signed, encryption) : signed;\n }\n\n return { status: 200, body };\n }\n\n private async introspect(recorded: FakeAuthioRecordedRequest, form: Record<string, string>): Promise<FakeAuthioError> {\n const client = await this.authenticate(recorded, form);\n\n if (\"status\" in client) return client;\n\n const issued = this.issued.get(form.token ?? \"\");\n const now = Math.floor(Date.now() / 1000);\n const refresh = this.refreshTokens.get(form.token ?? \"\");\n\n if (refresh)\n return refresh.clientId === client.clientId\n ? {\n status: 200,\n body: {\n active: true,\n token_type: \"Refresh\",\n client_id: refresh.clientId,\n sub: refresh.sub,\n exp: refresh.expiresAt,\n ...(refresh.scope ? { scope: refresh.scope } : {}),\n ...(refresh.sid ? { sid: refresh.sid } : {}),\n },\n }\n : { status: 200, body: { active: false } };\n\n if (!issued || issued.revoked || (issued.claims.exp ?? 0) <= now) return { status: 200, body: { active: false } };\n\n const audiences = [issued.claims.aud ?? []].flat();\n const allowed =\n issued.clientId === client.clientId && audiences.includes(client.clientId)\n ? true\n : audiences.some((audience) => this.clients.get(audience)?.introspectionClients?.includes(client.clientId) || audience === client.clientId);\n\n if (!allowed) return { status: 200, body: { active: false } };\n\n const { typ, ...claims } = issued.claims;\n\n return { status: 200, body: { active: true, token_type: typ ?? \"Bearer\", username: claims.preferred_username, ...claims } };\n }\n\n private async revoke(recorded: FakeAuthioRecordedRequest, form: Record<string, string>): Promise<FakeAuthioError> {\n const client = await this.authenticate(recorded, form);\n\n if (\"status\" in client) return client;\n\n this.revokeToken(form.token ?? \"\");\n this.refreshTokens.delete(form.token ?? \"\");\n\n return { status: 200 };\n }\n\n private async device(recorded: FakeAuthioRecordedRequest, form: Record<string, string>): Promise<FakeAuthioError> {\n const client = await this.authenticate(recorded, form);\n\n if (\"status\" in client) return client;\n\n const deviceCode = randomUUID();\n\n this.devicePolls.set(deviceCode, 0);\n\n return {\n status: 200,\n body: {\n device_code: deviceCode,\n user_code: \"WDJB-MJHT\",\n verification_uri: `${this.issuer}/device`,\n verification_uri_complete: `${this.issuer}/device?user_code=WDJB-MJHT`,\n expires_in: 600,\n interval: 5,\n },\n };\n }\n\n private async userInfo(headers: Record<string, string>, response: ServerResponse): Promise<void> {\n const token = headers.authorization?.replace(/^Bearer\\s+/i, \"\");\n const issued = token ? this.issued.get(token) : undefined;\n\n if (!issued || issued.revoked)\n return send(response, {\n status: 401,\n headers: { \"www-authenticate\": 'Bearer error=\"invalid_token\", error_description=\"The access token is not valid.\"' },\n });\n\n const user = [...this.users.values()].find((candidate) => candidate.sub === issued.claims.sub);\n const claims = { sub: issued.claims.sub, ...user?.userInfo };\n\n if (!this.userInfoAsJwt) return send(response, { status: 200, body: claims });\n\n const now = Math.floor(Date.now() / 1000);\n const signed = await new SignJWT(claims)\n .setProtectedHeader({ alg: \"RS256\", kid: this.keyId })\n .setIssuer(this.issuer)\n .setAudience(issued.clientId)\n .setIssuedAt(now)\n .setExpirationTime(now + this.lifetime)\n .sign(this.signingKey);\n const encryption = this.clients.get(issued.clientId)?.encryption;\n const jwt = encryption && encryption.userInfo !== false ? await encryptTo(signed, encryption) : signed;\n\n response.writeHead(200, { \"content-type\": \"application/jwt\" });\n response.end(jwt);\n }\n\n private requireUser(username: string): FakeAuthioUser {\n const user = this.users.get(username);\n\n if (!user) throw new Error(`The fake has no user ${username}.`);\n\n return user;\n }\n}\n\nfunction endpointOf(path: string): Endpoint | undefined {\n if (path.endsWith(\"/token\")) return \"token\";\n if (path.endsWith(\"/introspect\")) return \"introspect\";\n if (path.endsWith(\"/revoke\")) return \"revoke\";\n if (path.endsWith(\"/userinfo\")) return \"userinfo\";\n if (path.endsWith(\"/auth/device\")) return \"device\";\n if (path.endsWith(\"/openid-configuration\")) return \"discovery\";\n if (path.endsWith(\"/auth\")) return \"authorize\";\n if (path.endsWith(\"/logout\")) return \"logout\";\n return undefined;\n}\n\nasync function encryptTo(signed: string, encryption: { key: JWK; algorithm?: string; encryptionMethod?: string }): Promise<string> {\n const algorithm = encryption.algorithm ?? \"RSA-OAEP-256\";\n const key = await importJWK({ ...encryption.key, alg: algorithm, use: \"enc\", key_ops: undefined }, algorithm);\n\n return new CompactEncrypt(new TextEncoder().encode(signed))\n .setProtectedHeader({ alg: algorithm, enc: encryption.encryptionMethod ?? \"A256CBC-HS512\", typ: \"JWE\", cty: \"JWT\", ...(encryption.key.kid ? { kid: encryption.key.kid } : {}) })\n .encrypt(key);\n}\n\nfunction verifiesChallenge(verifier: string | undefined, challenge: string, method: string): boolean {\n if (!verifier) return false;\n\n return method === \"S256\" ? createHash(\"sha256\").update(verifier, \"ascii\").digest(\"base64url\") === challenge : verifier === challenge;\n}\n\nfunction halfHash(value: string): string {\n return createHash(\"sha256\").update(value, \"ascii\").digest().subarray(0, 16).toString(\"base64url\");\n}\n\nfunction send(response: ServerResponse, answer: FakeAuthioError): void {\n const headers: Record<string, string> = { ...answer.headers };\n\n if (answer.body !== undefined) headers[\"content-type\"] ??= \"application/json\";\n\n response.writeHead(answer.status, headers);\n response.end(answer.body === undefined ? undefined : JSON.stringify(answer.body));\n}\n\nfunction readBody(request: IncomingMessage): Promise<string> {\n return new Promise((resolve, reject) => {\n const chunks: Buffer[] = [];\n\n request.on(\"data\", (chunk: Buffer) => chunks.push(chunk));\n request.on(\"end\", () => resolve(Buffer.concat(chunks).toString(\"utf8\")));\n request.on(\"error\", reject);\n });\n}\n","import type { AuthioClock } from \"@hyper.authio/client\";\n\n/**\n * A clock that moves only when told to. `sleep` returns at once and moves the clock forward by the time asked, so\n * device polling and cache expiry run instantly and deterministically.\n */\nexport class ManualClock implements AuthioClock {\n /** Every `sleep` asked for, in milliseconds. */\n readonly sleeps: number[] = [];\n private time: number;\n\n /**\n * @param start Milliseconds since the epoch. Defaults to the current time.\n */\n constructor(start: number = Date.now()) {\n this.time = start;\n }\n\n now(): number {\n return this.time;\n }\n\n sleep(ms: number, signal?: AbortSignal): Promise<void> {\n if (signal?.aborted) return Promise.reject(signal.reason);\n\n this.sleeps.push(ms);\n this.time += ms;\n\n return Promise.resolve();\n }\n\n /** Moves the clock forward. */\n advance(ms: number): void {\n this.time += ms;\n }\n\n /** Sets the clock. */\n set(ms: number): void {\n this.time = ms;\n }\n}\n","import { randomUUID } from \"node:crypto\";\nimport { AuthioWebhookHeaders, computeWebhookSignatureHeader } from \"@hyper.authio/client\";\n\n/**\n * A webhook delivery as Authio would send it.\n */\nexport interface FakeWebhookDelivery {\n readonly body: string;\n readonly headers: Record<string, string>;\n readonly event: Record<string, unknown>;\n}\n\n/**\n * Builds a signed webhook delivery.\n *\n * @param type The event type.\n * @param data The event data.\n * @param secret The webhook secret.\n * @param options `id`, `timestamp` (milliseconds) and extra event members.\n */\nexport async function createWebhookDelivery(\n type: string,\n data: unknown,\n secret: string,\n options: { id?: string; timestamp?: number; realmId?: string; clientId?: string; sendEventIdHeader?: boolean } = {},\n): Promise<FakeWebhookDelivery> {\n const timestamp = options.timestamp ?? Date.now();\n const id = options.id ?? randomUUID();\n const event = {\n id,\n type,\n created_at: Math.floor(timestamp / 1000),\n ...(options.realmId ? { realm_id: options.realmId } : {}),\n ...(options.clientId ? { client_id: options.clientId } : {}),\n data,\n };\n const body = JSON.stringify(event);\n const headers: Record<string, string> = {\n \"content-type\": \"application/json\",\n [AuthioWebhookHeaders.Signature]: await computeWebhookSignatureHeader(body, secret, timestamp),\n [AuthioWebhookHeaders.Event]: type,\n };\n\n if (options.sendEventIdHeader ?? true) headers[AuthioWebhookHeaders.EventId] = id;\n\n return { body, headers, event };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/fake-authio.ts","../src/manual-clock.ts","../src/webhook-delivery.ts"],"names":["randomUUID","SignJWT","decodeJwt","generateKeyPair","exportJWK","createServer","jwtVerify","importJWK","decodeProtectedHeader","CompactEncrypt","createHash","AuthioWebhookHeaders","computeWebhookSignatureHeader"],"mappings":"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","file":"index.cjs","sourcesContent":["import { createServer, type IncomingMessage, type Server, type ServerResponse } from \"node:http\";\nimport type { AddressInfo } from \"node:net\";\nimport { createHash, randomUUID } from \"node:crypto\";\nimport {\n CompactEncrypt,\n decodeJwt,\n decodeProtectedHeader,\n exportJWK,\n generateKeyPair,\n importJWK,\n jwtVerify,\n SignJWT,\n type CryptoKey,\n type JWK,\n type JWTPayload,\n} from \"jose\";\n\n/**\n * How the fake encrypts what it issues to a client, as Authio does once the client registered an encryption key.\n */\nexport interface FakeAuthioClientEncryption {\n /** The client's public encryption key (RSA). */\n key: JWK;\n /** Defaults to `RSA-OAEP-256`. */\n algorithm?: \"RSA-OAEP\" | \"RSA-OAEP-256\";\n /** Defaults to `A256CBC-HS512`. */\n encryptionMethod?: \"A128CBC-HS256\" | \"A192CBC-HS384\" | \"A256CBC-HS512\";\n /** Encrypts the client's access tokens (nested JWT). */\n accessTokens?: boolean;\n /** Encrypts the client's ID tokens. Defaults to `true`. */\n idTokens?: boolean;\n /** Encrypts UserInfo answered as a JWT. Defaults to `true`. */\n userInfo?: boolean;\n /** Encrypts back-channel logout tokens. */\n logoutTokens?: boolean;\n}\n\n/**\n * How a client authenticates to the token, introspection, revocation and device endpoints, as registered in Authio.\n */\nexport type FakeAuthioTokenEndpointAuthMethod = \"client_secret_basic\" | \"client_secret_post\" | \"private_key_jwt\" | \"none\";\n\n/**\n * The algorithm Authio signs every token of a client with: the realm's RSA key, or the client secret (HS*).\n */\nexport type FakeAuthioSigningAlgorithm = \"RS256\" | \"HS256\" | \"HS384\" | \"HS512\";\n\n/**\n * A client registered in the fake, configured as a client is in Authio's console. What the client requires is\n * enforced as Authio enforces it: a request that does not match is refused with an error naming the setting, and\n * what the client does not require is accepted (PKCE sent voluntarily, a secret sent by a public client).\n */\nexport interface FakeAuthioClient {\n clientId: string;\n /** For `client_secret_basic` and `client_secret_post`, and the key of HS* signatures. */\n clientSecret?: string;\n /** The public JWK `private_key_jwt` assertions are verified with. */\n publicKey?: JWK;\n /**\n * How the client must authenticate; another method is refused with `invalid_client`, except a secret sent by a\n * `none` client, which is ignored. Defaults to `client_secret_basic` with a `clientSecret`, `private_key_jwt` with\n * only a `publicKey`, and `none` with neither.\n */\n tokenEndpointAuthMethod?: FakeAuthioTokenEndpointAuthMethod;\n /**\n * Refuses an authorization request without `code_challenge` (Authio's \"PKCE\" switch). Defaults to `true`, as Authio\n * creates clients; set `false` for a client with PKCE off.\n */\n requirePkce?: boolean;\n /**\n * The PKCE methods accepted, required or not: a `code_challenge` with another method is refused. Defaults to\n * `[\"S256\"]`, as Authio creates clients.\n */\n pkceMethods?: (\"S256\" | \"plain\")[];\n /**\n * The algorithm the client's ID tokens, signed UserInfo and logout tokens are signed with. Defaults to `RS256`. HS*\n * needs a `clientSecret` of at least 32, 48 or 64 bytes (RFC 7518 §3.2), as Authio requires.\n */\n signingAlgorithm?: FakeAuthioSigningAlgorithm;\n /** The algorithm the client's access tokens are signed with, Authio's second setting. Defaults to `RS256`. */\n accessTokenSigningAlgorithm?: FakeAuthioSigningAlgorithm;\n /** Issues a new ID token with every refresh. Defaults to `false`. */\n issueIdTokenOnRefresh?: boolean;\n /** Scopes granted when a request names none. */\n defaultScopes?: string[];\n /** Extra claims put into every access token issued to the client. */\n claims?: Record<string, unknown>;\n /** The client this one's tokens are introspectable by, besides itself (a resource server's introspection client). */\n introspectionClients?: string[];\n /** The redirect URIs the authorization endpoint accepts. Any when absent. */\n redirectUris?: string[];\n /** The post-logout redirect URIs the end-session endpoint accepts. Any when absent. */\n postLogoutRedirectUris?: string[];\n /** Where back-channel logout tokens are posted when a session of the client ends. */\n backchannelLogoutUri?: string;\n /** The page loaded (here: fetched) when a session of the client ends (front-channel logout). */\n frontchannelLogoutUri?: string;\n /** Adds `iss` and `sid` to the front-channel logout URI. Defaults to `false`. */\n frontchannelLogoutSessionRequired?: boolean;\n /** Encrypts what is issued to the client. */\n encryption?: FakeAuthioClientEncryption;\n}\n\n/**\n * A person the fake knows, for the password grant, authorization codes and UserInfo.\n */\nexport interface FakeAuthioUser {\n sub: string;\n username: string;\n password?: string;\n /** Claims put into the person's access tokens: `*_resource_access`, `org_id`, mapper claims… */\n claims?: Record<string, unknown>;\n /** What UserInfo answers besides `sub`. */\n userInfo?: Record<string, unknown>;\n /** The sign-in's methods. Defaults to `[\"pwd\"]`. */\n amr?: string[];\n /** The sign-in's level. Defaults to `1`, or the `acr_values` asked for. */\n acr?: string;\n}\n\n/**\n * A personal access token the fake accepts with the `personal_access_token` grant.\n */\nexport interface FakeAuthioPersonalAccessToken {\n /** The `pat_…` value. */\n token: string;\n /** The credential's id, the token's `sub`. */\n sub: string;\n /** The consumer's client, for a consumer's token; the `authio` client of an account otherwise. */\n clientId?: string;\n /** Claims added to the access token. */\n claims?: Record<string, unknown>;\n}\n\n/**\n * An error the fake answers a request with.\n */\nexport interface FakeAuthioError {\n status: number;\n body?: Record<string, unknown>;\n headers?: Record<string, string>;\n}\n\n/**\n * A request the fake received.\n */\nexport interface FakeAuthioRecordedRequest {\n method: string;\n path: string;\n headers: Record<string, string>;\n form: Record<string, string>;\n /** The query parameters. */\n query: Record<string, string>;\n /** The client the request authenticated as, when it did. */\n clientId?: string;\n}\n\n/**\n * A back-channel logout token the fake posted to a client.\n */\nexport interface FakeAuthioBackchannelDelivery {\n clientId: string;\n uri: string;\n logoutToken: string;\n /** The HTTP status the client answered, or 0 when it could not be reached. */\n status: number;\n}\n\n/**\n * A front-channel logout page the fake loaded for a client.\n */\nexport interface FakeAuthioFrontchannelDelivery {\n clientId: string;\n /** The URL loaded, with `iss` and `sid` when the client requires the session. */\n url: string;\n /** The HTTP status the client answered, or 0 when it could not be reached. */\n status: number;\n}\n\n/**\n * The parameters an authorization ended with, as the fake sent them back.\n */\nexport interface FakeAuthioAuthorizationOutcome {\n /** `code`, `state` and `iss`, or `error`, `error_description`, `state` and `iss`. */\n parameters: Record<string, string>;\n /** The redirect URI with the parameters, for `response_mode=query`. */\n callbackUrl: string | undefined;\n}\n\n/**\n * What the device flow answers to successive polls.\n */\nexport type FakeAuthioDeviceOutcome = \"pending\" | \"slow_down\" | \"approved\" | \"denied\" | \"expired\";\n\n/**\n * Options of the fake.\n */\nexport interface FakeAuthioOptions {\n /** The realm. Defaults to `fake`. */\n realm?: string;\n /** Seconds tokens live. Defaults to 300. */\n accessTokenLifetime?: number;\n clients?: FakeAuthioClient[];\n users?: FakeAuthioUser[];\n personalAccessTokens?: FakeAuthioPersonalAccessToken[];\n /**\n * The clock tokens are issued and checked with (milliseconds since the epoch), such as the `ManualClock` the\n * library under test uses. Defaults to the system clock.\n */\n clock?: { now(): number };\n}\n\n/**\n * Options of a token minted directly.\n */\nexport interface FakeAuthioTokenOptions {\n sub?: string;\n /** One or several audiences. Defaults to the client id. */\n audience?: string | string[];\n clientId?: string;\n scope?: string;\n /** Seconds. Negative values mint an expired token. */\n expiresIn?: number;\n /** The `typ` claim. Defaults to `Bearer`. */\n type?: string;\n /** Claims added to the payload. */\n claims?: Record<string, unknown>;\n /** Signs with another issuer. */\n issuer?: string;\n /** Signs with another key, so the signature does not verify. */\n untrusted?: boolean;\n /** Encrypts the token (nested JWT) to this public key, as Authio does for a client with an encryption key. */\n encryptTo?: { key: JWK; algorithm?: \"RSA-OAEP\" | \"RSA-OAEP-256\"; encryptionMethod?: string };\n}\n\ninterface IssuedToken {\n claims: JWTPayload;\n clientId: string;\n revoked: boolean;\n}\n\ninterface PendingCode {\n clientId: string;\n sub: string;\n redirectUri: string;\n scope?: string;\n codeVerifier?: string;\n codeChallenge?: string;\n codeChallengeMethod?: string;\n resource?: string;\n nonce?: string;\n sid?: string;\n authTime?: number;\n acr?: string;\n amr?: string[];\n}\n\ninterface FakeSession {\n sub: string;\n sid: string;\n authTime: number;\n acr: string;\n amr: string[];\n clients: Set<string>;\n}\n\ntype Endpoint = \"token\" | \"introspect\" | \"revoke\" | \"userinfo\" | \"device\" | \"discovery\" | \"authorize\" | \"logout\";\n\n/**\n * An in-memory Authio realm served over HTTP on loopback: discovery, JWKS, authorization (PKCE required or not and its\n * allowed methods, `state`, `nonce`, `prompt`, `max_age`, `acr_values`, `response_mode` query or web_message, RFC 9207\n * `iss`), token (client credentials, authorization code with ID tokens, refresh, token exchange, password, device code,\n * personal access token) with the client's exact authentication method, introspection, revocation, UserInfo, device\n * authorization, end session, back-channel and front-channel logout delivery, tokens signed RS256 or HS* with the\n * client secret, and JWE (RSA-OAEP, RSA-OAEP-256) for clients that registered an encryption key.\n */\nexport class FakeAuthio {\n /** Every request received, in order. */\n readonly requests: FakeAuthioRecordedRequest[] = [];\n /** Answers the next requests to an endpoint with these errors, in order, before answering normally. */\n readonly failures = new Map<Endpoint, FakeAuthioError[]>();\n /** Every back-channel logout token posted, in order. */\n readonly backchannelDeliveries: FakeAuthioBackchannelDelivery[] = [];\n /** Every front-channel logout page loaded, in order. */\n readonly frontchannelDeliveries: FakeAuthioFrontchannelDelivery[] = [];\n /** What successive device-code polls answer; the last value repeats. Defaults to `[\"approved\"]`. */\n deviceOutcomes: FakeAuthioDeviceOutcome[] = [\"approved\"];\n /** Overrides the discovery document's issuer, to test the mismatch check. */\n discoveryIssuer: string | undefined;\n /** Answers UserInfo as `application/jwt`, signed by the realm key (and encrypted for a client with a key). */\n userInfoAsJwt = false;\n /** Leaves `iss` out of authorization responses, to test the RFC 9207 check. */\n omitAuthorizationIssuer = false;\n /** Answers connected-account exchanges. Defaults to granting a token for the provider. */\n connectionResponder: ((form: Record<string, string>) => FakeAuthioError | Record<string, unknown>) | undefined;\n /** The person the authorization endpoint signs in when the request names none with `login_hint`. Defaults to the first user. */\n signInAs: string | undefined;\n\n private readonly clients = new Map<string, FakeAuthioClient>();\n private readonly users = new Map<string, FakeAuthioUser>();\n private readonly personalAccessTokens = new Map<string, FakeAuthioPersonalAccessToken>();\n private readonly codes = new Map<string, PendingCode>();\n private readonly refreshTokens = new Map<string, { clientId: string; sub: string; scope?: string; sid?: string; authTime?: number; expiresAt: number }>();\n private readonly issued = new Map<string, IssuedToken>();\n private readonly devicePolls = new Map<string, number>();\n private readonly lifetime: number;\n private readonly clock: { now(): number };\n private session: FakeSession | undefined;\n private server!: Server;\n private signingKey!: CryptoKey;\n private verificationKey!: CryptoKey;\n private untrustedKey!: CryptoKey;\n private publicJwk!: JWK;\n private baseUrl!: string;\n readonly realm: string;\n readonly keyId = \"fake-key-1\";\n\n private constructor(options: FakeAuthioOptions) {\n this.realm = options.realm ?? \"fake\";\n this.lifetime = options.accessTokenLifetime ?? 300;\n this.clock = options.clock ?? { now: () => Date.now() };\n\n for (const client of options.clients ?? []) this.clients.set(client.clientId, checkClient(client));\n for (const user of options.users ?? []) this.users.set(user.username, user);\n for (const pat of options.personalAccessTokens ?? []) this.personalAccessTokens.set(pat.token, pat);\n }\n\n /**\n * Starts the fake on a random loopback port.\n */\n static async start(options: FakeAuthioOptions = {}): Promise<FakeAuthio> {\n const fake = new FakeAuthio(options);\n\n await fake.listen();\n\n return fake;\n }\n\n /** `http://127.0.0.1:{port}`. */\n get authority(): string {\n return this.baseUrl;\n }\n\n /** `{authority}/realms/{realm}`. */\n get issuer(): string {\n return `${this.baseUrl}/realms/${this.realm}`;\n }\n\n /** The realm's public signing key. */\n get jwks(): { keys: JWK[] } {\n return { keys: [this.publicJwk] };\n }\n\n /** The session the authorization endpoint keeps (one browser), or `undefined` when nobody is signed in. */\n get currentSession(): { sub: string; sid: string; authTime: number } | undefined {\n return this.session ? { sub: this.session.sub, sid: this.session.sid, authTime: this.session.authTime } : undefined;\n }\n\n /** Registers a client. */\n addClient(client: FakeAuthioClient): void {\n this.clients.set(client.clientId, checkClient(client));\n }\n\n /** Registers a person. */\n addUser(user: FakeAuthioUser): void {\n this.users.set(user.username, user);\n }\n\n /** Registers a personal access token. */\n addPersonalAccessToken(token: FakeAuthioPersonalAccessToken): void {\n this.personalAccessTokens.set(token.token, token);\n }\n\n /** Ends the signed-in session without notifying anyone, as if it expired. */\n endSession(): void {\n this.session = undefined;\n }\n\n /**\n * Registers an authorization code for a person, as the authorization endpoint would after sign-in.\n */\n createAuthorizationCode(options: { clientId: string; username: string; redirectUri: string; scope?: string; codeChallengeVerifier?: string; resource?: string; nonce?: string }): string {\n const user = this.requireUser(options.username);\n const code = randomUUID();\n\n this.codes.set(code, {\n clientId: options.clientId,\n sub: user.sub,\n redirectUri: options.redirectUri,\n scope: options.scope,\n codeVerifier: options.codeChallengeVerifier,\n resource: options.resource,\n nonce: options.nonce,\n });\n\n return code;\n }\n\n /**\n * Follows an authorization URL as a browser would, signing in `signInAs` (or the `login_hint`), and returns what\n * Authio sent back: the callback URL for `response_mode=query`, the posted message's parameters for `web_message`.\n */\n async authorize(authorizationUrl: string): Promise<FakeAuthioAuthorizationOutcome> {\n const response = await fetch(authorizationUrl, { redirect: \"manual\" });\n const location = response.headers.get(\"location\");\n\n if (location) {\n const callback = new URL(location);\n\n return { parameters: Object.fromEntries(callback.searchParams), callbackUrl: location };\n }\n\n const html = await response.text();\n const message = /data-authorization-response='([^']*)'/.exec(html)?.[1];\n\n if (!message) throw new Error(`The fake answered the authorization with HTTP ${response.status} and no response.`);\n\n return { parameters: JSON.parse(decodeURIComponent(message)) as Record<string, string>, callbackUrl: undefined };\n }\n\n /**\n * Mints an access token signed by the realm key, recorded so introspection and revocation know it.\n */\n async issueAccessToken(options: FakeAuthioTokenOptions = {}): Promise<string> {\n const now = this.nowSeconds();\n const clientId = options.clientId ?? \"fake-client\";\n const jti = randomUUID();\n const payload: JWTPayload = {\n typ: options.type ?? \"Bearer\",\n azp: clientId,\n client_id: clientId,\n ...(options.scope ? { scope: options.scope } : {}),\n ...(options.sub ? { sub: options.sub } : {}),\n ...options.claims,\n };\n const builder = new SignJWT(payload)\n .setIssuer(options.issuer ?? this.issuer)\n .setAudience(options.audience ?? clientId)\n .setIssuedAt(now)\n .setNotBefore(now)\n .setExpirationTime(now + (options.expiresIn ?? this.lifetime))\n .setJti(jti);\n const signed = options.untrusted\n ? await builder.setProtectedHeader({ alg: \"RS256\", kid: this.keyId, typ: \"JWT\" }).sign(this.untrustedKey)\n : await this.sign(builder, this.clients.get(clientId), \"JWT\", this.clients.get(clientId)?.accessTokenSigningAlgorithm ?? \"RS256\");\n const token = options.encryptTo ? await encryptTo(signed, options.encryptTo) : signed;\n\n this.issued.set(token, { claims: decodeJwt(signed), clientId, revoked: false });\n\n return token;\n }\n\n /**\n * Mints a back-channel logout token for a client, signed by the realm key. `overrides` replaces claims (`undefined`\n * removes one) and `type` the header `typ`, to build invalid ones in tests.\n */\n async createLogoutToken(options: { clientId: string; sub?: string; sid?: string; type?: string; overrides?: Record<string, unknown> }): Promise<string> {\n const now = this.nowSeconds();\n const payload: Record<string, unknown> = {\n iss: this.issuer,\n aud: options.clientId,\n iat: now,\n exp: now + 120,\n jti: randomUUID(),\n ...(options.sub ? { sub: options.sub } : {}),\n ...(options.sid ? { sid: options.sid } : {}),\n events: { \"http://schemas.openid.net/event/backchannel-logout\": {} },\n ...options.overrides,\n };\n\n for (const key of Object.keys(payload)) if (payload[key] === undefined) delete payload[key];\n\n const signed = await this.sign(new SignJWT(payload as JWTPayload), this.clients.get(options.clientId), options.type ?? \"logout+jwt\");\n const encryption = this.clients.get(options.clientId)?.encryption;\n\n return encryption?.logoutTokens ? encryptTo(signed, encryption) : signed;\n }\n\n /**\n * Posts a back-channel logout token to the client's `backchannelLogoutUri`, as Authio does when a session ends.\n *\n * @returns The HTTP status the client answered, or 0 when it could not be reached.\n */\n async deliverBackchannelLogout(clientId: string, options: { sub?: string; sid?: string } = {}): Promise<number> {\n const client = this.clients.get(clientId);\n\n if (!client?.backchannelLogoutUri) throw new Error(`The fake client ${clientId} has no backchannelLogoutUri.`);\n\n const logoutToken = await this.createLogoutToken({ clientId, sub: options.sub, sid: options.sid });\n let status = 0;\n\n try {\n const response = await fetch(client.backchannelLogoutUri, {\n method: \"POST\",\n headers: { \"content-type\": \"application/x-www-form-urlencoded\" },\n body: new URLSearchParams({ logout_token: logoutToken }).toString(),\n });\n\n status = response.status;\n await response.arrayBuffer();\n } catch {\n status = 0;\n }\n\n this.backchannelDeliveries.push({ clientId, uri: client.backchannelLogoutUri, logoutToken, status });\n\n return status;\n }\n\n /**\n * The front-channel logout URL of a client for a session: its `frontchannelLogoutUri`, with `iss` and `sid` when the\n * client requires the session.\n */\n frontchannelLogoutUrl(clientId: string, sid: string): string {\n const client = this.clients.get(clientId);\n\n if (!client?.frontchannelLogoutUri) throw new Error(`The fake client ${clientId} has no frontchannelLogoutUri.`);\n\n const url = new URL(client.frontchannelLogoutUri);\n\n if (client.frontchannelLogoutSessionRequired) {\n url.searchParams.set(\"iss\", this.issuer);\n url.searchParams.set(\"sid\", sid);\n }\n\n return url.toString();\n }\n\n /**\n * Loads the client's front-channel logout page, as the browser does in an iframe when Authio ends a session.\n *\n * @returns The HTTP status the client answered, or 0 when it could not be reached.\n */\n async deliverFrontchannelLogout(clientId: string, options: { sid: string; headers?: Record<string, string> }): Promise<number> {\n const url = this.frontchannelLogoutUrl(clientId, options.sid);\n let status = 0;\n\n try {\n const response = await fetch(url, { headers: options.headers, redirect: \"manual\" });\n\n status = response.status;\n await response.arrayBuffer();\n } catch {\n status = 0;\n }\n\n this.frontchannelDeliveries.push({ clientId, url, status });\n\n return status;\n }\n\n /** Marks a token revoked, as Authio would after a sign-out: an access token, or a refresh token, which is then forgotten. */\n revokeToken(token: string): void {\n const issued = this.issued.get(token);\n\n if (issued) issued.revoked = true;\n\n this.refreshTokens.delete(token);\n }\n\n /** Revokes every refresh token of a person, or of one Authio session (`sid`), as Authio does when a session ends. */\n revokeRefreshTokens(options: { sub?: string; sid?: string }): void {\n for (const [token, refresh] of this.refreshTokens)\n if ((options.sid !== undefined && refresh.sid === options.sid) || (options.sid === undefined && options.sub !== undefined && refresh.sub === options.sub))\n this.refreshTokens.delete(token);\n }\n\n /** Forgets the recorded requests. */\n clearRequests(): void {\n this.requests.length = 0;\n }\n\n /** The recorded requests to one endpoint path suffix, such as `/token`. */\n requestsTo(suffix: string): FakeAuthioRecordedRequest[] {\n return this.requests.filter((request) => request.path.endsWith(suffix));\n }\n\n /** Stops the server. */\n close(): Promise<void> {\n return new Promise((resolve, reject) => {\n this.server.closeAllConnections?.();\n this.server.close((error) => (error ? reject(error) : resolve()));\n });\n }\n\n private async listen(): Promise<void> {\n const pair = await generateKeyPair(\"RS256\", { extractable: true });\n const untrusted = await generateKeyPair(\"RS256\");\n\n this.signingKey = pair.privateKey;\n this.verificationKey = pair.publicKey;\n this.untrustedKey = untrusted.privateKey;\n this.publicJwk = { ...(await exportJWK(pair.publicKey)), kid: this.keyId, alg: \"RS256\", use: \"sig\" };\n this.server = createServer((request, response) => {\n this.handle(request, response).catch((error: unknown) => {\n send(response, { status: 500, body: { error: \"server_error\", error_description: String(error) } });\n });\n });\n\n await new Promise<void>((resolve) => this.server.listen(0, \"127.0.0.1\", resolve));\n\n this.baseUrl = `http://127.0.0.1:${(this.server.address() as AddressInfo).port}`;\n }\n\n private async handle(request: IncomingMessage, response: ServerResponse): Promise<void> {\n const url = new URL(request.url ?? \"/\", this.baseUrl);\n const body = await readBody(request);\n const form = Object.fromEntries(new URLSearchParams(request.headers[\"content-type\"]?.includes(\"form\") ? body : \"\"));\n const headers = Object.fromEntries(Object.entries(request.headers).map(([name, value]) => [name, Array.isArray(value) ? value.join(\", \") : (value ?? \"\")]));\n const query = Object.fromEntries(url.searchParams);\n const recorded: FakeAuthioRecordedRequest = { method: request.method ?? \"GET\", path: url.pathname, headers, form, query };\n\n this.requests.push(recorded);\n\n const prefix = `/realms/${this.realm}`;\n const path = url.pathname.startsWith(prefix) ? url.pathname.slice(prefix.length) : url.pathname;\n const endpoint = endpointOf(path);\n const failure = endpoint ? this.failures.get(endpoint)?.shift() : undefined;\n\n if (failure) return send(response, failure);\n\n switch (path) {\n case \"/.well-known/openid-configuration\":\n return send(response, { status: 200, body: this.discovery() });\n case \"/protocol/openid-connect/certs\":\n return send(response, { status: 200, body: this.jwks });\n case \"/protocol/openid-connect/auth\":\n return this.authorizeEndpoint(query, response);\n case \"/protocol/openid-connect/token\":\n return send(response, await this.token(recorded, form));\n case \"/protocol/openid-connect/token/introspect\":\n return send(response, await this.introspect(recorded, form));\n case \"/protocol/openid-connect/revoke\":\n return send(response, await this.revoke(recorded, form));\n case \"/protocol/openid-connect/userinfo\":\n return this.userInfo(headers, response);\n case \"/protocol/openid-connect/auth/device\":\n return send(response, await this.device(recorded, form));\n case \"/protocol/openid-connect/logout\":\n return this.endSessionEndpoint(query, response);\n default:\n return send(response, { status: 404, body: { error: \"not_found\" } });\n }\n }\n\n private discovery(): Record<string, unknown> {\n const base = `${this.issuer}/protocol/openid-connect`;\n\n return {\n issuer: this.discoveryIssuer ?? this.issuer,\n authorization_endpoint: `${base}/auth`,\n token_endpoint: `${base}/token`,\n introspection_endpoint: `${base}/token/introspect`,\n revocation_endpoint: `${base}/revoke`,\n userinfo_endpoint: `${base}/userinfo`,\n end_session_endpoint: `${base}/logout`,\n device_authorization_endpoint: `${base}/auth/device`,\n jwks_uri: `${base}/certs`,\n scopes_supported: [\"openid\", \"profile\", \"email\", \"phone\", \"roles\", \"offline_access\"],\n response_types_supported: [\"code\"],\n response_modes_supported: [\"query\", \"web_message\"],\n grant_types_supported: [\n \"authorization_code\",\n \"refresh_token\",\n \"client_credentials\",\n \"password\",\n \"urn:ietf:params:oauth:grant-type:device_code\",\n \"urn:ietf:params:oauth:grant-type:token-exchange\",\n \"personal_access_token\",\n ],\n subject_types_supported: [\"public\"],\n id_token_signing_alg_values_supported: [\"RS256\"],\n id_token_encryption_alg_values_supported: [\"RSA-OAEP\", \"RSA-OAEP-256\"],\n id_token_encryption_enc_values_supported: [\"A128CBC-HS256\", \"A192CBC-HS384\", \"A256CBC-HS512\"],\n userinfo_signing_alg_values_supported: [\"RS256\"],\n userinfo_encryption_alg_values_supported: [\"RSA-OAEP\", \"RSA-OAEP-256\"],\n userinfo_encryption_enc_values_supported: [\"A128CBC-HS256\", \"A192CBC-HS384\", \"A256CBC-HS512\"],\n token_endpoint_auth_methods_supported: [\"client_secret_basic\", \"client_secret_post\", \"private_key_jwt\", \"none\"],\n code_challenge_methods_supported: [\"S256\", \"plain\"],\n prompt_values_supported: [\"none\", \"login\", \"select_account\", \"consent\"],\n display_values_supported: [\"page\", \"popup\"],\n acr_values_supported: [\"1\", \"2\", \"3\"],\n backchannel_logout_supported: true,\n backchannel_logout_session_supported: true,\n frontchannel_logout_supported: true,\n frontchannel_logout_session_supported: true,\n authorization_response_iss_parameter_supported: !this.omitAuthorizationIssuer,\n };\n }\n\n private authorizeEndpoint(query: Record<string, string>, response: ServerResponse): void {\n const client = this.clients.get(query.client_id ?? \"\");\n\n if (!client) return send(response, { status: 400, body: { error: \"invalid_request\", error_description: \"Unknown client_id.\" } });\n if (!query.redirect_uri || (client.redirectUris && !client.redirectUris.includes(query.redirect_uri)))\n return send(response, { status: 400, body: { error: \"invalid_request\", error_description: \"The redirect_uri is not registered.\" } });\n\n const answer = (parameters: Record<string, string | undefined>) => {\n const values: Record<string, string> = {};\n\n for (const [name, value] of Object.entries({ ...parameters, state: query.state, iss: this.omitAuthorizationIssuer ? undefined : this.issuer }))\n if (value !== undefined) values[name] = value;\n\n if (query.response_mode === \"web_message\") {\n const message = encodeURIComponent(JSON.stringify(values));\n\n response.writeHead(200, { \"content-type\": \"text/html; charset=utf-8\" });\n response.end(\n `<!doctype html><html><body data-authorization-response='${message}'><script>window.opener&&window.opener.postMessage({type:\"authorization_response\",response:JSON.parse(decodeURIComponent(document.body.dataset.authorizationResponse))},${JSON.stringify(new URL(query.redirect_uri!).origin)});</script></body></html>`,\n );\n return;\n }\n\n const location = new URL(query.redirect_uri!);\n\n for (const [name, value] of Object.entries(values)) location.searchParams.set(name, value);\n\n response.writeHead(302, { location: location.toString() });\n response.end();\n };\n\n if (query.response_mode !== undefined && query.response_mode !== \"query\" && query.response_mode !== \"web_message\")\n return answer({ error: \"invalid_request\", error_description: `The response_mode '${query.response_mode}' is not supported: Authio answers with query or web_message.` });\n\n if (query.response_type !== \"code\") return answer({ error: \"unsupported_response_type\", error_description: \"Only code is supported.\" });\n\n const method = query.code_challenge ? query.code_challenge_method : undefined;\n const allowedMethods = client.pkceMethods ?? [\"S256\"];\n\n if (query.code_challenge) {\n if (!method)\n return answer({ error: \"invalid_request\", error_description: \"code_challenge_method is required with code_challenge: Authio does not assume plain.\" });\n if (method !== \"S256\" && method !== \"plain\") return answer({ error: \"invalid_request\", error_description: `The PKCE method '${method}' is not supported.` });\n if (!(allowedMethods as string[]).includes(method))\n return answer({\n error: \"invalid_request\",\n error_description: `The PKCE method '${method}' is not allowed for the client ${client.clientId}, which allows ${allowedMethods.join(\", \")} (codeChallengeMethod).`,\n });\n } else if (client.requirePkce ?? true) {\n return answer({\n error: \"invalid_request\",\n error_description: `The client ${client.clientId} requires PKCE: send code_challenge and code_challenge_method (checks: [\"pkce\"]).`,\n });\n }\n\n const prompts = (query.prompt ?? \"\").split(\" \").filter(Boolean);\n const now = this.nowSeconds();\n const maxAge = query.max_age !== undefined ? Number(query.max_age) : undefined;\n const tooOld = this.session !== undefined && maxAge !== undefined && now - this.session.authTime > maxAge;\n const requestedAcr = (query.acr_values ?? \"\").split(\" \").filter(Boolean).sort().at(-1);\n const weaker = this.session !== undefined && requestedAcr !== undefined && Number(this.session.acr) < Number(requestedAcr);\n\n if (prompts.includes(\"none\") && (!this.session || tooOld || weaker)) return answer({ error: \"login_required\", error_description: \"Nobody is signed in.\" });\n\n if (!this.session || prompts.includes(\"login\") || tooOld || weaker || (query.login_hint && this.users.get(query.login_hint)?.sub !== this.session.sub)) {\n const username = (query.login_hint && this.users.has(query.login_hint) ? query.login_hint : undefined) ?? this.signInAs ?? this.users.keys().next().value;\n const user = username ? this.users.get(username) : undefined;\n\n if (!user) return answer({ error: \"access_denied\", error_description: \"The fake has no user to sign in.\" });\n\n const acr = requestedAcr ?? user.acr ?? \"1\";\n\n this.session = {\n sub: user.sub,\n sid: randomUUID().replace(/-/g, \"\"),\n authTime: now,\n acr,\n amr: user.amr ?? (Number(acr) >= 2 ? [\"pwd\", \"otp\", \"mfa\"] : [\"pwd\"]),\n clients: new Set(),\n };\n }\n\n this.session.clients.add(client.clientId);\n\n const code = randomUUID();\n\n this.codes.set(code, {\n clientId: client.clientId,\n sub: this.session.sub,\n redirectUri: query.redirect_uri,\n scope: query.scope,\n codeChallenge: query.code_challenge,\n codeChallengeMethod: method,\n resource: query.resource,\n nonce: query.nonce,\n sid: this.session.sid,\n authTime: this.session.authTime,\n acr: this.session.acr,\n amr: this.session.amr,\n });\n\n answer({ code });\n }\n\n private async endSessionEndpoint(query: Record<string, string>, response: ServerResponse): Promise<void> {\n let clientId = query.client_id;\n\n if (query.id_token_hint) {\n try {\n const audience = [decodeJwt(query.id_token_hint).aud ?? []].flat()[0];\n const { payload } = await jwtVerify(query.id_token_hint, this.verificationKeyFor(audience ? this.clients.get(audience) : undefined, query.id_token_hint), {\n issuer: this.issuer,\n currentDate: new Date(this.clock.now()),\n });\n\n clientId ??= [payload.aud ?? []].flat()[0];\n } catch {\n return send(response, { status: 400, body: { error: \"invalid_request\", error_description: \"The id_token_hint is not valid.\" } });\n }\n }\n\n const client = clientId ? this.clients.get(clientId) : undefined;\n const redirect = query.post_logout_redirect_uri;\n\n if (redirect && (!client || (client.postLogoutRedirectUris && !client.postLogoutRedirectUris.includes(redirect))))\n return send(response, { status: 400, body: { error: \"invalid_request\", error_description: \"The post_logout_redirect_uri is not registered.\" } });\n\n const ended = this.session;\n\n this.session = undefined;\n\n if (ended) this.revokeRefreshTokens({ sid: ended.sid });\n\n if (ended)\n for (const id of ended.clients) {\n if (this.clients.get(id)?.backchannelLogoutUri) await this.deliverBackchannelLogout(id, { sub: ended.sub, sid: ended.sid });\n if (this.clients.get(id)?.frontchannelLogoutUri) await this.deliverFrontchannelLogout(id, { sid: ended.sid });\n }\n\n if (!redirect) {\n response.writeHead(200, { \"content-type\": \"text/html; charset=utf-8\" });\n response.end(\"<!doctype html><p>You are signed out.</p>\");\n return;\n }\n\n const location = new URL(redirect);\n\n if (query.state) location.searchParams.set(\"state\", query.state);\n\n response.writeHead(302, { location: location.toString() });\n response.end();\n }\n\n private async authenticate(recorded: FakeAuthioRecordedRequest, form: Record<string, string>): Promise<FakeAuthioClient | FakeAuthioError> {\n const invalid = (description: string): FakeAuthioError => ({ status: 401, body: { error: \"invalid_client\", error_description: description } });\n const authorization = recorded.headers.authorization;\n const basic = authorization?.startsWith(\"Basic \")\n ? Buffer.from(authorization.slice(6), \"base64\").toString(\"utf8\").split(\":\").map(decodeURIComponent)\n : undefined;\n const presented: FakeAuthioTokenEndpointAuthMethod = basic\n ? \"client_secret_basic\"\n : form.client_assertion\n ? \"private_key_jwt\"\n : form.client_secret !== undefined\n ? \"client_secret_post\"\n : \"none\";\n const client = this.clients.get((basic ? basic[0] : form.client_id) ?? \"\");\n\n if (!client) return invalid(\"Unknown client.\");\n if (form.client_assertion && form.client_secret !== undefined) return invalid(\"A client assertion and a client secret cannot be sent together.\");\n\n const registered = registeredMethodOf(client);\n\n if (presented !== registered && !(registered === \"none\" && (presented === \"client_secret_basic\" || presented === \"client_secret_post\")))\n return invalid(`The client ${client.clientId} authenticates with ${registered} (tokenEndpointAuthMethod), not ${presented}.`);\n\n switch (registered) {\n case \"client_secret_basic\":\n if (!client.clientSecret || client.clientSecret !== basic?.[1]) return invalid(\"The client credentials are wrong.\");\n break;\n case \"client_secret_post\":\n if (!client.clientSecret || client.clientSecret !== form.client_secret) return invalid(\"The client credentials are wrong.\");\n break;\n case \"private_key_jwt\": {\n if (!client.publicKey) return invalid(\"The client has no registered key.\");\n if (form.client_assertion_type !== \"urn:ietf:params:oauth:client-assertion-type:jwt-bearer\") return invalid(\"Wrong assertion type.\");\n\n try {\n const key = await importJWK(client.publicKey, client.publicKey.alg);\n const { payload } = await jwtVerify(form.client_assertion!, key, {\n issuer: client.clientId,\n subject: client.clientId,\n audience: this.issuer,\n currentDate: new Date(this.clock.now()),\n });\n\n if (!payload.jti) return invalid(\"The assertion has no jti.\");\n } catch (error) {\n return invalid(`The assertion does not verify: ${(error as Error).message}`);\n }\n break;\n }\n default:\n break;\n }\n\n recorded.clientId = client.clientId;\n\n return client;\n }\n\n private async token(recorded: FakeAuthioRecordedRequest, form: Record<string, string>): Promise<FakeAuthioError> {\n const grant = (error: string, description: string): FakeAuthioError => ({ status: 400, body: { error, error_description: description } });\n\n if (form.grant_type === \"personal_access_token\") {\n const pat = this.personalAccessTokens.get(form.client_secret ?? \"\");\n\n if (!pat || (form.client_id && pat.clientId && form.client_id !== pat.clientId))\n return { status: 401, body: { error: \"invalid_client\", error_description: \"The personal access token is not valid.\" } };\n\n const clientId = pat.clientId ?? \"authio\";\n\n recorded.clientId = clientId;\n\n return this.tokenAnswer(this.clients.get(clientId) ?? { clientId }, {\n sub: pat.sub,\n scope: form.scope,\n audience: form.resource,\n claims: { amr: \"personal_access_token\", actor_type: \"personal_access_token\", credential_id: pat.sub, ...pat.claims },\n });\n }\n\n const client = await this.authenticate(recorded, form);\n\n if (\"status\" in client) return client;\n\n const scope = form.scope ?? client.defaultScopes?.join(\" \");\n\n switch (form.grant_type) {\n case \"client_credentials\":\n return this.tokenAnswer(client, { sub: client.clientId, scope, audience: form.resource, claims: client.claims });\n case \"password\": {\n const user = this.users.get(form.username ?? \"\");\n\n if (!user || user.password !== form.password) return grant(\"invalid_grant\", \"Wrong username or password.\");\n\n return this.tokenAnswer(client, { sub: user.sub, scope, claims: { ...client.claims, ...user.claims, preferred_username: user.username } }, user);\n }\n case \"authorization_code\": {\n const code = this.codes.get(form.code ?? \"\");\n\n if (!code || code.clientId !== client.clientId || code.redirectUri !== form.redirect_uri) return grant(\"invalid_grant\", \"The code is not valid.\");\n if (code.codeVerifier && code.codeVerifier !== form.code_verifier) return grant(\"invalid_grant\", \"PKCE verification failed.\");\n if (code.codeChallenge && !form.code_verifier) return grant(\"invalid_grant\", \"code_verifier is required: the code was issued with a code_challenge.\");\n if (code.codeChallenge && !verifiesChallenge(form.code_verifier, code.codeChallenge, code.codeChallengeMethod ?? \"S256\"))\n return grant(\"invalid_grant\", \"PKCE verification failed.\");\n\n this.codes.delete(form.code!);\n\n const user = [...this.users.values()].find((candidate) => candidate.sub === code.sub)!;\n const signIn = code.sid\n ? { sid: code.sid, auth_time: code.authTime, acr: code.acr, amr: code.amr }\n : { auth_time: this.nowSeconds(), acr: user.acr ?? \"1\", amr: user.amr ?? [\"pwd\"] };\n\n return this.tokenAnswer(\n client,\n {\n sub: user.sub,\n scope: code.scope,\n audience: form.resource ?? code.resource,\n claims: { ...client.claims, ...user.claims, ...signIn, preferred_username: user.username },\n },\n user,\n undefined,\n { nonce: code.nonce, signIn },\n );\n }\n case \"refresh_token\": {\n const refresh = this.refreshTokens.get(form.refresh_token ?? \"\");\n\n if (!refresh || refresh.clientId !== client.clientId) return grant(\"invalid_grant\", \"The refresh token is not valid.\");\n\n this.refreshTokens.delete(form.refresh_token!);\n\n const user = [...this.users.values()].find((candidate) => candidate.sub === refresh.sub);\n const signIn = { ...(refresh.sid ? { sid: refresh.sid } : {}), ...(refresh.authTime ? { auth_time: refresh.authTime } : {}) };\n\n return this.tokenAnswer(\n client,\n { sub: refresh.sub, scope: form.scope ?? refresh.scope, claims: { ...client.claims, ...user?.claims, ...signIn } },\n user,\n undefined,\n client.issueIdTokenOnRefresh ? { signIn } : undefined,\n );\n }\n case \"urn:ietf:params:oauth:grant-type:token-exchange\": {\n const subject = this.issued.get(form.subject_token ?? \"\");\n\n if (!subject || subject.revoked) return grant(\"invalid_grant\", \"The subject token is not valid.\");\n\n if (form.requested_token_type === \"urn:authio:params:oauth:token-type:connection-access-token\") {\n const answer = this.connectionResponder?.(form) ?? {\n access_token: `provider-token-${form.connection_provider}`,\n issued_token_type: form.requested_token_type,\n token_type: \"Bearer\",\n expires_in: 3600,\n provider: form.connection_provider,\n };\n\n return \"status\" in answer && typeof answer.status === \"number\" ? (answer as FakeAuthioError) : { status: 200, body: answer as Record<string, unknown> };\n }\n\n const { iss: _issuer, aud: _audience, exp: _expiry, iat: _issuedAt, nbf: _notBefore, jti: _jti, scope: _scope, ...claims } = subject.claims;\n\n return this.tokenAnswer(client, {\n sub: subject.claims.sub,\n scope: form.scope ?? (subject.claims.scope as string | undefined),\n audience: form.resource,\n claims: { ...claims, act: { client_id: client.clientId } },\n }, undefined, form.requested_token_type);\n }\n case \"urn:ietf:params:oauth:grant-type:device_code\": {\n const polls = this.devicePolls.get(form.device_code ?? \"\");\n\n if (polls === undefined) return grant(\"invalid_grant\", \"Unknown device code.\");\n\n this.devicePolls.set(form.device_code!, polls + 1);\n\n const outcome = this.deviceOutcomes[Math.min(polls, this.deviceOutcomes.length - 1)] ?? \"approved\";\n\n switch (outcome) {\n case \"pending\":\n return grant(\"authorization_pending\", \"The user has not approved yet.\");\n case \"slow_down\":\n return grant(\"slow_down\", \"Poll less often.\");\n case \"denied\":\n return grant(\"access_denied\", \"The user denied the request.\");\n case \"expired\":\n return grant(\"expired_token\", \"The device code expired.\");\n default:\n return this.tokenAnswer(client, { sub: \"device-user\", scope, claims: client.claims });\n }\n }\n default:\n return grant(\"unsupported_grant_type\", `The grant ${form.grant_type} is not supported.`);\n }\n }\n\n private async tokenAnswer(\n client: FakeAuthioClient,\n options: { sub?: string; scope?: string; audience?: string; claims?: Record<string, unknown> },\n user?: FakeAuthioUser,\n issuedTokenType?: string,\n idToken?: { nonce?: string; signIn: Record<string, unknown> },\n ): Promise<FakeAuthioError> {\n const encryption = client.encryption;\n const accessToken = await this.issueAccessToken({\n clientId: client.clientId,\n sub: options.sub,\n scope: options.scope,\n audience: options.audience ?? client.clientId,\n claims: options.claims,\n ...(encryption?.accessTokens ? { encryptTo: encryption } : {}),\n });\n const body: Record<string, unknown> = {\n access_token: accessToken,\n token_type: \"Bearer\",\n expires_in: this.lifetime,\n ...(options.scope ? { scope: options.scope } : {}),\n ...(issuedTokenType ? { issued_token_type: issuedTokenType } : {}),\n };\n\n if (user) {\n const refreshToken = randomUUID();\n const sid = typeof options.claims?.sid === \"string\" ? options.claims.sid : undefined;\n const authTime = typeof options.claims?.auth_time === \"number\" ? options.claims.auth_time : undefined;\n\n this.refreshTokens.set(refreshToken, {\n clientId: client.clientId,\n sub: user.sub,\n scope: options.scope,\n sid,\n authTime,\n expiresAt: this.nowSeconds() + 30 * 24 * 3600,\n });\n body.refresh_token = refreshToken;\n }\n\n if (user && idToken && (options.scope ?? \"\").split(\" \").includes(\"openid\")) {\n const now = this.nowSeconds();\n const signIn = Object.fromEntries(Object.entries(idToken.signIn).filter(([, value]) => value !== undefined));\n const signed = await this.sign(\n new SignJWT({\n typ: \"ID\",\n azp: client.clientId,\n ...signIn,\n ...(idToken.nonce ? { nonce: idToken.nonce } : {}),\n at_hash: halfHash(accessToken, client.signingAlgorithm ?? \"RS256\"),\n preferred_username: user.username,\n ...user.userInfo,\n })\n .setIssuer(this.issuer)\n .setAudience(client.clientId)\n .setSubject(user.sub)\n .setIssuedAt(now)\n .setExpirationTime(now + this.lifetime),\n client,\n \"JWT\",\n );\n\n body.id_token = encryption && encryption.idTokens !== false ? await encryptTo(signed, encryption) : signed;\n }\n\n return { status: 200, body };\n }\n\n private async introspect(recorded: FakeAuthioRecordedRequest, form: Record<string, string>): Promise<FakeAuthioError> {\n const client = await this.authenticate(recorded, form);\n\n if (\"status\" in client) return client;\n\n const issued = this.issued.get(form.token ?? \"\");\n const now = this.nowSeconds();\n const refresh = this.refreshTokens.get(form.token ?? \"\");\n\n if (refresh)\n return refresh.clientId === client.clientId\n ? {\n status: 200,\n body: {\n active: true,\n token_type: \"Refresh\",\n client_id: refresh.clientId,\n sub: refresh.sub,\n exp: refresh.expiresAt,\n ...(refresh.scope ? { scope: refresh.scope } : {}),\n ...(refresh.sid ? { sid: refresh.sid } : {}),\n },\n }\n : { status: 200, body: { active: false } };\n\n if (!issued || issued.revoked || (issued.claims.exp ?? 0) <= now) return { status: 200, body: { active: false } };\n\n const audiences = [issued.claims.aud ?? []].flat();\n const allowed =\n issued.clientId === client.clientId && audiences.includes(client.clientId)\n ? true\n : audiences.some((audience) => this.clients.get(audience)?.introspectionClients?.includes(client.clientId) || audience === client.clientId);\n\n if (!allowed) return { status: 200, body: { active: false } };\n\n const { typ, ...claims } = issued.claims;\n\n return { status: 200, body: { active: true, token_type: typ ?? \"Bearer\", username: claims.preferred_username, ...claims } };\n }\n\n private async revoke(recorded: FakeAuthioRecordedRequest, form: Record<string, string>): Promise<FakeAuthioError> {\n const client = await this.authenticate(recorded, form);\n\n if (\"status\" in client) return client;\n\n this.revokeToken(form.token ?? \"\");\n this.refreshTokens.delete(form.token ?? \"\");\n\n return { status: 200 };\n }\n\n private async device(recorded: FakeAuthioRecordedRequest, form: Record<string, string>): Promise<FakeAuthioError> {\n const client = await this.authenticate(recorded, form);\n\n if (\"status\" in client) return client;\n\n const deviceCode = randomUUID();\n\n this.devicePolls.set(deviceCode, 0);\n\n return {\n status: 200,\n body: {\n device_code: deviceCode,\n user_code: \"WDJB-MJHT\",\n verification_uri: `${this.issuer}/device`,\n verification_uri_complete: `${this.issuer}/device?user_code=WDJB-MJHT`,\n expires_in: 600,\n interval: 5,\n },\n };\n }\n\n private async userInfo(headers: Record<string, string>, response: ServerResponse): Promise<void> {\n const token = headers.authorization?.replace(/^Bearer\\s+/i, \"\");\n const issued = token ? this.issued.get(token) : undefined;\n\n if (!issued || issued.revoked)\n return send(response, {\n status: 401,\n headers: { \"www-authenticate\": 'Bearer error=\"invalid_token\", error_description=\"The access token is not valid.\"' },\n });\n\n const user = [...this.users.values()].find((candidate) => candidate.sub === issued.claims.sub);\n const claims = { sub: issued.claims.sub, ...user?.userInfo };\n\n if (!this.userInfoAsJwt) return send(response, { status: 200, body: claims });\n\n const now = this.nowSeconds();\n const signed = await this.sign(\n new SignJWT(claims).setIssuer(this.issuer).setAudience(issued.clientId).setIssuedAt(now).setExpirationTime(now + this.lifetime),\n this.clients.get(issued.clientId),\n undefined,\n );\n const encryption = this.clients.get(issued.clientId)?.encryption;\n const jwt = encryption && encryption.userInfo !== false ? await encryptTo(signed, encryption) : signed;\n\n response.writeHead(200, { \"content-type\": \"application/jwt\" });\n response.end(jwt);\n }\n\n private nowSeconds(): number {\n return Math.floor(this.clock.now() / 1000);\n }\n\n private sign(builder: SignJWT, client: FakeAuthioClient | undefined, type: string | undefined, algorithm = client?.signingAlgorithm ?? \"RS256\"): Promise<string> {\n if (algorithm === \"RS256\") return builder.setProtectedHeader({ alg: \"RS256\", kid: this.keyId, ...(type ? { typ: type } : {}) }).sign(this.signingKey);\n if (!client?.clientSecret) throw new Error(`The fake client ${client?.clientId} signs with ${algorithm} and has no clientSecret.`);\n\n return builder.setProtectedHeader({ alg: algorithm, ...(type ? { typ: type } : {}) }).sign(new TextEncoder().encode(client.clientSecret));\n }\n\n private verificationKeyFor(client: FakeAuthioClient | undefined, token: string): CryptoKey | Uint8Array {\n const algorithm = String(decodeProtectedHeader(token).alg ?? \"\");\n\n return algorithm.startsWith(\"HS\") && client?.clientSecret ? new TextEncoder().encode(client.clientSecret) : this.verificationKey;\n }\n\n private requireUser(username: string): FakeAuthioUser {\n const user = this.users.get(username);\n\n if (!user) throw new Error(`The fake has no user ${username}.`);\n\n return user;\n }\n}\n\nfunction endpointOf(path: string): Endpoint | undefined {\n if (path.endsWith(\"/token\")) return \"token\";\n if (path.endsWith(\"/introspect\")) return \"introspect\";\n if (path.endsWith(\"/revoke\")) return \"revoke\";\n if (path.endsWith(\"/userinfo\")) return \"userinfo\";\n if (path.endsWith(\"/auth/device\")) return \"device\";\n if (path.endsWith(\"/openid-configuration\")) return \"discovery\";\n if (path.endsWith(\"/auth\")) return \"authorize\";\n if (path.endsWith(\"/logout\")) return \"logout\";\n return undefined;\n}\n\nasync function encryptTo(signed: string, encryption: { key: JWK; algorithm?: string; encryptionMethod?: string }): Promise<string> {\n const algorithm = encryption.algorithm ?? \"RSA-OAEP-256\";\n const key = await importJWK({ ...encryption.key, alg: algorithm, use: \"enc\", key_ops: undefined }, algorithm);\n\n return new CompactEncrypt(new TextEncoder().encode(signed))\n .setProtectedHeader({ alg: algorithm, enc: encryption.encryptionMethod ?? \"A256CBC-HS512\", typ: \"JWE\", cty: \"JWT\", ...(encryption.key.kid ? { kid: encryption.key.kid } : {}) })\n .encrypt(key);\n}\n\nfunction verifiesChallenge(verifier: string | undefined, challenge: string, method: string): boolean {\n if (!verifier) return false;\n\n return method === \"S256\" ? createHash(\"sha256\").update(verifier, \"ascii\").digest(\"base64url\") === challenge : verifier === challenge;\n}\n\nfunction halfHash(value: string, algorithm: string): string {\n const size = algorithm.endsWith(\"384\") ? 384 : algorithm.endsWith(\"512\") ? 512 : 256;\n const digest = createHash(`sha${size}`).update(value, \"ascii\").digest();\n\n return digest.subarray(0, digest.length / 2).toString(\"base64url\");\n}\n\nfunction checkClient(client: FakeAuthioClient): FakeAuthioClient {\n for (const algorithm of [client.signingAlgorithm ?? \"RS256\", client.accessTokenSigningAlgorithm ?? \"RS256\"]) {\n const minimum = { HS256: 32, HS384: 48, HS512: 64 }[algorithm as \"HS256\"];\n\n if (minimum !== undefined && Buffer.byteLength(client.clientSecret ?? \"\", \"utf8\") < minimum)\n throw new Error(`The fake client ${client.clientId} signs with ${algorithm}, which needs a clientSecret of at least ${minimum} bytes (RFC 7518 §3.2).`);\n }\n\n return client;\n}\n\nfunction registeredMethodOf(client: FakeAuthioClient): FakeAuthioTokenEndpointAuthMethod {\n return client.tokenEndpointAuthMethod ?? (client.clientSecret ? \"client_secret_basic\" : client.publicKey ? \"private_key_jwt\" : \"none\");\n}\n\nfunction send(response: ServerResponse, answer: FakeAuthioError): void {\n const headers: Record<string, string> = { ...answer.headers };\n\n if (answer.body !== undefined) headers[\"content-type\"] ??= \"application/json\";\n\n response.writeHead(answer.status, headers);\n response.end(answer.body === undefined ? undefined : JSON.stringify(answer.body));\n}\n\nfunction readBody(request: IncomingMessage): Promise<string> {\n return new Promise((resolve, reject) => {\n const chunks: Buffer[] = [];\n\n request.on(\"data\", (chunk: Buffer) => chunks.push(chunk));\n request.on(\"end\", () => resolve(Buffer.concat(chunks).toString(\"utf8\")));\n request.on(\"error\", reject);\n });\n}\n","import type { AuthioClock } from \"@hyper.authio/client\";\n\n/**\n * A clock that moves only when told to. `sleep` returns at once and moves the clock forward by the time asked, so\n * device polling and cache expiry run instantly and deterministically.\n */\nexport class ManualClock implements AuthioClock {\n /** Every `sleep` asked for, in milliseconds. */\n readonly sleeps: number[] = [];\n private time: number;\n\n /**\n * @param start Milliseconds since the epoch. Defaults to the current time.\n */\n constructor(start: number = Date.now()) {\n this.time = start;\n }\n\n now(): number {\n return this.time;\n }\n\n sleep(ms: number, signal?: AbortSignal): Promise<void> {\n if (signal?.aborted) return Promise.reject(signal.reason);\n\n this.sleeps.push(ms);\n this.time += ms;\n\n return Promise.resolve();\n }\n\n /** Moves the clock forward. */\n advance(ms: number): void {\n this.time += ms;\n }\n\n /** Sets the clock. */\n set(ms: number): void {\n this.time = ms;\n }\n}\n","import { randomUUID } from \"node:crypto\";\nimport { AuthioWebhookHeaders, computeWebhookSignatureHeader } from \"@hyper.authio/client\";\n\n/**\n * A webhook delivery as Authio would send it.\n */\nexport interface FakeWebhookDelivery {\n readonly body: string;\n readonly headers: Record<string, string>;\n readonly event: Record<string, unknown>;\n}\n\n/**\n * Builds a signed webhook delivery.\n *\n * @param type The event type.\n * @param data The event data.\n * @param secret The webhook secret.\n * @param options `id`, `timestamp` (milliseconds) and extra event members.\n */\nexport async function createWebhookDelivery(\n type: string,\n data: unknown,\n secret: string,\n options: { id?: string; timestamp?: number; realmId?: string; clientId?: string; sendEventIdHeader?: boolean } = {},\n): Promise<FakeWebhookDelivery> {\n const timestamp = options.timestamp ?? Date.now();\n const id = options.id ?? randomUUID();\n const event = {\n id,\n type,\n created_at: Math.floor(timestamp / 1000),\n ...(options.realmId ? { realm_id: options.realmId } : {}),\n ...(options.clientId ? { client_id: options.clientId } : {}),\n data,\n };\n const body = JSON.stringify(event);\n const headers: Record<string, string> = {\n \"content-type\": \"application/json\",\n [AuthioWebhookHeaders.Signature]: await computeWebhookSignatureHeader(body, secret, timestamp),\n [AuthioWebhookHeaders.Event]: type,\n };\n\n if (options.sendEventIdHeader ?? true) headers[AuthioWebhookHeaders.EventId] = id;\n\n return { body, headers, event };\n}\n"]}
|