/**
 * In-memory stores for the OAuth 2.1 authorization server.
 *
 * All state is process-local — matching mailpouch's single-user design.
 * A restart drops outstanding auth codes (short TTL anyway) and tokens
 * (requiring clients to re-auth); registered DCR clients are re-provisioned
 * on demand because MCP hosts will call the register endpoint again.
 *
 * Rationale for not persisting to disk:
 *   - Keeps the attack surface small (no on-disk tokens to leak).
 *   - Tokens in this deployment are long-lived enough for an interactive
 *     session but re-issue is cheap.
 *   - Persistence is a follow-up PR when we tackle multi-instance or
 *     survivable restarts.
 */
export interface RegisteredClient {
    client_id: string;
    client_id_issued_at: number;
    client_name?: string;
    redirect_uris: string[];
    grant_types: string[];
    response_types: string[];
    token_endpoint_auth_method: string;
    scope?: string;
    client_secret?: string;
    client_secret_expires_at?: number;
}
export interface PendingAuth {
    code: string;
    clientId: string;
    redirectUri: string;
    codeChallenge: string;
    codeChallengeMethod: "S256" | "plain";
    scopes: string[];
    resource?: string;
    state?: string;
    /** ms since epoch. Codes expire after OAUTH_CODE_TTL_MS. */
    createdAt: number;
}
export interface IssuedToken {
    token: string;
    clientId: string;
    scopes: string[];
    resource?: string;
    /** ms since epoch. */
    expiresAt: number;
    /** Client IP at issuance. When set, verifyToken() rejects requests from a
     *  different IP — closes the "issue from loopback, replay from a non-pinned
     *  remote" gap that bypassed per-agent ipPins on the MCP endpoint. Optional
     *  for backwards compatibility with tokens issued before this field existed. */
    issuedFromIp?: string;
}
export declare const OAUTH_CODE_TTL_MS = 60000;
export declare const OAUTH_ACCESS_TOKEN_TTL_MS: number;
/**
 * Absolute ceilings. The DCR endpoint is rate-limited per IP upstream, so
 * a friendly client won't hit these. The caps exist so a broken or hostile
 * client can't grow the Maps without bound between sweep() calls.
 *
 * When a cap is hit we evict the oldest entry rather than refusing the
 * new one — matches the "self-host, keep the live session working"
 * philosophy. Evicted clients will simply re-register on their next use.
 */
export declare const OAUTH_MAX_CLIENTS = 1000;
export declare const OAUTH_MAX_CODES = 500;
export declare const OAUTH_MAX_TOKENS = 5000;
export declare class OAuthStore {
    private clients;
    private codes;
    /**
     * XPORT-005: tokens are keyed by sha256(token), never the raw token. The
     * user-supplied bearer is hashed before the Map lookup, so the comparison is
     * over fixed-length digests rather than letting V8's hash-table short-circuit
     * on the first byte of the attacker-controlled string — consistent with the
     * `timingSafeEqual` posture the rest of the codebase uses. The reverse index
     * stores hashes too.
     */
    private tokens;
    /** Reverse index clientId → token-hashes, so revoking a grant can invalidate
     *  all outstanding access tokens for that client immediately rather than
     *  waiting for the 24 h TTL to expire. Kept consistent with `tokens` via the
     *  issueToken / revokeToken / evict / sweep paths. */
    private tokensByClient;
    /** sha256(token) hex — the key under which a token's record lives. */
    private static hashToken;
    /** Drop the oldest entry from a Map (relies on Map's insertion-order iteration). */
    private evictOldest;
    private indexToken;
    /** `hash` is sha256(token) — the same key used in the primary tokens Map. */
    private unindexToken;
    registerClient(client: Omit<RegisteredClient, "client_id" | "client_id_issued_at">): RegisteredClient;
    getClient(id: string): RegisteredClient | undefined;
    /** Allocate a new one-shot authorization code. */
    issueAuthCode(params: Omit<PendingAuth, "code" | "createdAt">): PendingAuth;
    /** Consume a code (always deletes, returns record only if still valid). */
    consumeAuthCode(code: string): PendingAuth | null;
    issueToken(args: {
        clientId: string;
        scopes: string[];
        resource?: string;
        issuedFromIp?: string;
    }): IssuedToken;
    verifyToken(token: string): IssuedToken | null;
    revokeToken(token: string): boolean;
    /** Drop every outstanding access token for `clientId`. Returns the number
     *  of tokens revoked. Called when a per-agent grant is denied / revoked /
     *  expires so that ongoing requests holding the token can't continue past
     *  the policy change. */
    revokeTokensForClient(clientId: string): number;
    /**
     * Drop expired codes + tokens. Safe to call periodically — O(n) scan, but
     * n is small in a single-user deployment (usually ≤ dozens).
     */
    sweep(now?: number): {
        codes: number;
        tokens: number;
    };
    stats(): {
        clients: number;
        codes: number;
        tokens: number;
    };
}
//# sourceMappingURL=oauth-store.d.ts.map