@rekog/mcp-nest 1.7.4-alpha.0 → 1.7.4-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -359,7 +359,7 @@ function createMcpOAuthController(endpoints = {}) {
359
359
  (0, common_1.Header)('content-type', 'application/json'),
360
360
  (0, common_1.Header)('Cache-Control', 'no-store'),
361
361
  (0, common_1.Header)('Pragma', 'no-cache'),
362
- (0, common_1.HttpCode)(201),
362
+ (0, common_1.HttpCode)(200),
363
363
  __param(0, (0, common_1.Body)()),
364
364
  __param(1, (0, common_1.Req)()),
365
365
  __metadata("design:type", Function),
@@ -1 +1 @@
1
- {"version":3,"file":"mcp-oauth.controller.js","sourceRoot":"","sources":["../../src/authz/mcp-oauth.controller.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n BadRequestException,\n Body,\n Controller,\n Get,\n Header,\n HttpCode,\n Inject,\n Logger,\n Next,\n Post,\n Query,\n Req,\n Res,\n} from '@nestjs/common';\nimport { createHash, randomBytes } from 'crypto';\nimport { Request as ExpressRequest, NextFunction, Response } from 'express';\nimport passport from 'passport';\nimport { normalizeEndpoint } from '../mcp/utils/normalize-endpoint';\nimport {\n OAuthEndpointConfiguration,\n OAuthModuleOptions,\n OAuthSession,\n OAuthUserProfile,\n} from './providers/oauth-provider.interface';\nimport { ClientService } from './services/client.service';\nimport { JwtTokenService, TokenPair } from './services/jwt-token.service';\nimport { STRATEGY_NAME } from './services/oauth-strategy.service';\nimport { IOAuthStore } from './stores/oauth-store.interface';\n\ninterface OAuthCallbackRequest extends ExpressRequest {\n user?: {\n profile: OAuthUserProfile;\n accessToken: string;\n provider: string;\n };\n}\n\nexport function createMcpOAuthController(\n endpoints: OAuthEndpointConfiguration = {},\n) {\n @Controller()\n class McpOAuthController {\n readonly logger = new Logger(McpOAuthController.name);\n readonly serverUrl: string;\n readonly isProduction: boolean;\n readonly options: OAuthModuleOptions;\n constructor(\n @Inject('OAUTH_MODULE_OPTIONS') options: OAuthModuleOptions,\n @Inject('IOAuthStore') readonly store: IOAuthStore,\n readonly jwtTokenService: JwtTokenService,\n readonly clientService: ClientService,\n ) {\n this.serverUrl = options.serverUrl;\n this.isProduction = options.cookieSecure;\n this.options = options;\n }\n\n @Get(endpoints.wellKnownProtectedResourceMetadata)\n @Header('content-type', 'application/json')\n getProtectedResourceMetadata() {\n // The issuer URL of your authorization server.\n const authorizationServerIssuer = this.options.jwtIssuer;\n\n // The canonical URI of the MCP server resource itself.\n const resourceIdentifier = this.options.resource;\n\n const metadata = {\n /**\n * REQUIRED by MCP Spec.\n * A list of authorization server issuer URLs that can issue tokens for this resource.\n */\n authorization_servers: [authorizationServerIssuer],\n\n /**\n * RECOMMENDED by RFC 9728.\n * The identifier for this resource server.\n */\n resource: resourceIdentifier,\n\n /**\n * RECOMMENDED by RFC 9728.\n * A list of scopes that this resource server understands.\n */\n scopes_supported:\n this.options.protectedResourceMetadata.scopesSupported,\n\n /**\n * RECOMMENDED by RFC 9728.\n * A list of methods clients can use to present the access token.\n */\n bearer_methods_supported:\n this.options.protectedResourceMetadata.bearerMethodsSupported,\n\n /**\n * OPTIONAL but helpful custom metadata.\n * Declares which version of the MCP spec this server supports.\n */\n mcp_versions_supported:\n this.options.protectedResourceMetadata.mcpVersionsSupported,\n };\n\n return metadata;\n }\n\n // OAuth endpoints\n @Get(endpoints.wellKnownAuthorizationServerMetadata)\n @Header('content-type', 'application/json')\n getAuthorizationServerMetadata() {\n return {\n issuer: this.serverUrl,\n authorization_endpoint: normalizeEndpoint(\n `${this.serverUrl}/${endpoints.authorize}`,\n ),\n token_endpoint: normalizeEndpoint(\n `${this.serverUrl}/${endpoints.token}`,\n ),\n registration_endpoint: normalizeEndpoint(\n `${this.serverUrl}/${endpoints.register}`,\n ),\n response_types_supported:\n this.options.authorizationServerMetadata.responseTypesSupported,\n response_modes_supported:\n this.options.authorizationServerMetadata.responseModesSupported,\n grant_types_supported:\n this.options.authorizationServerMetadata.grantTypesSupported,\n token_endpoint_auth_methods_supported:\n this.options.authorizationServerMetadata\n .tokenEndpointAuthMethodsSupported,\n scopes_supported:\n this.options.authorizationServerMetadata.scopesSupported,\n revocation_endpoint: normalizeEndpoint(\n `${this.serverUrl}/${endpoints?.revoke}`,\n ),\n code_challenge_methods_supported:\n this.options.authorizationServerMetadata\n .codeChallengeMethodsSupported,\n };\n }\n\n @Post(endpoints.register)\n async registerClient(@Body() registrationDto: any) {\n return await this.clientService.registerClient(registrationDto);\n }\n\n @Get(endpoints.authorize)\n async authorize(\n @Query() query: any,\n @Req()\n req: any,\n @Res() res: Response,\n @Next() next: NextFunction,\n ) {\n const {\n response_type,\n client_id,\n redirect_uri,\n code_challenge,\n code_challenge_method,\n state,\n scope,\n } = query;\n const resource = this.options.resource;\n if (response_type !== 'code') {\n throw new BadRequestException('Only response_type=code is supported');\n }\n\n if (!client_id) {\n throw new BadRequestException('Missing required parameters');\n }\n\n // Validate client and redirect URI\n const client = await this.clientService.getClient(client_id);\n if (!client) {\n throw new BadRequestException('Invalid client_id');\n }\n\n const validRedirect = await this.clientService.validateRedirectUri(\n client_id,\n redirect_uri,\n );\n if (!validRedirect) {\n throw new BadRequestException('Invalid redirect_uri');\n }\n\n // Create OAuth session\n const sessionId = randomBytes(32).toString('base64url');\n const sessionState = randomBytes(32).toString('base64url');\n\n const oauthSession: OAuthSession = {\n sessionId,\n state: sessionState,\n clientId: client_id,\n redirectUri: redirect_uri,\n codeChallenge: code_challenge,\n codeChallengeMethod: code_challenge_method || 'plain',\n oauthState: state,\n scope: scope,\n resource,\n expiresAt: Date.now() + this.options.oauthSessionExpiresIn,\n };\n\n await this.store.storeOAuthSession(sessionId, oauthSession);\n\n // Set session cookie\n res.cookie('oauth_session', sessionId, {\n httpOnly: true,\n secure: this.isProduction,\n maxAge: this.options.oauthSessionExpiresIn,\n });\n\n // Store state for passport\n res.cookie('oauth_state', sessionState, {\n httpOnly: true,\n secure: this.isProduction,\n maxAge: this.options.oauthSessionExpiresIn,\n });\n\n // Redirect to the provider's auth endpoint\n passport.authenticate(STRATEGY_NAME, {\n state: req.cookies?.oauth_state,\n })(req, res, next);\n }\n\n @Get(endpoints.callback)\n handleProviderCallback(\n @Req() req: OAuthCallbackRequest,\n @Res() res: Response,\n @Next() next: NextFunction,\n ) {\n // Use a custom callback to handle the authentication result\n passport.authenticate(\n STRATEGY_NAME,\n { session: false },\n async (err: any, user: any) => {\n try {\n if (err) {\n this.logger.error('OAuth callback error:', err);\n throw new BadRequestException('Authentication failed');\n }\n\n if (!user) {\n throw new BadRequestException('Authentication failed');\n }\n\n req.user = user;\n await this.processAuthenticationSuccess(req, res);\n } catch (error) {\n next(error);\n }\n },\n )(req, res, next);\n }\n\n async processAuthenticationSuccess(\n req: OAuthCallbackRequest,\n res: Response,\n ) {\n const user = req.user;\n if (!user) {\n throw new BadRequestException('Authentication failed');\n }\n\n const sessionId = req.cookies?.oauth_session;\n if (!sessionId) {\n throw new BadRequestException('Missing OAuth session');\n }\n\n const session = await this.store.getOAuthSession(sessionId);\n if (!session) {\n throw new BadRequestException('Invalid or expired OAuth session');\n }\n\n // Verify state\n const stateFromCookie = req.cookies?.oauth_state;\n if (session.state !== stateFromCookie) {\n throw new BadRequestException('Invalid state parameter');\n }\n\n // Generate JWT for UI access\n const jwt = this.jwtTokenService.generateUserToken(\n user.profile.username,\n user.profile,\n );\n\n // Set JWT token as cookie for UI endpoints\n res.cookie('auth_token', jwt, {\n httpOnly: true,\n secure: this.isProduction,\n maxAge: this.options.cookieMaxAge,\n });\n\n // Clear temporary cookies\n res.clearCookie('oauth_session');\n res.clearCookie('oauth_state');\n\n // Generate authorization code\n const authCode = randomBytes(32).toString('base64url');\n\n // Store the auth code\n await this.store.storeAuthCode({\n code: authCode,\n user_id: user.profile.username,\n client_id: session.clientId!,\n redirect_uri: session.redirectUri!,\n code_challenge: session.codeChallenge!,\n code_challenge_method: session.codeChallengeMethod!,\n expires_at: Date.now() + this.options.authCodeExpiresIn,\n resource: session.resource,\n scope: session.scope,\n github_access_token: '', // No longer provider-specific\n });\n\n // Build redirect URL with authorization code\n const redirectUrl = new URL(session.redirectUri!);\n redirectUrl.searchParams.set('code', authCode);\n if (session.oauthState) {\n redirectUrl.searchParams.set('state', session.oauthState);\n }\n\n // Clean up session\n await this.store.removeOAuthSession(sessionId);\n\n res.redirect(redirectUrl.toString());\n }\n\n @Post(endpoints.token)\n @Header('content-type', 'application/json')\n @Header('Cache-Control', 'no-store')\n @Header('Pragma', 'no-cache')\n @HttpCode(201)\n async exchangeToken(\n @Body() body: any,\n @Req() req: any,\n ): Promise<TokenPair> {\n const { grant_type, code, code_verifier, redirect_uri, refresh_token } =\n body;\n\n switch (grant_type) {\n case 'authorization_code': {\n // Extract client credentials based on authentication method\n const clientCredentials = this.extractClientCredentials(req, body);\n return await this.handleAuthorizationCodeGrant(\n code,\n code_verifier,\n redirect_uri,\n clientCredentials,\n );\n }\n case 'refresh_token': {\n // For refresh tokens, try to extract client credentials, but allow fallback to token-based extraction\n let clientCredentials: { client_id: string; client_secret?: string };\n try {\n clientCredentials = this.extractClientCredentials(req, body);\n } catch {\n // If we can't extract credentials, we'll try to get them from the refresh token\n clientCredentials = { client_id: '' }; // Will be filled from token\n }\n return await this.handleRefreshTokenGrant(\n refresh_token,\n clientCredentials,\n );\n }\n default:\n throw new BadRequestException('Unsupported grant_type');\n }\n }\n\n /**\n * Extract client credentials from request based on authentication method\n */\n extractClientCredentials(\n req: any,\n body: any,\n ): { client_id: string; client_secret?: string } {\n // Try client_secret_basic first (Authorization header)\n const authHeader = req.headers?.authorization;\n if (authHeader && authHeader.startsWith('Basic ')) {\n const credentials = Buffer.from(authHeader.slice(6), 'base64').toString(\n 'utf-8',\n );\n const [client_id, client_secret] = credentials.split(':', 2);\n if (client_id) {\n return { client_id, client_secret };\n }\n }\n\n // Try client_secret_post (body parameters)\n if (body.client_id) {\n return {\n client_id: body.client_id,\n client_secret: body.client_secret,\n };\n }\n\n throw new BadRequestException('Missing client credentials');\n }\n\n /**\n * Validate client authentication based on the client's configured method\n */\n validateClientAuthentication(\n client: any,\n clientCredentials: { client_id: string; client_secret?: string },\n ): void {\n if (!client) {\n throw new BadRequestException('Invalid client_id');\n }\n\n const { token_endpoint_auth_method } = client;\n\n switch (token_endpoint_auth_method) {\n case 'client_secret_basic':\n case 'client_secret_post':\n if (!clientCredentials.client_secret) {\n throw new BadRequestException(\n 'Client secret required for this authentication method',\n );\n }\n if (client.client_secret !== clientCredentials.client_secret) {\n throw new BadRequestException('Invalid client credentials');\n }\n break;\n\n case 'none':\n // Public client - no secret required\n if (clientCredentials.client_secret) {\n throw new BadRequestException(\n 'Client secret not allowed for public clients',\n );\n }\n break;\n\n default:\n throw new BadRequestException(\n `Unsupported authentication method: ${token_endpoint_auth_method}`,\n );\n }\n }\n\n async handleAuthorizationCodeGrant(\n code: string,\n code_verifier: string,\n _redirect_uri: string,\n clientCredentials: { client_id: string; client_secret?: string },\n ): Promise<TokenPair> {\n this.logger.debug('handleAuthorizationCodeGrant - Params:', {\n code,\n client_id: clientCredentials.client_id,\n });\n\n // Get and validate the authorization code\n const authCode = await this.store.getAuthCode(code);\n if (!authCode) {\n this.logger.error(\n 'handleAuthorizationCodeGrant - Invalid authorization code:',\n code,\n );\n throw new BadRequestException('Invalid authorization code');\n }\n if (authCode.expires_at < Date.now()) {\n await this.store.removeAuthCode(code);\n this.logger.error(\n 'handleAuthorizationCodeGrant - Authorization code expired:',\n code,\n );\n throw new BadRequestException('Authorization code has expired');\n }\n if (authCode.client_id !== clientCredentials.client_id) {\n this.logger.error(\n 'handleAuthorizationCodeGrant - Client ID mismatch:',\n { expected: authCode.client_id, got: clientCredentials.client_id },\n );\n throw new BadRequestException('Client ID mismatch');\n }\n\n // Get client and validate authentication\n const client = await this.clientService.getClient(\n clientCredentials.client_id,\n );\n this.validateClientAuthentication(client, clientCredentials);\n if (authCode.code_challenge) {\n const isValid = this.validatePKCE(\n code_verifier,\n authCode.code_challenge,\n authCode.code_challenge_method,\n );\n if (!isValid) {\n this.logger.error(\n 'handleAuthorizationCodeGrant - Invalid PKCE verification',\n );\n throw new BadRequestException('Invalid PKCE verification');\n }\n }\n if (!authCode.resource) {\n this.logger.error(\n 'handleAuthorizationCodeGrant - No resource associated with code',\n );\n throw new BadRequestException(\n 'Authorization code is not associated with a resource',\n );\n }\n\n const tokens = this.jwtTokenService.generateTokenPair(\n authCode.user_id,\n clientCredentials.client_id,\n authCode.scope,\n authCode.resource,\n );\n await this.store.removeAuthCode(code);\n this.logger.log(\n 'handleAuthorizationCodeGrant - Token pair generated for user:',\n authCode.user_id,\n );\n return tokens;\n }\n\n async handleRefreshTokenGrant(\n refresh_token: string,\n clientCredentials: { client_id: string; client_secret?: string },\n ): Promise<TokenPair> {\n // Verify the refresh token first to get client_id from token if not provided\n const payload = this.jwtTokenService.validateToken(refresh_token);\n if (!payload || payload.type !== 'refresh') {\n throw new BadRequestException('Invalid or expired refresh token');\n }\n\n // Use client_id from token if not provided in credentials\n const clientId = clientCredentials.client_id || payload.client_id;\n if (!clientId) {\n throw new BadRequestException('Unable to determine client_id');\n }\n\n // Get client and validate authentication\n const client = await this.clientService.getClient(clientId);\n\n // For refresh token grants, we can be more lenient with client authentication\n // if the token already contains the client_id and the client is public\n if (client?.token_endpoint_auth_method !== 'none') {\n this.validateClientAuthentication(client, {\n ...clientCredentials,\n client_id: clientId,\n });\n }\n\n // Verify the refresh token belongs to the client\n if (payload.client_id !== clientId) {\n throw new BadRequestException(\n 'Invalid refresh token or token does not belong to this client',\n );\n }\n\n const newTokens = this.jwtTokenService.refreshAccessToken(refresh_token);\n if (!newTokens) {\n throw new BadRequestException('Failed to refresh token');\n }\n\n return newTokens;\n }\n\n validatePKCE(\n code_verifier: string,\n code_challenge: string,\n method: string,\n ): boolean {\n if (method === 'plain') {\n return code_verifier === code_challenge;\n } else if (method === 'S256') {\n const hash = createHash('sha256')\n .update(code_verifier)\n .digest('base64url');\n return hash === code_challenge;\n }\n return false;\n }\n }\n\n return McpOAuthController;\n}\n"]}
1
+ {"version":3,"file":"mcp-oauth.controller.js","sourceRoot":"","sources":["../../src/authz/mcp-oauth.controller.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n BadRequestException,\n Body,\n Controller,\n Get,\n Header,\n HttpCode,\n Inject,\n Logger,\n Next,\n Post,\n Query,\n Req,\n Res,\n} from '@nestjs/common';\nimport { createHash, randomBytes } from 'crypto';\nimport { Request as ExpressRequest, NextFunction, Response } from 'express';\nimport passport from 'passport';\nimport { normalizeEndpoint } from '../mcp/utils/normalize-endpoint';\nimport {\n OAuthEndpointConfiguration,\n OAuthModuleOptions,\n OAuthSession,\n OAuthUserProfile,\n} from './providers/oauth-provider.interface';\nimport { ClientService } from './services/client.service';\nimport { JwtTokenService, TokenPair } from './services/jwt-token.service';\nimport { STRATEGY_NAME } from './services/oauth-strategy.service';\nimport { IOAuthStore } from './stores/oauth-store.interface';\n\ninterface OAuthCallbackRequest extends ExpressRequest {\n user?: {\n profile: OAuthUserProfile;\n accessToken: string;\n provider: string;\n };\n}\n\nexport function createMcpOAuthController(\n endpoints: OAuthEndpointConfiguration = {},\n) {\n @Controller()\n class McpOAuthController {\n readonly logger = new Logger(McpOAuthController.name);\n readonly serverUrl: string;\n readonly isProduction: boolean;\n readonly options: OAuthModuleOptions;\n constructor(\n @Inject('OAUTH_MODULE_OPTIONS') options: OAuthModuleOptions,\n @Inject('IOAuthStore') readonly store: IOAuthStore,\n readonly jwtTokenService: JwtTokenService,\n readonly clientService: ClientService,\n ) {\n this.serverUrl = options.serverUrl;\n this.isProduction = options.cookieSecure;\n this.options = options;\n }\n\n @Get(endpoints.wellKnownProtectedResourceMetadata)\n @Header('content-type', 'application/json')\n getProtectedResourceMetadata() {\n // The issuer URL of your authorization server.\n const authorizationServerIssuer = this.options.jwtIssuer;\n\n // The canonical URI of the MCP server resource itself.\n const resourceIdentifier = this.options.resource;\n\n const metadata = {\n /**\n * REQUIRED by MCP Spec.\n * A list of authorization server issuer URLs that can issue tokens for this resource.\n */\n authorization_servers: [authorizationServerIssuer],\n\n /**\n * RECOMMENDED by RFC 9728.\n * The identifier for this resource server.\n */\n resource: resourceIdentifier,\n\n /**\n * RECOMMENDED by RFC 9728.\n * A list of scopes that this resource server understands.\n */\n scopes_supported:\n this.options.protectedResourceMetadata.scopesSupported,\n\n /**\n * RECOMMENDED by RFC 9728.\n * A list of methods clients can use to present the access token.\n */\n bearer_methods_supported:\n this.options.protectedResourceMetadata.bearerMethodsSupported,\n\n /**\n * OPTIONAL but helpful custom metadata.\n * Declares which version of the MCP spec this server supports.\n */\n mcp_versions_supported:\n this.options.protectedResourceMetadata.mcpVersionsSupported,\n };\n\n return metadata;\n }\n\n // OAuth endpoints\n @Get(endpoints.wellKnownAuthorizationServerMetadata)\n @Header('content-type', 'application/json')\n getAuthorizationServerMetadata() {\n return {\n issuer: this.serverUrl,\n authorization_endpoint: normalizeEndpoint(\n `${this.serverUrl}/${endpoints.authorize}`,\n ),\n token_endpoint: normalizeEndpoint(\n `${this.serverUrl}/${endpoints.token}`,\n ),\n registration_endpoint: normalizeEndpoint(\n `${this.serverUrl}/${endpoints.register}`,\n ),\n response_types_supported:\n this.options.authorizationServerMetadata.responseTypesSupported,\n response_modes_supported:\n this.options.authorizationServerMetadata.responseModesSupported,\n grant_types_supported:\n this.options.authorizationServerMetadata.grantTypesSupported,\n token_endpoint_auth_methods_supported:\n this.options.authorizationServerMetadata\n .tokenEndpointAuthMethodsSupported,\n scopes_supported:\n this.options.authorizationServerMetadata.scopesSupported,\n revocation_endpoint: normalizeEndpoint(\n `${this.serverUrl}/${endpoints?.revoke}`,\n ),\n code_challenge_methods_supported:\n this.options.authorizationServerMetadata\n .codeChallengeMethodsSupported,\n };\n }\n\n @Post(endpoints.register)\n async registerClient(@Body() registrationDto: any) {\n return await this.clientService.registerClient(registrationDto);\n }\n\n @Get(endpoints.authorize)\n async authorize(\n @Query() query: any,\n @Req()\n req: any,\n @Res() res: Response,\n @Next() next: NextFunction,\n ) {\n const {\n response_type,\n client_id,\n redirect_uri,\n code_challenge,\n code_challenge_method,\n state,\n scope,\n } = query;\n const resource = this.options.resource;\n if (response_type !== 'code') {\n throw new BadRequestException('Only response_type=code is supported');\n }\n\n if (!client_id) {\n throw new BadRequestException('Missing required parameters');\n }\n\n // Validate client and redirect URI\n const client = await this.clientService.getClient(client_id);\n if (!client) {\n throw new BadRequestException('Invalid client_id');\n }\n\n const validRedirect = await this.clientService.validateRedirectUri(\n client_id,\n redirect_uri,\n );\n if (!validRedirect) {\n throw new BadRequestException('Invalid redirect_uri');\n }\n\n // Create OAuth session\n const sessionId = randomBytes(32).toString('base64url');\n const sessionState = randomBytes(32).toString('base64url');\n\n const oauthSession: OAuthSession = {\n sessionId,\n state: sessionState,\n clientId: client_id,\n redirectUri: redirect_uri,\n codeChallenge: code_challenge,\n codeChallengeMethod: code_challenge_method || 'plain',\n oauthState: state,\n scope: scope,\n resource,\n expiresAt: Date.now() + this.options.oauthSessionExpiresIn,\n };\n\n await this.store.storeOAuthSession(sessionId, oauthSession);\n\n // Set session cookie\n res.cookie('oauth_session', sessionId, {\n httpOnly: true,\n secure: this.isProduction,\n maxAge: this.options.oauthSessionExpiresIn,\n });\n\n // Store state for passport\n res.cookie('oauth_state', sessionState, {\n httpOnly: true,\n secure: this.isProduction,\n maxAge: this.options.oauthSessionExpiresIn,\n });\n\n // Redirect to the provider's auth endpoint\n passport.authenticate(STRATEGY_NAME, {\n state: req.cookies?.oauth_state,\n })(req, res, next);\n }\n\n @Get(endpoints.callback)\n handleProviderCallback(\n @Req() req: OAuthCallbackRequest,\n @Res() res: Response,\n @Next() next: NextFunction,\n ) {\n // Use a custom callback to handle the authentication result\n passport.authenticate(\n STRATEGY_NAME,\n { session: false },\n async (err: any, user: any) => {\n try {\n if (err) {\n this.logger.error('OAuth callback error:', err);\n throw new BadRequestException('Authentication failed');\n }\n\n if (!user) {\n throw new BadRequestException('Authentication failed');\n }\n\n req.user = user;\n await this.processAuthenticationSuccess(req, res);\n } catch (error) {\n next(error);\n }\n },\n )(req, res, next);\n }\n\n async processAuthenticationSuccess(\n req: OAuthCallbackRequest,\n res: Response,\n ) {\n const user = req.user;\n if (!user) {\n throw new BadRequestException('Authentication failed');\n }\n\n const sessionId = req.cookies?.oauth_session;\n if (!sessionId) {\n throw new BadRequestException('Missing OAuth session');\n }\n\n const session = await this.store.getOAuthSession(sessionId);\n if (!session) {\n throw new BadRequestException('Invalid or expired OAuth session');\n }\n\n // Verify state\n const stateFromCookie = req.cookies?.oauth_state;\n if (session.state !== stateFromCookie) {\n throw new BadRequestException('Invalid state parameter');\n }\n\n // Generate JWT for UI access\n const jwt = this.jwtTokenService.generateUserToken(\n user.profile.username,\n user.profile,\n );\n\n // Set JWT token as cookie for UI endpoints\n res.cookie('auth_token', jwt, {\n httpOnly: true,\n secure: this.isProduction,\n maxAge: this.options.cookieMaxAge,\n });\n\n // Clear temporary cookies\n res.clearCookie('oauth_session');\n res.clearCookie('oauth_state');\n\n // Generate authorization code\n const authCode = randomBytes(32).toString('base64url');\n\n // Store the auth code\n await this.store.storeAuthCode({\n code: authCode,\n user_id: user.profile.username,\n client_id: session.clientId!,\n redirect_uri: session.redirectUri!,\n code_challenge: session.codeChallenge!,\n code_challenge_method: session.codeChallengeMethod!,\n expires_at: Date.now() + this.options.authCodeExpiresIn,\n resource: session.resource,\n scope: session.scope,\n github_access_token: '', // No longer provider-specific\n });\n\n // Build redirect URL with authorization code\n const redirectUrl = new URL(session.redirectUri!);\n redirectUrl.searchParams.set('code', authCode);\n if (session.oauthState) {\n redirectUrl.searchParams.set('state', session.oauthState);\n }\n\n // Clean up session\n await this.store.removeOAuthSession(sessionId);\n\n res.redirect(redirectUrl.toString());\n }\n\n @Post(endpoints.token)\n @Header('content-type', 'application/json')\n @Header('Cache-Control', 'no-store')\n @Header('Pragma', 'no-cache')\n @HttpCode(200)\n async exchangeToken(\n @Body() body: any,\n @Req() req: any,\n ): Promise<TokenPair> {\n const { grant_type, code, code_verifier, redirect_uri, refresh_token } =\n body;\n\n switch (grant_type) {\n case 'authorization_code': {\n // Extract client credentials based on authentication method\n const clientCredentials = this.extractClientCredentials(req, body);\n return await this.handleAuthorizationCodeGrant(\n code,\n code_verifier,\n redirect_uri,\n clientCredentials,\n );\n }\n case 'refresh_token': {\n // For refresh tokens, try to extract client credentials, but allow fallback to token-based extraction\n let clientCredentials: { client_id: string; client_secret?: string };\n try {\n clientCredentials = this.extractClientCredentials(req, body);\n } catch {\n // If we can't extract credentials, we'll try to get them from the refresh token\n clientCredentials = { client_id: '' }; // Will be filled from token\n }\n return await this.handleRefreshTokenGrant(\n refresh_token,\n clientCredentials,\n );\n }\n default:\n throw new BadRequestException('Unsupported grant_type');\n }\n }\n\n /**\n * Extract client credentials from request based on authentication method\n */\n extractClientCredentials(\n req: any,\n body: any,\n ): { client_id: string; client_secret?: string } {\n // Try client_secret_basic first (Authorization header)\n const authHeader = req.headers?.authorization;\n if (authHeader && authHeader.startsWith('Basic ')) {\n const credentials = Buffer.from(authHeader.slice(6), 'base64').toString(\n 'utf-8',\n );\n const [client_id, client_secret] = credentials.split(':', 2);\n if (client_id) {\n return { client_id, client_secret };\n }\n }\n\n // Try client_secret_post (body parameters)\n if (body.client_id) {\n return {\n client_id: body.client_id,\n client_secret: body.client_secret,\n };\n }\n\n throw new BadRequestException('Missing client credentials');\n }\n\n /**\n * Validate client authentication based on the client's configured method\n */\n validateClientAuthentication(\n client: any,\n clientCredentials: { client_id: string; client_secret?: string },\n ): void {\n if (!client) {\n throw new BadRequestException('Invalid client_id');\n }\n\n const { token_endpoint_auth_method } = client;\n\n switch (token_endpoint_auth_method) {\n case 'client_secret_basic':\n case 'client_secret_post':\n if (!clientCredentials.client_secret) {\n throw new BadRequestException(\n 'Client secret required for this authentication method',\n );\n }\n if (client.client_secret !== clientCredentials.client_secret) {\n throw new BadRequestException('Invalid client credentials');\n }\n break;\n\n case 'none':\n // Public client - no secret required\n if (clientCredentials.client_secret) {\n throw new BadRequestException(\n 'Client secret not allowed for public clients',\n );\n }\n break;\n\n default:\n throw new BadRequestException(\n `Unsupported authentication method: ${token_endpoint_auth_method}`,\n );\n }\n }\n\n async handleAuthorizationCodeGrant(\n code: string,\n code_verifier: string,\n _redirect_uri: string,\n clientCredentials: { client_id: string; client_secret?: string },\n ): Promise<TokenPair> {\n this.logger.debug('handleAuthorizationCodeGrant - Params:', {\n code,\n client_id: clientCredentials.client_id,\n });\n\n // Get and validate the authorization code\n const authCode = await this.store.getAuthCode(code);\n if (!authCode) {\n this.logger.error(\n 'handleAuthorizationCodeGrant - Invalid authorization code:',\n code,\n );\n throw new BadRequestException('Invalid authorization code');\n }\n if (authCode.expires_at < Date.now()) {\n await this.store.removeAuthCode(code);\n this.logger.error(\n 'handleAuthorizationCodeGrant - Authorization code expired:',\n code,\n );\n throw new BadRequestException('Authorization code has expired');\n }\n if (authCode.client_id !== clientCredentials.client_id) {\n this.logger.error(\n 'handleAuthorizationCodeGrant - Client ID mismatch:',\n { expected: authCode.client_id, got: clientCredentials.client_id },\n );\n throw new BadRequestException('Client ID mismatch');\n }\n\n // Get client and validate authentication\n const client = await this.clientService.getClient(\n clientCredentials.client_id,\n );\n this.validateClientAuthentication(client, clientCredentials);\n if (authCode.code_challenge) {\n const isValid = this.validatePKCE(\n code_verifier,\n authCode.code_challenge,\n authCode.code_challenge_method,\n );\n if (!isValid) {\n this.logger.error(\n 'handleAuthorizationCodeGrant - Invalid PKCE verification',\n );\n throw new BadRequestException('Invalid PKCE verification');\n }\n }\n if (!authCode.resource) {\n this.logger.error(\n 'handleAuthorizationCodeGrant - No resource associated with code',\n );\n throw new BadRequestException(\n 'Authorization code is not associated with a resource',\n );\n }\n\n const tokens = this.jwtTokenService.generateTokenPair(\n authCode.user_id,\n clientCredentials.client_id,\n authCode.scope,\n authCode.resource,\n );\n await this.store.removeAuthCode(code);\n this.logger.log(\n 'handleAuthorizationCodeGrant - Token pair generated for user:',\n authCode.user_id,\n );\n return tokens;\n }\n\n async handleRefreshTokenGrant(\n refresh_token: string,\n clientCredentials: { client_id: string; client_secret?: string },\n ): Promise<TokenPair> {\n // Verify the refresh token first to get client_id from token if not provided\n const payload = this.jwtTokenService.validateToken(refresh_token);\n if (!payload || payload.type !== 'refresh') {\n throw new BadRequestException('Invalid or expired refresh token');\n }\n\n // Use client_id from token if not provided in credentials\n const clientId = clientCredentials.client_id || payload.client_id;\n if (!clientId) {\n throw new BadRequestException('Unable to determine client_id');\n }\n\n // Get client and validate authentication\n const client = await this.clientService.getClient(clientId);\n\n // For refresh token grants, we can be more lenient with client authentication\n // if the token already contains the client_id and the client is public\n if (client?.token_endpoint_auth_method !== 'none') {\n this.validateClientAuthentication(client, {\n ...clientCredentials,\n client_id: clientId,\n });\n }\n\n // Verify the refresh token belongs to the client\n if (payload.client_id !== clientId) {\n throw new BadRequestException(\n 'Invalid refresh token or token does not belong to this client',\n );\n }\n\n const newTokens = this.jwtTokenService.refreshAccessToken(refresh_token);\n if (!newTokens) {\n throw new BadRequestException('Failed to refresh token');\n }\n\n return newTokens;\n }\n\n validatePKCE(\n code_verifier: string,\n code_challenge: string,\n method: string,\n ): boolean {\n if (method === 'plain') {\n return code_verifier === code_challenge;\n } else if (method === 'S256') {\n const hash = createHash('sha256')\n .update(code_verifier)\n .digest('base64url');\n return hash === code_challenge;\n }\n return false;\n }\n }\n\n return McpOAuthController;\n}\n"]}
@@ -70,7 +70,6 @@ export interface OAuthUserModuleOptions {
70
70
  storeConfiguration?: StoreConfiguration;
71
71
  apiPrefix?: string;
72
72
  endpoints?: OAuthEndpointConfiguration;
73
- supportEmail?: string;
74
73
  }
75
74
  export interface OAuthModuleDefaults {
76
75
  serverUrl: string;
@@ -102,7 +101,6 @@ export interface OAuthModuleDefaults {
102
101
  export type OAuthModuleOptions = Required<Pick<OAuthUserModuleOptions, 'provider' | 'clientId' | 'clientSecret' | 'jwtSecret'>> & Required<OAuthModuleDefaults> & {
103
102
  cookieSecure: boolean;
104
103
  storeConfiguration?: StoreConfiguration;
105
- supportEmail?: string;
106
104
  };
107
105
  export interface OAuthSession {
108
106
  sessionId: string;
@@ -1 +1 @@
1
- {"version":3,"file":"oauth-provider.interface.d.ts","sourceRoot":"","sources":["../../../src/authz/providers/oauth-provider.interface.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"oauth-provider.interface.d.ts","sourceRoot":"","sources":["../../../src/authz/providers/oauth-provider.interface.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"oauth-provider.interface.js","sourceRoot":"","sources":["../../../src/authz/providers/oauth-provider.interface.ts"],"names":[],"mappings":"","sourcesContent":["import { TypeOrmModuleOptions } from '@nestjs/typeorm';\nimport { IOAuthStore } from '../stores/oauth-store.interface';\n\nexport interface OAuthProviderConfig {\n name: string;\n displayName?: string;\n strategy: any; // Passport Strategy constructor\n strategyOptions: (options: {\n serverUrl: string;\n clientId: string;\n clientSecret: string;\n callbackPath?: string; // Optional custom callback path\n }) => any;\n scope?: string[];\n profileMapper: (profile: any) => OAuthUserProfile;\n}\n\nexport interface OAuthUserProfile {\n id: string;\n username: string;\n email?: string;\n displayName?: string;\n avatarUrl?: string;\n raw?: any; // Original profile data\n}\n\n// Store configuration union type\nexport type StoreConfiguration =\n | { type: 'typeorm'; options: TypeOrmModuleOptions }\n | { type: 'custom'; store: IOAuthStore }\n | { type: 'memory' }\n | undefined; // Default to memory store\n\nexport interface OAuthEndpointConfiguration {\n wellKnownAuthorizationServerMetadata?: string; // Default: '/.well-known/oauth-authorization-server'\n wellKnownProtectedResourceMetadata?: string | string[]; // Default: '/.well-known/oauth-protected-resource'\n register?: string; // Default: '/register'\n authorize?: string; // Default: '/authorize'\n callback?: string; // Default: '/callback'\n token?: string; // Default: '/token'\n revoke?: string; // Default: '/revoke'\n}\n\nexport interface OAuthUserModuleOptions {\n provider: OAuthProviderConfig;\n\n // Required OAuth Provider Credentials\n clientId: string;\n clientSecret: string;\n\n // Required JWT Configuration\n jwtSecret: string;\n\n // Server Configuration\n serverUrl?: string;\n resource?: string; // should be the endpoint clients connect to, e.g.: 'https://localhost:3000/mcp'\n // JWT Configuration\n jwtIssuer?: string;\n jwtAudience?: string;\n jwtAccessTokenExpiresIn?: string;\n jwtRefreshTokenExpiresIn?: string;\n\n // Cookie Configuration\n cookieSecure?: boolean;\n cookieMaxAge?: number;\n\n // OAuth Session Configuration\n oauthSessionExpiresIn?: number; // in milliseconds\n authCodeExpiresIn?: number; // in milliseconds\n\n // Protected Resource Metadata Configuration\n protectedResourceMetadata?: {\n scopesSupported?: string[];\n bearerMethodsSupported?: string[];\n mcpVersionsSupported?: string[];\n };\n\n // Authorization Server Metadata Configuration\n authorizationServerMetadata?: {\n responseTypesSupported?: string[];\n responseModesSupported?: string[];\n grantTypesSupported?: string[];\n tokenEndpointAuthMethodsSupported?: string[];\n scopesSupported?: string[];\n codeChallengeMethodsSupported?: string[];\n };\n\n // Storage Configuration - single property for all storage options\n storeConfiguration?: StoreConfiguration;\n apiPrefix?: string;\n\n // Endpoint Configuration\n endpoints?: OAuthEndpointConfiguration;\n\n // Optional support contact for operational issues\n supportEmail?: string;\n}\n\nexport interface OAuthModuleDefaults {\n serverUrl: string;\n resource: string; // Default resource URL\n jwtIssuer: string;\n jwtAudience: string;\n jwtAccessTokenExpiresIn: string;\n jwtRefreshTokenExpiresIn: string;\n cookieMaxAge: number;\n oauthSessionExpiresIn: number;\n authCodeExpiresIn: number;\n nodeEnv: string;\n apiPrefix: string;\n endpoints: OAuthEndpointConfiguration;\n protectedResourceMetadata: {\n scopesSupported: string[];\n bearerMethodsSupported: string[];\n mcpVersionsSupported: string[];\n };\n authorizationServerMetadata: {\n responseTypesSupported: string[];\n responseModesSupported: string[];\n grantTypesSupported: string[];\n tokenEndpointAuthMethodsSupported: string[];\n scopesSupported: string[];\n codeChallengeMethodsSupported: string[];\n };\n}\n\n// Resolved options after merging with defaults\nexport type OAuthModuleOptions = Required<\n Pick<\n OAuthUserModuleOptions,\n 'provider' | 'clientId' | 'clientSecret' | 'jwtSecret'\n >\n> &\n Required<OAuthModuleDefaults> & {\n // Optional fields that may remain undefined\n cookieSecure: boolean;\n storeConfiguration?: StoreConfiguration;\n // Optional support contact\n supportEmail?: string;\n };\n\nexport interface OAuthSession {\n sessionId: string;\n state: string;\n clientId?: string;\n redirectUri?: string;\n codeChallenge?: string;\n codeChallengeMethod?: string;\n oauthState?: string;\n scope?: string;\n resource?: string;\n expiresAt: number;\n}\n"]}
1
+ {"version":3,"file":"oauth-provider.interface.js","sourceRoot":"","sources":["../../../src/authz/providers/oauth-provider.interface.ts"],"names":[],"mappings":"","sourcesContent":["import { TypeOrmModuleOptions } from '@nestjs/typeorm';\nimport { IOAuthStore } from '../stores/oauth-store.interface';\n\nexport interface OAuthProviderConfig {\n name: string;\n displayName?: string;\n strategy: any; // Passport Strategy constructor\n strategyOptions: (options: {\n serverUrl: string;\n clientId: string;\n clientSecret: string;\n callbackPath?: string; // Optional custom callback path\n }) => any;\n scope?: string[];\n profileMapper: (profile: any) => OAuthUserProfile;\n}\n\nexport interface OAuthUserProfile {\n id: string;\n username: string;\n email?: string;\n displayName?: string;\n avatarUrl?: string;\n raw?: any; // Original profile data\n}\n\n// Store configuration union type\nexport type StoreConfiguration =\n | { type: 'typeorm'; options: TypeOrmModuleOptions }\n | { type: 'custom'; store: IOAuthStore }\n | { type: 'memory' }\n | undefined; // Default to memory store\n\nexport interface OAuthEndpointConfiguration {\n wellKnownAuthorizationServerMetadata?: string; // Default: '/.well-known/oauth-authorization-server'\n wellKnownProtectedResourceMetadata?: string | string[]; // Default: '/.well-known/oauth-protected-resource'\n register?: string; // Default: '/register'\n authorize?: string; // Default: '/authorize'\n callback?: string; // Default: '/callback'\n token?: string; // Default: '/token'\n revoke?: string; // Default: '/revoke'\n}\n\nexport interface OAuthUserModuleOptions {\n provider: OAuthProviderConfig;\n\n // Required OAuth Provider Credentials\n clientId: string;\n clientSecret: string;\n\n // Required JWT Configuration\n jwtSecret: string;\n\n // Server Configuration\n serverUrl?: string;\n resource?: string; // should be the endpoint clients connect to, e.g.: 'https://localhost:3000/mcp'\n // JWT Configuration\n jwtIssuer?: string;\n jwtAudience?: string;\n jwtAccessTokenExpiresIn?: string;\n jwtRefreshTokenExpiresIn?: string;\n\n // Cookie Configuration\n cookieSecure?: boolean;\n cookieMaxAge?: number;\n\n // OAuth Session Configuration\n oauthSessionExpiresIn?: number; // in milliseconds\n authCodeExpiresIn?: number; // in milliseconds\n\n // Protected Resource Metadata Configuration\n protectedResourceMetadata?: {\n scopesSupported?: string[];\n bearerMethodsSupported?: string[];\n mcpVersionsSupported?: string[];\n };\n\n // Authorization Server Metadata Configuration\n authorizationServerMetadata?: {\n responseTypesSupported?: string[];\n responseModesSupported?: string[];\n grantTypesSupported?: string[];\n tokenEndpointAuthMethodsSupported?: string[];\n scopesSupported?: string[];\n codeChallengeMethodsSupported?: string[];\n };\n\n // Storage Configuration - single property for all storage options\n storeConfiguration?: StoreConfiguration;\n apiPrefix?: string;\n\n // Endpoint Configuration\n endpoints?: OAuthEndpointConfiguration;\n}\n\nexport interface OAuthModuleDefaults {\n serverUrl: string;\n resource: string; // Default resource URL\n jwtIssuer: string;\n jwtAudience: string;\n jwtAccessTokenExpiresIn: string;\n jwtRefreshTokenExpiresIn: string;\n cookieMaxAge: number;\n oauthSessionExpiresIn: number;\n authCodeExpiresIn: number;\n nodeEnv: string;\n apiPrefix: string;\n endpoints: OAuthEndpointConfiguration;\n protectedResourceMetadata: {\n scopesSupported: string[];\n bearerMethodsSupported: string[];\n mcpVersionsSupported: string[];\n };\n authorizationServerMetadata: {\n responseTypesSupported: string[];\n responseModesSupported: string[];\n grantTypesSupported: string[];\n tokenEndpointAuthMethodsSupported: string[];\n scopesSupported: string[];\n codeChallengeMethodsSupported: string[];\n };\n}\n\n// Resolved options after merging with defaults\nexport type OAuthModuleOptions = Required<\n Pick<\n OAuthUserModuleOptions,\n 'provider' | 'clientId' | 'clientSecret' | 'jwtSecret'\n >\n> &\n Required<OAuthModuleDefaults> & {\n // Optional fields that may remain undefined\n cookieSecure: boolean;\n storeConfiguration?: StoreConfiguration;\n };\n\nexport interface OAuthSession {\n sessionId: string;\n state: string;\n clientId?: string;\n redirectUri?: string;\n codeChallenge?: string;\n codeChallengeMethod?: string;\n oauthState?: string;\n scope?: string;\n resource?: string;\n expiresAt: number;\n}\n"]}
@@ -5,8 +5,8 @@ export declare class ClientService {
5
5
  private readonly options;
6
6
  constructor(store: IOAuthStore, options: OAuthModuleOptions);
7
7
  registerClient(registrationDto: ClientRegistrationDto): Promise<OAuthClient>;
8
+ protected preRegistrationChecks(_dto: ClientRegistrationDto): Promise<void>;
8
9
  getClient(clientId: string): Promise<OAuthClient | null>;
9
10
  validateRedirectUri(clientId: string, redirectUri: string): Promise<boolean>;
10
- private findClientByName;
11
11
  }
12
12
  //# sourceMappingURL=client.service.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.service.d.ts","sourceRoot":"","sources":["../../../src/authz/services/client.service.ts"],"names":[],"mappings":"AACA,OAAO,EACL,qBAAqB,EACrB,WAAW,EACX,WAAW,EACZ,MAAM,iCAAiC,CAAC;AAEzC,OAAO,EAAE,kBAAkB,EAAE,MAAM,uCAAuC,CAAC;AAE3E,qBACa,aAAa;IAEC,OAAO,CAAC,QAAQ,CAAC,KAAK;IAE7C,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAFgB,KAAK,EAAE,WAAW,EAEzC,OAAO,EAAE,kBAAkB;IAOxC,cAAc,CAClB,eAAe,EAAE,qBAAqB,GACrC,OAAO,CAAC,WAAW,CAAC;IAmGjB,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAcxD,mBAAmB,CACvB,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,OAAO,CAAC;YAKL,gBAAgB;CAM/B"}
1
+ {"version":3,"file":"client.service.d.ts","sourceRoot":"","sources":["../../../src/authz/services/client.service.ts"],"names":[],"mappings":"AACA,OAAO,EACL,qBAAqB,EACrB,WAAW,EACX,WAAW,EACZ,MAAM,iCAAiC,CAAC;AAEzC,OAAO,EAAE,kBAAkB,EAAE,MAAM,uCAAuC,CAAC;AAE3E,qBACa,aAAa;IAEC,OAAO,CAAC,QAAQ,CAAC,KAAK;IAE7C,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAFgB,KAAK,EAAE,WAAW,EAEzC,OAAO,EAAE,kBAAkB;IAUxC,cAAc,CAClB,eAAe,EAAE,qBAAqB,GACrC,OAAO,CAAC,WAAW,CAAC;cAuEP,qBAAqB,CAAC,IAAI,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC;IAI3E,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IAcxD,mBAAmB,CACvB,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,OAAO,CAAC;CAKpB"}
@@ -39,30 +39,8 @@ let ClientService = class ClientService {
39
39
  response_types: ['code'],
40
40
  token_endpoint_auth_method: registrationDto.token_endpoint_auth_method || 'none',
41
41
  };
42
- const existingClient = await this.findClientByName(registrationDto.client_name);
42
+ await this.preRegistrationChecks(registrationDto);
43
43
  const now = new Date();
44
- if (existingClient) {
45
- const incomingUris = Array.from(new Set(registrationDto.redirect_uris || []));
46
- const existingUris = new Set(existingClient.redirect_uris || []);
47
- const sameSize = incomingUris.length === existingUris.size;
48
- const sameValues = sameSize && incomingUris.every((u) => existingUris.has(u));
49
- if (!sameValues) {
50
- const contact = this.options.supportEmail
51
- ? ` Please contact MCP Server support at ${this.options.supportEmail} to request a redirect URI change.`
52
- : ' Please contact MCP Server support to request a redirect URI change.';
53
- throw new common_1.BadRequestException(`Client "${registrationDto.client_name}" is already registered. Changing redirect_uris is not allowed for security reasons.${contact}`);
54
- }
55
- const updatedClient = {
56
- ...existingClient,
57
- ...defaultClientValues,
58
- ...registrationDto,
59
- redirect_uris: existingClient.redirect_uris,
60
- updated_at: now,
61
- };
62
- const nc = await this.store.storeClient(updatedClient);
63
- const filteredClient = Object.fromEntries(Object.entries(nc).filter(([, value]) => value !== null));
64
- return filteredClient;
65
- }
66
44
  const client_id = this.store.generateClientId(registrationDto);
67
45
  const authMethod = registrationDto.token_endpoint_auth_method || 'none';
68
46
  const client_secret = authMethod !== 'none' ? (0, crypto_1.randomBytes)(32).toString('hex') : undefined;
@@ -78,6 +56,8 @@ let ClientService = class ClientService {
78
56
  const filteredClient = Object.fromEntries(Object.entries(client).filter(([, value]) => value !== null));
79
57
  return filteredClient;
80
58
  }
59
+ async preRegistrationChecks(_dto) {
60
+ }
81
61
  async getClient(clientId) {
82
62
  const client = await this.store.getClient(clientId);
83
63
  if (!client) {
@@ -90,9 +70,6 @@ let ClientService = class ClientService {
90
70
  const client = await this.getClient(clientId);
91
71
  return client ? client.redirect_uris.includes(redirectUri) : false;
92
72
  }
93
- async findClientByName(clientName) {
94
- return await this.store.findClient(clientName);
95
- }
96
73
  };
97
74
  exports.ClientService = ClientService;
98
75
  exports.ClientService = ClientService = __decorate([
@@ -1 +1 @@
1
- {"version":3,"file":"client.service.js","sourceRoot":"","sources":["../../../src/authz/services/client.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { BadRequestException, Injectable, Inject } from '@nestjs/common';\nimport {\n ClientRegistrationDto,\n IOAuthStore,\n OAuthClient,\n} from '../stores/oauth-store.interface';\nimport { randomBytes } from 'crypto';\nimport { OAuthModuleOptions } from '../providers/oauth-provider.interface';\n\n@Injectable()\nexport class ClientService {\n constructor(\n @Inject('IOAuthStore') private readonly store: IOAuthStore,\n @Inject('OAUTH_MODULE_OPTIONS')\n private readonly options: OAuthModuleOptions,\n ) {}\n\n /**\n * Register or update a client application\n * If client with same name exists, update it; otherwise create new\n */\n async registerClient(\n registrationDto: ClientRegistrationDto,\n ): Promise<OAuthClient> {\n // Validate required fields\n if (\n !registrationDto.redirect_uris ||\n !Array.isArray(registrationDto.redirect_uris)\n ) {\n throw new BadRequestException(\n 'redirect_uris is required and must be an array',\n );\n }\n\n // Validate token_endpoint_auth_method if provided\n const supportedAuthMethods = [\n 'client_secret_basic',\n 'client_secret_post',\n 'none',\n ];\n if (\n registrationDto.token_endpoint_auth_method &&\n !supportedAuthMethods.includes(registrationDto.token_endpoint_auth_method)\n ) {\n throw new BadRequestException(\n `Unsupported token_endpoint_auth_method. Supported methods: ${supportedAuthMethods.join(', ')}`,\n );\n }\n\n // Default values for new clients\n const defaultClientValues = {\n grant_types: ['authorization_code', 'refresh_token'],\n response_types: ['code'],\n token_endpoint_auth_method:\n registrationDto.token_endpoint_auth_method || 'none',\n };\n\n // Check if client with same name already exists\n const existingClient = await this.findClientByName(\n registrationDto.client_name,\n );\n const now = new Date();\n\n if (existingClient) {\n // If redirect_uris differ, block the change for security reasons\n const incomingUris = Array.from(\n new Set(registrationDto.redirect_uris || []),\n );\n const existingUris = new Set(existingClient.redirect_uris || []);\n const sameSize = incomingUris.length === existingUris.size;\n const sameValues = sameSize && incomingUris.every((u) => existingUris.has(u));\n\n if (!sameValues) {\n const contact = this.options.supportEmail\n ? ` Please contact MCP Server support at ${this.options.supportEmail} to request a redirect URI change.`\n : ' Please contact MCP Server support to request a redirect URI change.';\n throw new BadRequestException(\n `Client \"${registrationDto.client_name}\" is already registered. Changing redirect_uris is not allowed for security reasons.${contact}`,\n );\n }\n\n // Update existing client - merge existing, defaults, and new values (keep original redirect_uris)\n const updatedClient: OAuthClient = {\n ...existingClient,\n ...defaultClientValues,\n ...registrationDto,\n redirect_uris: existingClient.redirect_uris,\n updated_at: now,\n };\n const nc = await this.store.storeClient(updatedClient);\n const filteredClient = Object.fromEntries(\n Object.entries(nc).filter(([, value]) => value !== null),\n ) as OAuthClient;\n return filteredClient;\n }\n\n // Create new client - merge defaults with registration data\n const client_id = this.store.generateClientId(\n registrationDto as OAuthClient,\n );\n\n // Only generate client_secret for methods that require it\n const authMethod = registrationDto.token_endpoint_auth_method || 'none';\n const client_secret =\n authMethod !== 'none' ? randomBytes(32).toString('hex') : undefined;\n\n const newClient: OAuthClient = {\n ...defaultClientValues,\n ...registrationDto,\n client_id,\n client_secret,\n created_at: now,\n updated_at: now,\n };\n const client = await this.store.storeClient(newClient);\n const filteredClient = Object.fromEntries(\n Object.entries(client).filter(([, value]) => value !== null),\n ) as OAuthClient;\n\n return filteredClient;\n }\n\n async getClient(clientId: string): Promise<OAuthClient | null> {\n const client = await this.store.getClient(clientId);\n if (!client) {\n return null;\n }\n\n // Remove null fields from the client object\n const filteredClient = Object.fromEntries(\n Object.entries(client).filter(([, value]) => value !== null),\n ) as OAuthClient;\n\n return filteredClient;\n }\n\n async validateRedirectUri(\n clientId: string,\n redirectUri: string,\n ): Promise<boolean> {\n const client = await this.getClient(clientId);\n return client ? client.redirect_uris.includes(redirectUri) : false;\n }\n\n private async findClientByName(\n clientName: string,\n ): Promise<OAuthClient | undefined> {\n // Use the new findClient method for efficient lookup\n return await this.store.findClient(clientName);\n }\n}\n"]}
1
+ {"version":3,"file":"client.service.js","sourceRoot":"","sources":["../../../src/authz/services/client.service.ts"],"names":[],"mappings":"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","sourcesContent":["import { BadRequestException, Injectable, Inject } from '@nestjs/common';\nimport {\n ClientRegistrationDto,\n IOAuthStore,\n OAuthClient,\n} from '../stores/oauth-store.interface';\nimport { randomBytes } from 'crypto';\nimport { OAuthModuleOptions } from '../providers/oauth-provider.interface';\n\n@Injectable()\nexport class ClientService {\n constructor(\n @Inject('IOAuthStore') private readonly store: IOAuthStore,\n @Inject('OAUTH_MODULE_OPTIONS')\n private readonly options: OAuthModuleOptions,\n ) {}\n\n /**\n * Register a client application.\n * Always creates a new client record. client_name is not treated as unique.\n *\n * Note: Left open for future enhancements (e.g., software statements,\n * URL-based Client ID Metadata Documents) via preRegistrationChecks().\n */\n async registerClient(\n registrationDto: ClientRegistrationDto,\n ): Promise<OAuthClient> {\n // Validate required fields\n if (\n !registrationDto.redirect_uris ||\n !Array.isArray(registrationDto.redirect_uris)\n ) {\n throw new BadRequestException(\n 'redirect_uris is required and must be an array',\n );\n }\n\n // Validate token_endpoint_auth_method if provided\n const supportedAuthMethods = [\n 'client_secret_basic',\n 'client_secret_post',\n 'none',\n ];\n if (\n registrationDto.token_endpoint_auth_method &&\n !supportedAuthMethods.includes(registrationDto.token_endpoint_auth_method)\n ) {\n throw new BadRequestException(\n `Unsupported token_endpoint_auth_method. Supported methods: ${supportedAuthMethods.join(', ')}`,\n );\n }\n\n // Default values for new clients\n const defaultClientValues = {\n grant_types: ['authorization_code', 'refresh_token'],\n response_types: ['code'],\n token_endpoint_auth_method:\n registrationDto.token_endpoint_auth_method || 'none',\n };\n\n // Future-proofing: hook for software statements / metadata URL validations\n await this.preRegistrationChecks(registrationDto);\n\n const now = new Date();\n\n // Create new client - merge defaults with registration data\n const client_id = this.store.generateClientId(\n registrationDto as OAuthClient,\n );\n\n // Only generate client_secret for methods that require it\n const authMethod = registrationDto.token_endpoint_auth_method || 'none';\n const client_secret =\n authMethod !== 'none' ? randomBytes(32).toString('hex') : undefined;\n\n const newClient: OAuthClient = {\n ...defaultClientValues,\n ...registrationDto,\n client_id,\n client_secret,\n created_at: now,\n updated_at: now,\n };\n const client = await this.store.storeClient(newClient);\n const filteredClient = Object.fromEntries(\n Object.entries(client).filter(([, value]) => value !== null),\n ) as OAuthClient;\n\n return filteredClient;\n }\n\n /**\n * Hook for future registration policies (e.g., software statements per RFC 7591/7592,\n * or URL-based Client Registration using Client ID Metadata Documents).\n * Currently a no-op to keep behavior: always create a new client.\n */\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n protected async preRegistrationChecks(_dto: ClientRegistrationDto): Promise<void> {\n // Intentionally left blank. Implement validations/attestations in the future.\n }\n\n async getClient(clientId: string): Promise<OAuthClient | null> {\n const client = await this.store.getClient(clientId);\n if (!client) {\n return null;\n }\n\n // Remove null fields from the client object\n const filteredClient = Object.fromEntries(\n Object.entries(client).filter(([, value]) => value !== null),\n ) as OAuthClient;\n\n return filteredClient;\n }\n\n async validateRedirectUri(\n clientId: string,\n redirectUri: string,\n ): Promise<boolean> {\n const client = await this.getClient(clientId);\n return client ? client.redirect_uris.includes(redirectUri) : false;\n }\n\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rekog/mcp-nest",
3
- "version": "1.7.4-alpha.0",
3
+ "version": "1.7.4-alpha.2",
4
4
  "description": "NestJS module for creating Model Context Protocol (MCP) servers",
5
5
  "main": "dist/index.js",
6
6
  "license": "MIT",
@@ -328,7 +328,7 @@ export function createMcpOAuthController(
328
328
  @Header('content-type', 'application/json')
329
329
  @Header('Cache-Control', 'no-store')
330
330
  @Header('Pragma', 'no-cache')
331
- @HttpCode(201)
331
+ @HttpCode(200)
332
332
  async exchangeToken(
333
333
  @Body() body: any,
334
334
  @Req() req: any,
@@ -91,9 +91,6 @@ export interface OAuthUserModuleOptions {
91
91
 
92
92
  // Endpoint Configuration
93
93
  endpoints?: OAuthEndpointConfiguration;
94
-
95
- // Optional support contact for operational issues
96
- supportEmail?: string;
97
94
  }
98
95
 
99
96
  export interface OAuthModuleDefaults {
@@ -135,8 +132,6 @@ export type OAuthModuleOptions = Required<
135
132
  // Optional fields that may remain undefined
136
133
  cookieSecure: boolean;
137
134
  storeConfiguration?: StoreConfiguration;
138
- // Optional support contact
139
- supportEmail?: string;
140
135
  };
141
136
 
142
137
  export interface OAuthSession {
@@ -16,8 +16,11 @@ export class ClientService {
16
16
  ) {}
17
17
 
18
18
  /**
19
- * Register or update a client application
20
- * If client with same name exists, update it; otherwise create new
19
+ * Register a client application.
20
+ * Always creates a new client record. client_name is not treated as unique.
21
+ *
22
+ * Note: Left open for future enhancements (e.g., software statements,
23
+ * URL-based Client ID Metadata Documents) via preRegistrationChecks().
21
24
  */
22
25
  async registerClient(
23
26
  registrationDto: ClientRegistrationDto,
@@ -55,44 +58,10 @@ export class ClientService {
55
58
  registrationDto.token_endpoint_auth_method || 'none',
56
59
  };
57
60
 
58
- // Check if client with same name already exists
59
- const existingClient = await this.findClientByName(
60
- registrationDto.client_name,
61
- );
62
- const now = new Date();
61
+ // Future-proofing: hook for software statements / metadata URL validations
62
+ await this.preRegistrationChecks(registrationDto);
63
63
 
64
- if (existingClient) {
65
- // If redirect_uris differ, block the change for security reasons
66
- const incomingUris = Array.from(
67
- new Set(registrationDto.redirect_uris || []),
68
- );
69
- const existingUris = new Set(existingClient.redirect_uris || []);
70
- const sameSize = incomingUris.length === existingUris.size;
71
- const sameValues = sameSize && incomingUris.every((u) => existingUris.has(u));
72
-
73
- if (!sameValues) {
74
- const contact = this.options.supportEmail
75
- ? ` Please contact MCP Server support at ${this.options.supportEmail} to request a redirect URI change.`
76
- : ' Please contact MCP Server support to request a redirect URI change.';
77
- throw new BadRequestException(
78
- `Client "${registrationDto.client_name}" is already registered. Changing redirect_uris is not allowed for security reasons.${contact}`,
79
- );
80
- }
81
-
82
- // Update existing client - merge existing, defaults, and new values (keep original redirect_uris)
83
- const updatedClient: OAuthClient = {
84
- ...existingClient,
85
- ...defaultClientValues,
86
- ...registrationDto,
87
- redirect_uris: existingClient.redirect_uris,
88
- updated_at: now,
89
- };
90
- const nc = await this.store.storeClient(updatedClient);
91
- const filteredClient = Object.fromEntries(
92
- Object.entries(nc).filter(([, value]) => value !== null),
93
- ) as OAuthClient;
94
- return filteredClient;
95
- }
64
+ const now = new Date();
96
65
 
97
66
  // Create new client - merge defaults with registration data
98
67
  const client_id = this.store.generateClientId(
@@ -120,6 +89,16 @@ export class ClientService {
120
89
  return filteredClient;
121
90
  }
122
91
 
92
+ /**
93
+ * Hook for future registration policies (e.g., software statements per RFC 7591/7592,
94
+ * or URL-based Client Registration using Client ID Metadata Documents).
95
+ * Currently a no-op to keep behavior: always create a new client.
96
+ */
97
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
98
+ protected async preRegistrationChecks(_dto: ClientRegistrationDto): Promise<void> {
99
+ // Intentionally left blank. Implement validations/attestations in the future.
100
+ }
101
+
123
102
  async getClient(clientId: string): Promise<OAuthClient | null> {
124
103
  const client = await this.store.getClient(clientId);
125
104
  if (!client) {
@@ -142,10 +121,4 @@ export class ClientService {
142
121
  return client ? client.redirect_uris.includes(redirectUri) : false;
143
122
  }
144
123
 
145
- private async findClientByName(
146
- clientName: string,
147
- ): Promise<OAuthClient | undefined> {
148
- // Use the new findClient method for efficient lookup
149
- return await this.store.findClient(clientName);
150
- }
151
124
  }