UNPKG

mcpresso-oauth-server

Version:

Production-ready OAuth 2.1 server implementation for Model Context Protocol (MCP) with PKCE support

164 lines (132 loc) 4.48 kB
import type { MCPOAuthStorage, OAuthClient, OAuthUser, AuthorizationCode, AccessToken, RefreshToken } from '../types.js' export class MemoryStorage implements MCPOAuthStorage { private clients = new Map<string, OAuthClient>() private users = new Map<string, OAuthUser>() private authorizationCodes = new Map<string, AuthorizationCode>() private accessTokens = new Map<string, AccessToken>() private refreshTokens = new Map<string, RefreshToken>() // ===== CLIENT MANAGEMENT ===== async createClient(client: OAuthClient): Promise<void> { this.clients.set(client.id, client) } async getClient(clientId: string): Promise<OAuthClient | null> { return this.clients.get(clientId) || null } async listClients(): Promise<OAuthClient[]> { return Array.from(this.clients.values()) } async updateClient(clientId: string, updates: Partial<OAuthClient>): Promise<void> { const client = this.clients.get(clientId) if (client) { this.clients.set(clientId, { ...client, ...updates, updatedAt: new Date() }) } } async deleteClient(clientId: string): Promise<void> { this.clients.delete(clientId) } // ===== USER MANAGEMENT ===== async createUser(user: OAuthUser): Promise<void> { this.users.set(user.id, user) } async getUser(userId: string): Promise<OAuthUser | null> { return this.users.get(userId) || null } async getUserByUsername(username: string): Promise<OAuthUser | null> { for (const user of this.users.values()) { if (user.username === username) { return user } } return null } async listUsers(): Promise<OAuthUser[]> { return Array.from(this.users.values()) } async updateUser(userId: string, updates: Partial<OAuthUser>): Promise<void> { const user = this.users.get(userId) if (user) { this.users.set(userId, { ...user, ...updates, updatedAt: new Date() }) } } async deleteUser(userId: string): Promise<void> { this.users.delete(userId) } // ===== AUTHORIZATION CODES ===== async createAuthorizationCode(code: AuthorizationCode): Promise<void> { this.authorizationCodes.set(code.code, code) } async getAuthorizationCode(code: string): Promise<AuthorizationCode | null> { return this.authorizationCodes.get(code) || null } async deleteAuthorizationCode(code: string): Promise<void> { this.authorizationCodes.delete(code) } async cleanupExpiredCodes(): Promise<void> { const now = new Date() for (const [code, authCode] of this.authorizationCodes.entries()) { if (authCode.expiresAt < now) { this.authorizationCodes.delete(code) } } } // ===== ACCESS TOKENS ===== async createAccessToken(token: AccessToken): Promise<void> { this.accessTokens.set(token.token, token) } async getAccessToken(token: string): Promise<AccessToken | null> { return this.accessTokens.get(token) || null } async deleteAccessToken(token: string): Promise<void> { this.accessTokens.delete(token) } async cleanupExpiredTokens(): Promise<void> { const now = new Date() for (const [token, accessToken] of this.accessTokens.entries()) { if (accessToken.expiresAt < now) { this.accessTokens.delete(token) } } } // ===== REFRESH TOKENS ===== async createRefreshToken(token: RefreshToken): Promise<void> { this.refreshTokens.set(token.token, token) } async getRefreshToken(token: string): Promise<RefreshToken | null> { return this.refreshTokens.get(token) || null } async deleteRefreshToken(token: string): Promise<void> { this.refreshTokens.delete(token) } async deleteRefreshTokensByAccessToken(accessTokenId: string): Promise<void> { for (const [token, refreshToken] of this.refreshTokens.entries()) { if (refreshToken.accessTokenId === accessTokenId) { this.refreshTokens.delete(token) } } } async cleanupExpiredRefreshTokens(): Promise<void> { const now = new Date() for (const [token, refreshToken] of this.refreshTokens.entries()) { if (refreshToken.expiresAt < now) { this.refreshTokens.delete(token) } } } // ===== UTILITY METHODS ===== getStats() { return { clients: this.clients.size, users: this.users.size, authorizationCodes: this.authorizationCodes.size, accessTokens: this.accessTokens.size, refreshTokens: this.refreshTokens.size } } }