@vfarcic/dot-ai
Version:
AI-powered development productivity platform that enhances software development workflows through intelligent automation and AI-driven assistance
115 lines • 5.43 kB
TypeScript
/**
* MCP SDK OAuth Server Provider for PRD #380.
*
* Implements the SDK's OAuthServerProvider interface with:
* - In-memory client store (clients re-register on restart per MCP spec)
* - Dual-mode token verification (JWT + legacy DOT_AI_AUTH_TOKEN)
* - Dex OIDC integration for authorize/callback/token flow (Task 2.3)
*/
import type { Request, Response } from 'express';
import type { OAuthRegisteredClientsStore } from '@modelcontextprotocol/sdk/server/auth/clients.js';
import type { OAuthServerProvider, AuthorizationParams } from '@modelcontextprotocol/sdk/server/auth/provider.js';
import type { AuthInfo } from '@modelcontextprotocol/sdk/server/auth/types.js';
import type { OAuthClientInformationFull, OAuthTokens } from '@modelcontextprotocol/sdk/shared/auth.js';
/**
* In-memory client store for OAuth registered clients.
* Clients re-register on server restart per the MCP Authorization spec.
*/
export declare class DotAIClientsStore implements OAuthRegisteredClientsStore {
private clients;
getClient(clientId: string): OAuthClientInformationFull | undefined;
registerClient(client: Omit<OAuthClientInformationFull, 'client_id' | 'client_id_issued_at'>): OAuthClientInformationFull;
/** Clear all registered clients. For testing only. @internal */
_clearClients(): void;
}
/**
* OAuth Server Provider for dot-ai.
*
* Acts as the OAuth Authorization Server for MCP clients. On authorize,
* redirects the browser to Dex for authentication, then exchanges the
* Dex code for an ID token and issues a dot-ai JWT.
*
* Token verification supports dual-mode: JWT first, legacy token fallback.
*/
export declare class DotAIOAuthProvider implements OAuthServerProvider {
readonly clientsStore: DotAIClientsStore;
private pendingRequests;
private authCodes;
private requestedExpiries;
private dexConfig;
private dotAiExternalUrl;
private pruneTimer;
constructor();
/**
* Periodically remove expired entries from pendingRequests and authCodes
* to prevent unbounded memory growth from abandoned OAuth flows.
*/
private startPruning;
/** Remove expired pending requests and authorization codes. */
private pruneExpired;
/** Stop the pruning timer. For testing only. @internal */
_stopPruning(): void;
/**
* Store a client-requested token expiry for an upcoming token exchange.
* Called by middleware that intercepts POST /token before the SDK handler.
*
* @param authorizationCode - The authorization code from the token request
* @param requestedExpiry - Requested expiry in seconds
*/
setRequestedExpiry(authorizationCode: string, requestedExpiry: number): void;
/**
* Calculate token expiry based on client request, defaults, and limits.
*
* Priority:
* 1. Client-requested expiry (if valid and within max limit)
* 2. OAUTH_DEFAULT_TOKEN_TTL_SECONDS env var
* 3. Built-in default (1 day)
*
* @param authorizationCode - The authorization code being exchanged
* @returns Expiry time in seconds
*/
private getTokenExpiry;
private loadDexConfig;
/**
* Start the authorization flow by redirecting the browser to Dex.
*
* Stores the pending auth request (PKCE challenge, redirect URI, state)
* keyed by a random session ID, then encodes sessionId|originalState
* in the Dex state param so the callback can recover the pending request.
*/
authorize(client: OAuthClientInformationFull, params: AuthorizationParams, res: Response): Promise<void>;
/**
* Return the PKCE code challenge for a given authorization code.
*
* Called by the SDK's tokenHandler BEFORE exchangeAuthorizationCode.
* Do NOT delete the code here — it is consumed in exchangeAuthorizationCode.
*/
challengeForAuthorizationCode(client: OAuthClientInformationFull, authorizationCode: string): Promise<string>;
/**
* Exchange a dot-ai authorization code for a JWT access token.
*
* Called by the SDK's tokenHandler AFTER PKCE verification passes.
* Consumes the authorization code (one-time use) and signs a JWT
* containing the user's identity from the Dex ID token.
*/
exchangeAuthorizationCode(client: OAuthClientInformationFull, authorizationCode: string, _codeVerifier?: string, redirectUri?: string, _resource?: URL): Promise<OAuthTokens>;
exchangeRefreshToken(_client: OAuthClientInformationFull, _refreshToken: string, _scopes?: string[], _resource?: URL): Promise<OAuthTokens>;
/**
* Handle the Dex OIDC callback after user authenticates.
*
* Receives the redirect from Dex with ?code=DEX_CODE&state=sessionId|originalState.
* Exchanges the Dex code for an ID token, extracts user identity,
* creates a dot-ai authorization code, and redirects to the MCP client.
*/
handleCallback(req: Request, res: Response): Promise<void>;
/**
* Verify an access token (dual-mode: JWT + legacy token).
*
* 1. If no auth configured → anonymous access (backward compatible)
* 2. Try JWT verification → returns AuthInfo with identity in `extra`
* 3. Fall back to legacy DOT_AI_AUTH_TOKEN → returns AuthInfo without identity
* 4. Throw InvalidTokenError on failure
*/
verifyAccessToken(token: string): Promise<AuthInfo>;
}
//# sourceMappingURL=provider.d.ts.map