/**
 * In-memory stores for the OAuth 2.1 authorization server.
 *
 * Codes (60s TTL) and DCR clients are process-local: a restart drops codes
 * (short-lived anyway) and clients re-register on demand.
 *
 * Issued ACCESS TOKENS are optionally persisted (when the store is constructed
 * with a path) so they survive a daemon restart — without persistence, a
 * restart dropped the in-memory Map and 401'd every live token, silently
 * breaking headless / static-config clients (field finding #7). Only the token
 * HASH (the Map key) + metadata are written to disk (0600, atomic) — never the
 * raw bearer — so a leaked file cannot be replayed as a credential.
 */
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 readonly persistPath?;
    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;
    /**
     * Optional on-disk persistence of ISSUED TOKENS so they survive a daemon
     * restart (XPORT/#7 — a restart used to drop the in-memory Map and 401 every
     * live token, silently breaking headless/static-config clients). Only the
     * token HASH (the Map key) + metadata are written — never the raw bearer — so
     * a leaked file cannot be replayed as a credential. Codes (60s TTL) and DCR
     * clients are intentionally NOT persisted.
     */
    constructor(persistPath?: string | undefined);
    private load;
    private persist;
    /** 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;
    /**
     * Register a client with a predetermined client_id. Used to load persisted
     * service accounts (client_credentials grant) at startup so token-issued
     * callers resolve to a human-readable client_name in logs and the Agents tab.
     * Unlike {@link registerClient}, the id is supplied by the caller (it already
     * lives in the service-account store) rather than freshly minted.
     */
    registerServiceClient(record: RegisteredClient): void;
    /** 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