/**
 * OAuth 2.1 authorization-server HTTP handlers for mailpouch.
 *
 * Implements the surface required by the 2025-11-25 MCP spec for an
 * authenticated remote deployment:
 *
 *   GET  /.well-known/oauth-authorization-server  — RFC 8414 metadata
 *   GET  /.well-known/oauth-protected-resource    — RFC 9728 metadata
 *   POST /oauth/register                          — RFC 7591 DCR
 *   GET  /oauth/authorize                         — auto-consent → 302 with code
 *   POST /oauth/token                             — code exchange (PKCE)
 *   POST /oauth/revoke                            — token revocation
 *
 * Authorize is fully automatic (no admin password, no consent form): a valid
 * request — known client_id, allowlisted redirect_uri, PKCE S256 challenge —
 * immediately issues a code and 302-redirects. The human gate is NOT here; it
 * is the per-agent grant Approve/Deny in the Agents tab. The issued token is
 * inert until that grant is approved, and a pending request self-expires after
 * 5 minutes if not approved. PKCE binds the code to the agent's verifier, the
 * redirect_uri is allowlisted, and every endpoint is rate-limited (per IP).
 */
import type { IncomingMessage, ServerResponse } from "http";
import { OAuthStore } from "./oauth-store.js";
import { TokenBucketLimiter } from "./rate-limit.js";
/**
 * Strip control characters / ANSI escapes and length-cap a DCR-supplied
 * client_name (XPORT-002 from the 2026-05-28 audit). Exported for tests
 * — production callers go through `handleRegister` which uses it inline.
 * Returns undefined for empty/missing input so the consent page falls
 * back to "(unnamed client)" rather than rendering an empty string.
 */
export declare function sanitizeDcrClientName(raw: string | undefined): string | undefined;
export interface OAuthEndpointsConfig {
    /** Externally-visible base URL of the server, e.g. https://mcp.example.com. */
    issuer: string;
    /** Absolute URL for the /mcp endpoint — used in oauth-protected-resource. */
    resource: string;
}
export interface OAuthHandlerResult {
    /** True when the handler has already written a response. */
    handled: boolean;
}
export declare class OAuthHandlers {
    private readonly store;
    private readonly cfg;
    private readonly limiter;
    private readonly onClientRegistered?;
    /** Extracts the caller IP from a request (injected to avoid importing http.ts
     *  here, which would create an import cycle). */
    private readonly ipExtractor?;
    /** Verifies a service-account client_id + client_secret for the
     *  client_credentials grant. Returns true when the pair is valid. Injected so
     *  this module stays free of the agents-layer import. When absent, the
     *  client_credentials grant is rejected (deployment issued no service accounts). */
    private readonly verifyClientCredentials?;
    constructor(store: OAuthStore, cfg: OAuthEndpointsConfig, limiter: TokenBucketLimiter, onClientRegistered?: (c: {
        client_id: string;
        client_name?: string;
        ip?: string;
    }) => void, ipExtractor?: (req: IncomingMessage) => string, verifyClientCredentials?: (clientId: string, secret: string) => boolean);
    /**
     * XPORT-008: reject state-changing POSTs whose Origin is cross-site. The
     * consent form is same-origin (`form-action 'self'`); a present Origin that
     * doesn't match the issuer means a cross-site submission. A missing Origin is
     * allowed through (some same-origin form posts omit it) — the CSRF token is
     * the primary defence; the Origin check is belt-and-suspenders.
     */
    private originAllowed;
    /**
     * Dispatch an HTTP request to the right OAuth endpoint. Returns
     * `{ handled: true }` when we owned the response; false lets the caller
     * fall through to the MCP endpoint.
     */
    dispatch(req: IncomingMessage, res: ServerResponse, url: URL): Promise<OAuthHandlerResult>;
    /** RFC 8414 §3 — Authorization Server Metadata. */
    private serveAuthServerMetadata;
    /** RFC 9728 — Protected Resource Metadata. */
    private serveProtectedResourceMetadata;
    /** RFC 7591 Dynamic Client Registration. Public, no secret issued. */
    private handleRegister;
    /** Consent page — returns a small HTML form rather than a redirect. */
    private handleAuthorizeGet;
    /** Token endpoint — exchanges auth code for access token under PKCE. */
    private handleToken;
    /**
     * RFC 6749 §4.4 client_credentials grant — the non-interactive login path for
     * service accounts (cron/headless agents). The client authenticates with its
     * own client_id + client_secret (HTTP Basic per §2.3.1, or form body); on a
     * verified pair we issue an access token bound to that client_id. No PKCE, no
     * authorization code, no interactive consent — the agent was pre-approved at
     * issuance (an active grant already exists), so GrantManager still gates every
     * tool call exactly as for an interactively-approved agent.
     */
    private handleClientCredentials;
    private handleRevoke;
}
//# sourceMappingURL=oauth-handlers.d.ts.map