/** * Dynamic Client Registration — POST /oauth/register * * Who calls: Developers/automation. * * Purpose: Let clients register programmatically (redirect URIs, grant types, etc.). */ /** * Quick checklist (security & correctness) * - PKCE (S256) required for public clients (and basically for all). * - Use authorization code grant only (no implicit/hybrid). * - Rotate refresh tokens and bind them to client + user + scopes. * - Prefer private_key_jwt or mTLS for confidential clients. * - PAR + JAR recommended for higher security. * - Consider DPoP (proof-of-possession) to reduce token replay. * - Keep codes very short-lived (e.g., ≤60 s) and single-use. * - Publish discovery and JWKS, rotate keys safely. * - Decide JWT vs opaque access tokens; provide introspection if opaque. */ import { FlowBase, FlowRunOptions } from "@frontmcp/sdk"; import { z } from "zod"; /** Simple in-memory registry (dev only) */ type RegisteredClient = { client_id: string; client_secret?: string; token_endpoint_auth_method: "none" | "client_secret_basic" | "client_secret_post" | "private_key_jwt" | "tls_client_auth"; grant_types: string[]; response_types: string[]; redirect_uris: string[]; client_name?: string; scope?: string; created_at: number; dev: boolean; }; /** Optional: export getters so other flows can validate client_id */ export declare const DevClientRegistry: { get(client_id: string): RegisteredClient | undefined; has(client_id: string): boolean; }; declare const inputSchema: z.ZodObject<{ request: z.ZodObject<{}, "passthrough", z.ZodTypeAny, z.objectOutputType<{}, z.ZodTypeAny, "passthrough">, z.objectInputType<{}, z.ZodTypeAny, "passthrough">>; response: z.ZodObject<{}, "passthrough", z.ZodTypeAny, z.objectOutputType<{}, z.ZodTypeAny, "passthrough">, z.objectInputType<{}, z.ZodTypeAny, "passthrough">>; next: z.ZodOptional, z.ZodUnknown>>; }, "strip", z.ZodTypeAny, { request: {} & { [k: string]: unknown; }; response: {} & { [k: string]: unknown; }; next?: ((...args: unknown[]) => unknown) | undefined; }, { request: {} & { [k: string]: unknown; }; response: {} & { [k: string]: unknown; }; next?: ((...args: unknown[]) => unknown) | undefined; }>; declare const outputSchema: z.ZodObject<{ kind: z.ZodLiteral<"json">; status: z.ZodEffects; body: z.ZodUnion<[z.ZodObject<{}, "passthrough", z.ZodTypeAny, z.objectOutputType<{}, z.ZodTypeAny, "passthrough">, z.objectInputType<{}, z.ZodTypeAny, "passthrough">>, z.ZodArray, z.ZodRecord]>; contentType: z.ZodDefault; } & { headers: z.ZodOptional]>]>>>>; cookies: z.ZodOptional; domain: z.ZodOptional; httpOnly: z.ZodDefault; secure: z.ZodOptional; sameSite: z.ZodOptional>; maxAge: z.ZodOptional; expires: z.ZodOptional; }, "strip", z.ZodTypeAny, { name: string; value: string; path: string; httpOnly: boolean; domain?: string | undefined; secure?: boolean | undefined; sameSite?: "lax" | "strict" | "none" | undefined; maxAge?: number | undefined; expires?: Date | undefined; }, { name: string; value: string; path?: string | undefined; domain?: string | undefined; httpOnly?: boolean | undefined; secure?: boolean | undefined; sameSite?: "lax" | "strict" | "none" | undefined; maxAge?: number | undefined; expires?: Date | undefined; }>, "many">>>; }, "strip", z.ZodTypeAny, { status: number; kind: "json"; body: any[] | z.objectOutputType<{}, z.ZodTypeAny, "passthrough"> | Record; contentType: string; headers?: Record | undefined; cookies?: { name: string; value: string; path: string; httpOnly: boolean; domain?: string | undefined; secure?: boolean | undefined; sameSite?: "lax" | "strict" | "none" | undefined; maxAge?: number | undefined; expires?: Date | undefined; }[] | undefined; }, { status: number; kind: "json"; body: any[] | z.objectInputType<{}, z.ZodTypeAny, "passthrough"> | Record; headers?: Record | undefined; cookies?: { name: string; value: string; path?: string | undefined; domain?: string | undefined; httpOnly?: boolean | undefined; secure?: boolean | undefined; sameSite?: "lax" | "strict" | "none" | undefined; maxAge?: number | undefined; expires?: Date | undefined; }[] | undefined; contentType?: string | undefined; }>; declare const stateSchema: z.ZodObject<{ body: z.ZodObject<{ redirect_uris: z.ZodArray; token_endpoint_auth_method: z.ZodDefault>; grant_types: z.ZodDefault, "many">>; response_types: z.ZodDefault, "many">>; client_name: z.ZodOptional; scope: z.ZodOptional; }, "passthrough", z.ZodTypeAny, z.objectOutputType<{ redirect_uris: z.ZodArray; token_endpoint_auth_method: z.ZodDefault>; grant_types: z.ZodDefault, "many">>; response_types: z.ZodDefault, "many">>; client_name: z.ZodOptional; scope: z.ZodOptional; }, z.ZodTypeAny, "passthrough">, z.objectInputType<{ redirect_uris: z.ZodArray; token_endpoint_auth_method: z.ZodDefault>; grant_types: z.ZodDefault, "many">>; response_types: z.ZodDefault, "many">>; client_name: z.ZodOptional; scope: z.ZodOptional; }, z.ZodTypeAny, "passthrough">>; isDev: z.ZodBoolean; }, "strip", z.ZodTypeAny, { body: { redirect_uris: string[]; token_endpoint_auth_method: "client_secret_basic" | "client_secret_post" | "private_key_jwt" | "none" | "tls_client_auth"; grant_types: ("authorization_code" | "refresh_token" | "urn:ietf:params:oauth:grant-type:device_code")[]; response_types: "code"[]; scope?: string | undefined; client_name?: string | undefined; } & { [k: string]: unknown; }; isDev: boolean; }, { body: { redirect_uris: string[]; scope?: string | undefined; token_endpoint_auth_method?: "client_secret_basic" | "client_secret_post" | "private_key_jwt" | "none" | "tls_client_auth" | undefined; grant_types?: ("authorization_code" | "refresh_token" | "urn:ietf:params:oauth:grant-type:device_code")[] | undefined; response_types?: "code"[] | undefined; client_name?: string | undefined; } & { [k: string]: unknown; }; isDev: boolean; }>; declare const plan: { readonly pre: ["parseInput", "validateInput"]; readonly execute: ["registerClient", "respondRegistration"]; readonly post: ["validateOutput"]; }; declare global { export interface ExtendFlows { 'oauth:register': FlowRunOptions; } } declare const name: "oauth:register"; export default class OauthRegisterFlow extends FlowBase { private registered?; parseInput(): Promise; validateInput(): Promise; registerClient(): Promise; respondRegistration(): Promise; validateOutput(): Promise; } export {};