@rekog/mcp-nest 1.7.0 → 1.7.1
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.
- package/README.md +10 -8
- package/dist/authz/mcp-oauth.controller.d.ts +3 -1
- package/dist/authz/mcp-oauth.controller.d.ts.map +1 -1
- package/dist/authz/mcp-oauth.controller.js +25 -6
- package/dist/authz/mcp-oauth.controller.js.map +1 -1
- package/dist/authz/mcp-oauth.module.d.ts.map +1 -1
- package/dist/authz/mcp-oauth.module.js +1 -0
- package/dist/authz/mcp-oauth.module.js.map +1 -1
- package/dist/authz/providers/oauth-provider.interface.d.ts +3 -0
- package/dist/authz/providers/oauth-provider.interface.d.ts.map +1 -1
- package/dist/authz/providers/oauth-provider.interface.js.map +1 -1
- package/dist/authz/services/jwt-token.service.d.ts +5 -7
- package/dist/authz/services/jwt-token.service.d.ts.map +1 -1
- package/dist/authz/services/jwt-token.service.js +80 -44
- package/dist/authz/services/jwt-token.service.js.map +1 -1
- package/dist/authz/stores/memory-store.service.spec.js +188 -0
- package/dist/authz/stores/memory-store.service.spec.js.map +1 -1
- package/dist/authz/stores/oauth-store.interface.d.ts +2 -0
- package/dist/authz/stores/oauth-store.interface.d.ts.map +1 -1
- package/dist/authz/stores/oauth-store.interface.js.map +1 -1
- package/dist/authz/stores/typeorm/entities/authorization-code.entity.d.ts +1 -0
- package/dist/authz/stores/typeorm/entities/authorization-code.entity.d.ts.map +1 -1
- package/dist/authz/stores/typeorm/entities/authorization-code.entity.js +4 -0
- package/dist/authz/stores/typeorm/entities/authorization-code.entity.js.map +1 -1
- package/dist/authz/stores/typeorm/entities/oauth-session.entity.d.ts +1 -0
- package/dist/authz/stores/typeorm/entities/oauth-session.entity.d.ts.map +1 -1
- package/dist/authz/stores/typeorm/entities/oauth-session.entity.js +4 -0
- package/dist/authz/stores/typeorm/entities/oauth-session.entity.js.map +1 -1
- package/dist/authz/stores/typeorm/typeorm-store.service.spec.d.ts +2 -0
- package/dist/authz/stores/typeorm/typeorm-store.service.spec.d.ts.map +1 -0
- package/dist/authz/stores/typeorm/typeorm-store.service.spec.js +319 -0
- package/dist/authz/stores/typeorm/typeorm-store.service.spec.js.map +1 -0
- package/dist/mcp/transport/streamable-http.controller.factory.d.ts.map +1 -1
- package/dist/mcp/transport/streamable-http.controller.factory.js +4 -0
- package/dist/mcp/transport/streamable-http.controller.factory.js.map +1 -1
- package/package.json +1 -1
- package/src/authz/mcp-oauth.controller.ts +41 -18
- package/src/authz/mcp-oauth.module.ts +1 -0
- package/src/authz/providers/oauth-provider.interface.ts +3 -1
- package/src/authz/services/jwt-token.service.ts +82 -76
- package/src/authz/stores/memory-store.service.spec.ts +237 -1
- package/src/authz/stores/oauth-store.interface.ts +2 -0
- package/src/authz/stores/typeorm/entities/authorization-code.entity.ts +3 -0
- package/src/authz/stores/typeorm/entities/oauth-session.entity.ts +3 -0
- package/src/authz/stores/typeorm/typeorm-store.service.spec.ts +450 -0
- package/src/mcp/transport/streamable-http.controller.factory.ts +4 -0
- package/src/authz/stores/sqlite/sqlite-store.service.ts +0 -279
package/README.md
CHANGED
|
@@ -17,16 +17,18 @@ With `@rekog/mcp-nest` you define tools, resources, and prompts in a way that's
|
|
|
17
17
|
|
|
18
18
|
## Features
|
|
19
19
|
|
|
20
|
-
- 🚀 **Multi-Transport Support**: HTTP+SSE, Streamable HTTP, and STDIO
|
|
20
|
+
- 🚀 **[Multi-Transport Support](docs/server-examples.md#multiple-transport-types)**: HTTP+SSE, Streamable HTTP, and STDIO
|
|
21
21
|
- 🔧 **[Tools](docs/tools.md)**: Expose NestJS methods as MCP tools with automatic discovery and Zod validation
|
|
22
|
+
- 🛠️ **[Elicitation](docs/tools.md#interactive-tool-calls)**: Interactive tool calls with user input elicitation
|
|
23
|
+
- 📊 **[Progress Notifications](docs/tools.md#tool-with-progress-reporting)**: Real-time progress updates for long-running operations
|
|
24
|
+
- 🌐 **[HTTP Request Access](docs/tools.md#understanding-tool-method-parameters)**: Full access to request context within MCP handlers
|
|
22
25
|
- 📁 **[Resources](docs/resources.md)**: Serve content and data through MCP resource system
|
|
23
26
|
- 📚 **[Resource Templates](docs/resource-templates.md)**: Dynamic resources with parameterized URIs
|
|
24
27
|
- 💬 **[Prompts](docs/prompts.md)**: Define reusable prompt templates for AI interactions
|
|
25
|
-
-
|
|
26
|
-
-
|
|
27
|
-
-
|
|
28
|
-
-
|
|
29
|
-
- 💉 **Dependency Injection**: Leverage NestJS DI system throughout MCP components
|
|
28
|
+
- 🔐 **[Guard-based Authentication](docs/server-examples.md#server-with-authentication)**: Guard-based security with OAuth support
|
|
29
|
+
- 🏠 **[Built-in Authorization Server](docs/built-in-authorization-server.md)** — Using the built-in Authorization Server for easy setups. **(Beta)**
|
|
30
|
+
- 🌐 **[External Authorization Server](docs/external-authorization-server/README.md)** — Securing your MCP server with an external authorization server (Keycloak, Auth0, etc).
|
|
31
|
+
- 💉 **[Dependency Injection](docs/dependency-injection.md)**: Leverage NestJS DI system throughout MCP components
|
|
30
32
|
|
|
31
33
|
## Installation
|
|
32
34
|
|
|
@@ -83,8 +85,8 @@ export class GreetingTool {
|
|
|
83
85
|
- **[Resource Templates Guide](docs/resource-templates.md)** - Create parameterized resources
|
|
84
86
|
- **[Prompts Guide](docs/prompts.md)** - Build reusable prompt templates
|
|
85
87
|
- **[Built-in Authorization Server](docs/built-in-authorization-server.md)** - Secure your MCP server with built-in OAuth
|
|
86
|
-
- **[External Authorization Server](docs/
|
|
87
|
-
- **[Server examples](docs/examples.md)** - MCP servers examples (Streamable HTTP, HTTP, and STDIO) and with Fastify support
|
|
88
|
+
- **[External Authorization Server](docs/external-authorization-server/README.md)** - Securing your MCP server with an external authorization server (Keycloak, Auth0, etc)
|
|
89
|
+
- **[Server examples](docs/server-examples.md)** - MCP servers examples (Streamable HTTP, HTTP, and STDIO) and with Fastify support
|
|
88
90
|
|
|
89
91
|
## Playground
|
|
90
92
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Logger } from '@nestjs/common';
|
|
1
2
|
import { Request as ExpressRequest, NextFunction, Response } from 'express';
|
|
2
3
|
import { AuthenticatedRequest } from './guards/jwt-auth.guard';
|
|
3
4
|
import { OAuthEndpointConfiguration, OAuthModuleOptions, OAuthUserProfile } from './providers/oauth-provider.interface';
|
|
@@ -13,6 +14,7 @@ interface OAuthCallbackRequest extends ExpressRequest {
|
|
|
13
14
|
}
|
|
14
15
|
export declare function createMcpOAuthController(endpoints?: OAuthEndpointConfiguration): {
|
|
15
16
|
new (options: OAuthModuleOptions, store: IOAuthStore, jwtTokenService: JwtTokenService, clientService: ClientService): {
|
|
17
|
+
readonly logger: Logger;
|
|
16
18
|
readonly serverUrl: string;
|
|
17
19
|
readonly isProduction: boolean;
|
|
18
20
|
readonly options: OAuthModuleOptions;
|
|
@@ -36,7 +38,7 @@ export declare function createMcpOAuthController(endpoints?: OAuthEndpointConfig
|
|
|
36
38
|
handleProviderCallback(req: OAuthCallbackRequest, res: Response, next: NextFunction): void;
|
|
37
39
|
processAuthenticationSuccess(req: OAuthCallbackRequest, res: Response): Promise<void>;
|
|
38
40
|
exchangeToken(body: any): Promise<TokenPair>;
|
|
39
|
-
handleAuthorizationCodeGrant(code: string, code_verifier: string,
|
|
41
|
+
handleAuthorizationCodeGrant(code: string, code_verifier: string, _redirect_uri: string, client_id: string): Promise<TokenPair>;
|
|
40
42
|
handleRefreshTokenGrant(refresh_token: string): TokenPair;
|
|
41
43
|
validateToken(req: AuthenticatedRequest): {
|
|
42
44
|
valid: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-oauth.controller.d.ts","sourceRoot":"","sources":["../../src/authz/mcp-oauth.controller.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"mcp-oauth.controller.d.ts","sourceRoot":"","sources":["../../src/authz/mcp-oauth.controller.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,MAAM,EAOP,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAE5E,OAAO,EAAE,oBAAoB,EAAmB,MAAM,yBAAyB,CAAC;AAChF,OAAO,EACL,0BAA0B,EAC1B,kBAAkB,EAElB,gBAAgB,EACjB,MAAM,sCAAsC,CAAC;AAC9C,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAE1E,OAAO,EACL,qBAAqB,EACrB,WAAW,EACZ,MAAM,gCAAgC,CAAC;AAGxC,UAAU,oBAAqB,SAAQ,cAAc;IACnD,IAAI,CAAC,EAAE;QACL,OAAO,EAAE,gBAAgB,CAAC;QAC1B,WAAW,EAAE,MAAM,CAAC;QACpB,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC;CACH;AAED,wBAAgB,wBAAwB,CACtC,SAAS,GAAE,0BAA+B;kBASG,kBAAkB,SACpB,WAAW,mBACxB,eAAe,iBACjB,aAAa;;4BAPnB,MAAM;+BACH,OAAO;0BACZ,kBAAkB;wBAGK,WAAW;kCACxB,eAAe;gCACjB,aAAa;;;;;;;;;;;;;wCAqCO,qBAAqB;yBAMjD,GAAG,OAEd,GAAG,OACI,QAAQ,QACN,YAAY;oCA0Ed,oBAAoB,OACpB,QAAQ,QACN,YAAY;0CA2BrB,oBAAoB,OACpB,QAAQ;4BAwEmB,GAAG,GAAG,OAAO,CAAC,SAAS,CAAC;2CAyBlD,MAAM,iBACG,MAAM,iBACN,MAAM,aACV,MAAM,GAChB,OAAO,CAAC,SAAS,CAAC;+CA+DkB,MAAM,GAAG,SAAS;2BAW/B,oBAAoB;;;;;;;oCAW7B,MAAM,kBACL,MAAM,UACd,MAAM,GACb,OAAO;;EAcb"}
|
|
@@ -25,11 +25,13 @@ const jwt_token_service_1 = require("./services/jwt-token.service");
|
|
|
25
25
|
const oauth_strategy_service_1 = require("./services/oauth-strategy.service");
|
|
26
26
|
const normalize_endpoint_1 = require("../mcp/utils/normalize-endpoint");
|
|
27
27
|
function createMcpOAuthController(endpoints = {}) {
|
|
28
|
-
|
|
28
|
+
var McpOAuthController_1;
|
|
29
|
+
let McpOAuthController = McpOAuthController_1 = class McpOAuthController {
|
|
29
30
|
constructor(options, store, jwtTokenService, clientService) {
|
|
30
31
|
this.store = store;
|
|
31
32
|
this.jwtTokenService = jwtTokenService;
|
|
32
33
|
this.clientService = clientService;
|
|
34
|
+
this.logger = new common_1.Logger(McpOAuthController_1.name);
|
|
33
35
|
this.serverUrl = options.serverUrl;
|
|
34
36
|
this.isProduction = options.cookieSecure;
|
|
35
37
|
this.options = options;
|
|
@@ -56,7 +58,8 @@ function createMcpOAuthController(endpoints = {}) {
|
|
|
56
58
|
return await this.clientService.registerClient(registrationDto);
|
|
57
59
|
}
|
|
58
60
|
async authorize(query, req, res, next) {
|
|
59
|
-
const { response_type, client_id, redirect_uri, code_challenge, code_challenge_method, state,
|
|
61
|
+
const { response_type, client_id, redirect_uri, code_challenge, code_challenge_method, state, } = query;
|
|
62
|
+
const resource = this.options.resource;
|
|
60
63
|
if (response_type !== 'code') {
|
|
61
64
|
throw new common_1.BadRequestException('Only response_type=code is supported');
|
|
62
65
|
}
|
|
@@ -81,6 +84,7 @@ function createMcpOAuthController(endpoints = {}) {
|
|
|
81
84
|
codeChallenge: code_challenge,
|
|
82
85
|
codeChallengeMethod: code_challenge_method || 'plain',
|
|
83
86
|
oauthState: state,
|
|
87
|
+
scope: query.scope || '',
|
|
84
88
|
resource,
|
|
85
89
|
expiresAt: Date.now() + this.options.oauthSessionExpiresIn,
|
|
86
90
|
};
|
|
@@ -103,7 +107,7 @@ function createMcpOAuthController(endpoints = {}) {
|
|
|
103
107
|
passport_1.default.authenticate(oauth_strategy_service_1.STRATEGY_NAME, { session: false }, async (err, user) => {
|
|
104
108
|
try {
|
|
105
109
|
if (err) {
|
|
106
|
-
|
|
110
|
+
this.logger.error('OAuth callback error:', err);
|
|
107
111
|
throw new common_1.BadRequestException('Authentication failed');
|
|
108
112
|
}
|
|
109
113
|
if (!user) {
|
|
@@ -151,6 +155,8 @@ function createMcpOAuthController(endpoints = {}) {
|
|
|
151
155
|
code_challenge: session.codeChallenge,
|
|
152
156
|
code_challenge_method: session.codeChallengeMethod,
|
|
153
157
|
expires_at: Date.now() + this.options.authCodeExpiresIn,
|
|
158
|
+
resource: session.resource,
|
|
159
|
+
scope: session.scope,
|
|
154
160
|
github_access_token: '',
|
|
155
161
|
});
|
|
156
162
|
const redirectUrl = new URL(session.redirectUri);
|
|
@@ -173,26 +179,39 @@ function createMcpOAuthController(endpoints = {}) {
|
|
|
173
179
|
throw new common_1.BadRequestException('Unsupported grant_type');
|
|
174
180
|
}
|
|
175
181
|
}
|
|
176
|
-
async handleAuthorizationCodeGrant(code, code_verifier,
|
|
182
|
+
async handleAuthorizationCodeGrant(code, code_verifier, _redirect_uri, client_id) {
|
|
183
|
+
this.logger.debug('handleAuthorizationCodeGrant - Params:', {
|
|
184
|
+
code,
|
|
185
|
+
client_id,
|
|
186
|
+
});
|
|
177
187
|
const authCode = await this.store.getAuthCode(code);
|
|
178
188
|
if (!authCode) {
|
|
189
|
+
this.logger.error('handleAuthorizationCodeGrant - Invalid authorization code:', code);
|
|
179
190
|
throw new common_1.BadRequestException('Invalid authorization code');
|
|
180
191
|
}
|
|
181
192
|
if (authCode.expires_at < Date.now()) {
|
|
182
193
|
await this.store.removeAuthCode(code);
|
|
194
|
+
this.logger.error('handleAuthorizationCodeGrant - Authorization code expired:', code);
|
|
183
195
|
throw new common_1.BadRequestException('Authorization code has expired');
|
|
184
196
|
}
|
|
185
197
|
if (authCode.client_id !== client_id) {
|
|
198
|
+
this.logger.error('handleAuthorizationCodeGrant - Client ID mismatch:', { expected: authCode.client_id, got: client_id });
|
|
186
199
|
throw new common_1.BadRequestException('Client ID mismatch');
|
|
187
200
|
}
|
|
188
201
|
if (authCode.code_challenge) {
|
|
189
202
|
const isValid = this.validatePKCE(code_verifier, authCode.code_challenge, authCode.code_challenge_method);
|
|
190
203
|
if (!isValid) {
|
|
204
|
+
this.logger.error('handleAuthorizationCodeGrant - Invalid PKCE verification');
|
|
191
205
|
throw new common_1.BadRequestException('Invalid PKCE verification');
|
|
192
206
|
}
|
|
193
207
|
}
|
|
194
|
-
|
|
208
|
+
if (!authCode.resource) {
|
|
209
|
+
this.logger.error('handleAuthorizationCodeGrant - No resource associated with code');
|
|
210
|
+
throw new common_1.BadRequestException('Authorization code is not associated with a resource');
|
|
211
|
+
}
|
|
212
|
+
const tokens = this.jwtTokenService.generateTokenPair(authCode.user_id, client_id, authCode.scope, authCode.resource);
|
|
195
213
|
await this.store.removeAuthCode(code);
|
|
214
|
+
this.logger.log('handleAuthorizationCodeGrant - Token pair generated for user:', authCode.user_id);
|
|
196
215
|
return tokens;
|
|
197
216
|
}
|
|
198
217
|
handleRefreshTokenGrant(refresh_token) {
|
|
@@ -271,7 +290,7 @@ function createMcpOAuthController(endpoints = {}) {
|
|
|
271
290
|
__metadata("design:paramtypes", [Object]),
|
|
272
291
|
__metadata("design:returntype", void 0)
|
|
273
292
|
], McpOAuthController.prototype, "validateToken", null);
|
|
274
|
-
McpOAuthController = __decorate([
|
|
293
|
+
McpOAuthController = McpOAuthController_1 = __decorate([
|
|
275
294
|
(0, common_1.Controller)(),
|
|
276
295
|
__param(0, (0, common_1.Inject)('OAUTH_MODULE_OPTIONS')),
|
|
277
296
|
__param(1, (0, common_1.Inject)('IOAuthStore')),
|
|
@@ -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 Inject,\n Next,\n Post,\n Query,\n Req,\n Res,\n UseGuards,\n} from '@nestjs/common';\nimport { createHash, randomBytes } from 'crypto';\nimport { Request as ExpressRequest, NextFunction, Response } from 'express';\nimport passport from 'passport';\nimport { AuthenticatedRequest, McpAuthJwtGuard } from './guards/jwt-auth.guard';\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 {\n ClientRegistrationDto,\n IOAuthStore,\n} from './stores/oauth-store.interface';\nimport { normalizeEndpoint } from '../mcp/utils/normalize-endpoint';\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 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 // OAuth endpoints\n @Get(endpoints.wellKnown)\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: ['code'],\n response_modes_supported: ['query'],\n grant_types_supported: ['authorization_code', 'refresh_token'],\n token_endpoint_auth_methods_supported: [\n 'client_secret_basic',\n 'client_secret_post',\n 'none',\n ],\n revocation_endpoint: normalizeEndpoint(\n `${this.serverUrl}/${endpoints?.revoke}`,\n ),\n code_challenge_methods_supported: ['plain', 'S256'],\n };\n }\n\n @Post(endpoints.register)\n async registerClient(@Body() registrationDto: ClientRegistrationDto) {\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 resource,\n } = query;\n\n // Validate parameters\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 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 console.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 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 // Token endpoints (remain the same)\n @Post(endpoints.token)\n async exchangeToken(@Body() body: any): Promise<TokenPair> {\n const {\n grant_type,\n code,\n code_verifier,\n redirect_uri,\n client_id,\n refresh_token,\n } = body;\n\n if (grant_type === 'authorization_code') {\n return this.handleAuthorizationCodeGrant(\n code,\n code_verifier,\n redirect_uri,\n client_id,\n );\n } else if (grant_type === 'refresh_token') {\n return this.handleRefreshTokenGrant(refresh_token);\n } else {\n throw new BadRequestException('Unsupported grant_type');\n }\n }\n\n async handleAuthorizationCodeGrant(\n code: string,\n code_verifier: string,\n redirect_uri: string,\n client_id: string,\n ): Promise<TokenPair> {\n // Validate the authorization code\n const authCode = await this.store.getAuthCode(code);\n if (!authCode) {\n throw new BadRequestException('Invalid authorization code');\n }\n\n // Check if code has expired\n if (authCode.expires_at < Date.now()) {\n await this.store.removeAuthCode(code);\n throw new BadRequestException('Authorization code has expired');\n }\n\n // Validate client_id matches\n if (authCode.client_id !== client_id) {\n throw new BadRequestException('Client ID mismatch');\n }\n\n // Validate PKCE if required\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 throw new BadRequestException('Invalid PKCE verification');\n }\n }\n\n // Generate tokens\n const tokens = this.jwtTokenService.generateTokenPair(\n authCode.user_id,\n client_id,\n 'mcp:access',\n );\n\n // Remove the used authorization code\n await this.store.removeAuthCode(code);\n\n return tokens;\n }\n\n handleRefreshTokenGrant(refresh_token: string): TokenPair {\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 @Get(endpoints.validate)\n @UseGuards(McpAuthJwtGuard)\n validateToken(@Req() req: AuthenticatedRequest) {\n return {\n valid: true,\n user_id: req.user.sub,\n client_id: req.user.client_id,\n scope: req.user.scope,\n expires_at: req.user.exp! * 1000,\n };\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":";;;;;;;;;;;;;;;;;AAyCA,4DA+WC;AAxZD,2CAawB;AACxB,mCAAiD;AAEjD,wDAAgC;AAChC,4DAAgF;AAOhF,8DAA0D;AAC1D,oEAA0E;AAC1E,8EAAkE;AAKlE,wEAAoE;AAUpE,SAAgB,wBAAwB,CACtC,YAAwC,EAAE;;IAE1C,IACM,kBAAkB,0BADxB,MACM,kBAAkB;QAKtB,YACkC,OAA2B,EACpC,KAA2B,EACzC,eAAgC,EAChC,aAA4B;YAFL,UAAK,GAAL,KAAK,CAAa;YACzC,oBAAe,GAAf,eAAe,CAAiB;YAChC,kBAAa,GAAb,aAAa,CAAe;YAR9B,WAAM,GAAG,IAAI,eAAM,CAAC,oBAAkB,CAAC,IAAI,CAAC,CAAC;YAUpD,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC;YACnC,IAAI,CAAC,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC;YACzC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACzB,CAAC;QAID,8BAA8B;YAC5B,OAAO;gBACL,MAAM,EAAE,IAAI,CAAC,SAAS;gBACtB,sBAAsB,EAAE,IAAA,sCAAiB,EACvC,GAAG,IAAI,CAAC,SAAS,IAAI,SAAS,CAAC,SAAS,EAAE,CAC3C;gBACD,cAAc,EAAE,IAAA,sCAAiB,EAC/B,GAAG,IAAI,CAAC,SAAS,IAAI,SAAS,CAAC,KAAK,EAAE,CACvC;gBACD,qBAAqB,EAAE,IAAA,sCAAiB,EACtC,GAAG,IAAI,CAAC,SAAS,IAAI,SAAS,CAAC,QAAQ,EAAE,CAC1C;gBACD,wBAAwB,EAAE,CAAC,MAAM,CAAC;gBAClC,wBAAwB,EAAE,CAAC,OAAO,CAAC;gBACnC,qBAAqB,EAAE,CAAC,oBAAoB,EAAE,eAAe,CAAC;gBAC9D,qCAAqC,EAAE;oBACrC,qBAAqB;oBACrB,oBAAoB;oBACpB,MAAM;iBACP;gBACD,mBAAmB,EAAE,IAAA,sCAAiB,EACpC,GAAG,IAAI,CAAC,SAAS,IAAI,SAAS,EAAE,MAAM,EAAE,CACzC;gBACD,gCAAgC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC;aACpD,CAAC;QACJ,CAAC;QAGK,AAAN,KAAK,CAAC,cAAc,CAAS,eAAsC;YACjE,OAAO,MAAM,IAAI,CAAC,aAAa,CAAC,cAAc,CAAC,eAAe,CAAC,CAAC;QAClE,CAAC;QAGK,AAAN,KAAK,CAAC,SAAS,CACJ,KAAU,EAEnB,GAAQ,EACD,GAAa,EACZ,IAAkB;YAE1B,MAAM,EACJ,aAAa,EACb,SAAS,EACT,YAAY,EACZ,cAAc,EACd,qBAAqB,EACrB,KAAK,GACN,GAAG,KAAK,CAAC;YACV,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC;YACvC,IAAI,aAAa,KAAK,MAAM,EAAE,CAAC;gBAC7B,MAAM,IAAI,4BAAmB,CAAC,sCAAsC,CAAC,CAAC;YACxE,CAAC;YAED,IAAI,CAAC,SAAS,EAAE,CAAC;gBACf,MAAM,IAAI,4BAAmB,CAAC,6BAA6B,CAAC,CAAC;YAC/D,CAAC;YAGD,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;YAC7D,IAAI,CAAC,MAAM,EAAE,CAAC;gBACZ,MAAM,IAAI,4BAAmB,CAAC,mBAAmB,CAAC,CAAC;YACrD,CAAC;YAED,MAAM,aAAa,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,mBAAmB,CAChE,SAAS,EACT,YAAY,CACb,CAAC;YACF,IAAI,CAAC,aAAa,EAAE,CAAC;gBACnB,MAAM,IAAI,4BAAmB,CAAC,sBAAsB,CAAC,CAAC;YACxD,CAAC;YAGD,MAAM,SAAS,GAAG,IAAA,oBAAW,EAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;YACxD,MAAM,YAAY,GAAG,IAAA,oBAAW,EAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;YAE3D,MAAM,YAAY,GAAiB;gBACjC,SAAS;gBACT,KAAK,EAAE,YAAY;gBACnB,QAAQ,EAAE,SAAS;gBACnB,WAAW,EAAE,YAAY;gBACzB,aAAa,EAAE,cAAc;gBAC7B,mBAAmB,EAAE,qBAAqB,IAAI,OAAO;gBACrD,UAAU,EAAE,KAAK;gBACjB,KAAK,EAAE,KAAK,CAAC,KAAK,IAAI,EAAE;gBACxB,QAAQ;gBACR,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,qBAAqB;aAC3D,CAAC;YAEF,MAAM,IAAI,CAAC,KAAK,CAAC,iBAAiB,CAAC,SAAS,EAAE,YAAY,CAAC,CAAC;YAG5D,GAAG,CAAC,MAAM,CAAC,eAAe,EAAE,SAAS,EAAE;gBACrC,QAAQ,EAAE,IAAI;gBACd,MAAM,EAAE,IAAI,CAAC,YAAY;gBACzB,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,qBAAqB;aAC3C,CAAC,CAAC;YAGH,GAAG,CAAC,MAAM,CAAC,aAAa,EAAE,YAAY,EAAE;gBACtC,QAAQ,EAAE,IAAI;gBACd,MAAM,EAAE,IAAI,CAAC,YAAY;gBACzB,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,qBAAqB;aAC3C,CAAC,CAAC;YAGH,kBAAQ,CAAC,YAAY,CAAC,sCAAa,EAAE;gBACnC,KAAK,EAAE,GAAG,CAAC,OAAO,EAAE,WAAW;aAChC,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;QACrB,CAAC;QAGD,sBAAsB,CACb,GAAyB,EACzB,GAAa,EACZ,IAAkB;YAG1B,kBAAQ,CAAC,YAAY,CACnB,sCAAa,EACb,EAAE,OAAO,EAAE,KAAK,EAAE,EAClB,KAAK,EAAE,GAAQ,EAAE,IAAS,EAAE,EAAE;gBAC5B,IAAI,CAAC;oBACH,IAAI,GAAG,EAAE,CAAC;wBACR,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,uBAAuB,EAAE,GAAG,CAAC,CAAC;wBAChD,MAAM,IAAI,4BAAmB,CAAC,uBAAuB,CAAC,CAAC;oBACzD,CAAC;oBAED,IAAI,CAAC,IAAI,EAAE,CAAC;wBACV,MAAM,IAAI,4BAAmB,CAAC,uBAAuB,CAAC,CAAC;oBACzD,CAAC;oBAED,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC;oBAChB,MAAM,IAAI,CAAC,4BAA4B,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;gBACpD,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,IAAI,CAAC,KAAK,CAAC,CAAC;gBACd,CAAC;YACH,CAAC,CACF,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;QACpB,CAAC;QAED,KAAK,CAAC,4BAA4B,CAChC,GAAyB,EACzB,GAAa;YAEb,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,CAAC;YACtB,IAAI,CAAC,IAAI,EAAE,CAAC;gBACV,MAAM,IAAI,4BAAmB,CAAC,uBAAuB,CAAC,CAAC;YACzD,CAAC;YAED,MAAM,SAAS,GAAG,GAAG,CAAC,OAAO,EAAE,aAAa,CAAC;YAC7C,IAAI,CAAC,SAAS,EAAE,CAAC;gBACf,MAAM,IAAI,4BAAmB,CAAC,uBAAuB,CAAC,CAAC;YACzD,CAAC;YAED,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,SAAS,CAAC,CAAC;YAC5D,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,MAAM,IAAI,4BAAmB,CAAC,kCAAkC,CAAC,CAAC;YACpE,CAAC;YAGD,MAAM,eAAe,GAAG,GAAG,CAAC,OAAO,EAAE,WAAW,CAAC;YACjD,IAAI,OAAO,CAAC,KAAK,KAAK,eAAe,EAAE,CAAC;gBACtC,MAAM,IAAI,4BAAmB,CAAC,yBAAyB,CAAC,CAAC;YAC3D,CAAC;YAGD,MAAM,GAAG,GAAG,IAAI,CAAC,eAAe,CAAC,iBAAiB,CAChD,IAAI,CAAC,OAAO,CAAC,QAAQ,EACrB,IAAI,CAAC,OAAO,CACb,CAAC;YAGF,GAAG,CAAC,MAAM,CAAC,YAAY,EAAE,GAAG,EAAE;gBAC5B,QAAQ,EAAE,IAAI;gBACd,MAAM,EAAE,IAAI,CAAC,YAAY;gBACzB,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,YAAY;aAClC,CAAC,CAAC;YAGH,GAAG,CAAC,WAAW,CAAC,eAAe,CAAC,CAAC;YACjC,GAAG,CAAC,WAAW,CAAC,aAAa,CAAC,CAAC;YAG/B,MAAM,QAAQ,GAAG,IAAA,oBAAW,EAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;YAGvD,MAAM,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC;gBAC7B,IAAI,EAAE,QAAQ;gBACd,OAAO,EAAE,IAAI,CAAC,OAAO,CAAC,QAAQ;gBAC9B,SAAS,EAAE,OAAO,CAAC,QAAS;gBAC5B,YAAY,EAAE,OAAO,CAAC,WAAY;gBAClC,cAAc,EAAE,OAAO,CAAC,aAAc;gBACtC,qBAAqB,EAAE,OAAO,CAAC,mBAAoB;gBACnD,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,iBAAiB;gBACvD,QAAQ,EAAE,OAAO,CAAC,QAAQ;gBAC1B,KAAK,EAAE,OAAO,CAAC,KAAK;gBACpB,mBAAmB,EAAE,EAAE;aACxB,CAAC,CAAC;YAGH,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,WAAY,CAAC,CAAC;YAClD,WAAW,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;YAC/C,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;gBACvB,WAAW,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;YAC5D,CAAC;YAGD,MAAM,IAAI,CAAC,KAAK,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC;YAE/C,GAAG,CAAC,QAAQ,CAAC,WAAW,CAAC,QAAQ,EAAE,CAAC,CAAC;QACvC,CAAC;QAIK,AAAN,KAAK,CAAC,aAAa,CAAS,IAAS;YACnC,MAAM,EACJ,UAAU,EACV,IAAI,EACJ,aAAa,EACb,YAAY,EACZ,SAAS,EACT,aAAa,GACd,GAAG,IAAI,CAAC;YAET,IAAI,UAAU,KAAK,oBAAoB,EAAE,CAAC;gBACxC,OAAO,IAAI,CAAC,4BAA4B,CACtC,IAAI,EACJ,aAAa,EACb,YAAY,EACZ,SAAS,CACV,CAAC;YACJ,CAAC;iBAAM,IAAI,UAAU,KAAK,eAAe,EAAE,CAAC;gBAC1C,OAAO,IAAI,CAAC,uBAAuB,CAAC,aAAa,CAAC,CAAC;YACrD,CAAC;iBAAM,CAAC;gBACN,MAAM,IAAI,4BAAmB,CAAC,wBAAwB,CAAC,CAAC;YAC1D,CAAC;QACH,CAAC;QAED,KAAK,CAAC,4BAA4B,CAChC,IAAY,EACZ,aAAqB,EACrB,aAAqB,EACrB,SAAiB;YAEjB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,wCAAwC,EAAE;gBAC1D,IAAI;gBACJ,SAAS;aACV,CAAC,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC;YACpD,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACd,IAAI,CAAC,MAAM,CAAC,KAAK,CACf,4DAA4D,EAC5D,IAAI,CACL,CAAC;gBACF,MAAM,IAAI,4BAAmB,CAAC,4BAA4B,CAAC,CAAC;YAC9D,CAAC;YACD,IAAI,QAAQ,CAAC,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;gBACrC,MAAM,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;gBACtC,IAAI,CAAC,MAAM,CAAC,KAAK,CACf,4DAA4D,EAC5D,IAAI,CACL,CAAC;gBACF,MAAM,IAAI,4BAAmB,CAAC,gCAAgC,CAAC,CAAC;YAClE,CAAC;YACD,IAAI,QAAQ,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;gBACrC,IAAI,CAAC,MAAM,CAAC,KAAK,CACf,oDAAoD,EACpD,EAAE,QAAQ,EAAE,QAAQ,CAAC,SAAS,EAAE,GAAG,EAAE,SAAS,EAAE,CACjD,CAAC;gBACF,MAAM,IAAI,4BAAmB,CAAC,oBAAoB,CAAC,CAAC;YACtD,CAAC;YACD,IAAI,QAAQ,CAAC,cAAc,EAAE,CAAC;gBAC5B,MAAM,OAAO,GAAG,IAAI,CAAC,YAAY,CAC/B,aAAa,EACb,QAAQ,CAAC,cAAc,EACvB,QAAQ,CAAC,qBAAqB,CAC/B,CAAC;gBACF,IAAI,CAAC,OAAO,EAAE,CAAC;oBACb,IAAI,CAAC,MAAM,CAAC,KAAK,CACf,0DAA0D,CAC3D,CAAC;oBACF,MAAM,IAAI,4BAAmB,CAAC,2BAA2B,CAAC,CAAC;gBAC7D,CAAC;YACH,CAAC;YACD,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC;gBACvB,IAAI,CAAC,MAAM,CAAC,KAAK,CACf,iEAAiE,CAClE,CAAC;gBACF,MAAM,IAAI,4BAAmB,CAC3B,sDAAsD,CACvD,CAAC;YACJ,CAAC;YACD,MAAM,MAAM,GAAG,IAAI,CAAC,eAAe,CAAC,iBAAiB,CACnD,QAAQ,CAAC,OAAO,EAChB,SAAS,EACT,QAAQ,CAAC,KAAK,EACd,QAAQ,CAAC,QAAQ,CAClB,CAAC;YACF,MAAM,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,IAAI,CAAC,CAAC;YACtC,IAAI,CAAC,MAAM,CAAC,GAAG,CACb,+DAA+D,EAC/D,QAAQ,CAAC,OAAO,CACjB,CAAC;YACF,OAAO,MAAM,CAAC;QAChB,CAAC;QAED,uBAAuB,CAAC,aAAqB;YAC3C,MAAM,SAAS,GAAG,IAAI,CAAC,eAAe,CAAC,kBAAkB,CAAC,aAAa,CAAC,CAAC;YACzE,IAAI,CAAC,SAAS,EAAE,CAAC;gBACf,MAAM,IAAI,4BAAmB,CAAC,yBAAyB,CAAC,CAAC;YAC3D,CAAC;YAED,OAAO,SAAS,CAAC;QACnB,CAAC;QAID,aAAa,CAAQ,GAAyB;YAC5C,OAAO;gBACL,KAAK,EAAE,IAAI;gBACX,OAAO,EAAE,GAAG,CAAC,IAAI,CAAC,GAAG;gBACrB,SAAS,EAAE,GAAG,CAAC,IAAI,CAAC,SAAS;gBAC7B,KAAK,EAAE,GAAG,CAAC,IAAI,CAAC,KAAK;gBACrB,UAAU,EAAE,GAAG,CAAC,IAAI,CAAC,GAAI,GAAG,IAAI;aACjC,CAAC;QACJ,CAAC;QAED,YAAY,CACV,aAAqB,EACrB,cAAsB,EACtB,MAAc;YAEd,IAAI,MAAM,KAAK,OAAO,EAAE,CAAC;gBACvB,OAAO,aAAa,KAAK,cAAc,CAAC;YAC1C,CAAC;iBAAM,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;gBAC7B,MAAM,IAAI,GAAG,IAAA,mBAAU,EAAC,QAAQ,CAAC;qBAC9B,MAAM,CAAC,aAAa,CAAC;qBACrB,MAAM,CAAC,WAAW,CAAC,CAAC;gBACvB,OAAO,IAAI,KAAK,cAAc,CAAC;YACjC,CAAC;YACD,OAAO,KAAK,CAAC;QACf,CAAC;KACF,CAAA;IAtVC;QADC,IAAA,YAAG,EAAC,SAAS,CAAC,SAAS,CAAC;;;;4EA0BxB;IAGK;QADL,IAAA,aAAI,EAAC,SAAS,CAAC,QAAQ,CAAC;QACH,WAAA,IAAA,aAAI,GAAE,CAAA;;;;4DAE3B;IAGK;QADL,IAAA,YAAG,EAAC,SAAS,CAAC,SAAS,CAAC;QAEtB,WAAA,IAAA,cAAK,GAAE,CAAA;QACP,WAAA,IAAA,YAAG,GAAE,CAAA;QAEL,WAAA,IAAA,YAAG,GAAE,CAAA;QACL,WAAA,IAAA,aAAI,GAAE,CAAA;;;;uDAsER;IAGD;QADC,IAAA,YAAG,EAAC,SAAS,CAAC,QAAQ,CAAC;QAErB,WAAA,IAAA,YAAG,GAAE,CAAA;QACL,WAAA,IAAA,YAAG,GAAE,CAAA;QACL,WAAA,IAAA,aAAI,GAAE,CAAA;;;;oEAwBR;IA4EK;QADL,IAAA,aAAI,EAAC,SAAS,CAAC,KAAK,CAAC;QACD,WAAA,IAAA,aAAI,GAAE,CAAA;;;;2DAsB1B;IAiFD;QAFC,IAAA,YAAG,EAAC,SAAS,CAAC,QAAQ,CAAC;QACvB,IAAA,kBAAS,EAAC,gCAAe,CAAC;QACZ,WAAA,IAAA,YAAG,GAAE,CAAA;;;;2DAQnB;IAvVG,kBAAkB;QADvB,IAAA,mBAAU,GAAE;QAOR,WAAA,IAAA,eAAM,EAAC,sBAAsB,CAAC,CAAA;QAC9B,WAAA,IAAA,eAAM,EAAC,aAAa,CAAC,CAAA;yDACI,mCAAe;YACjB,8BAAa;OATnC,kBAAkB,CAwWvB;IAED,OAAO,kBAAkB,CAAC;AAC5B,CAAC","sourcesContent":["import {\n BadRequestException,\n Body,\n Controller,\n Get,\n Inject,\n Logger,\n Next,\n Post,\n Query,\n Req,\n Res,\n UseGuards,\n} from '@nestjs/common';\nimport { createHash, randomBytes } from 'crypto';\nimport { Request as ExpressRequest, NextFunction, Response } from 'express';\nimport passport from 'passport';\nimport { AuthenticatedRequest, McpAuthJwtGuard } from './guards/jwt-auth.guard';\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 {\n ClientRegistrationDto,\n IOAuthStore,\n} from './stores/oauth-store.interface';\nimport { normalizeEndpoint } from '../mcp/utils/normalize-endpoint';\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 // OAuth endpoints\n @Get(endpoints.wellKnown)\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: ['code'],\n response_modes_supported: ['query'],\n grant_types_supported: ['authorization_code', 'refresh_token'],\n token_endpoint_auth_methods_supported: [\n 'client_secret_basic',\n 'client_secret_post',\n 'none',\n ],\n revocation_endpoint: normalizeEndpoint(\n `${this.serverUrl}/${endpoints?.revoke}`,\n ),\n code_challenge_methods_supported: ['plain', 'S256'],\n };\n }\n\n @Post(endpoints.register)\n async registerClient(@Body() registrationDto: ClientRegistrationDto) {\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 } = 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: query.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 // Token endpoints (remain the same)\n @Post(endpoints.token)\n async exchangeToken(@Body() body: any): Promise<TokenPair> {\n const {\n grant_type,\n code,\n code_verifier,\n redirect_uri,\n client_id,\n refresh_token,\n } = body;\n\n if (grant_type === 'authorization_code') {\n return this.handleAuthorizationCodeGrant(\n code,\n code_verifier,\n redirect_uri,\n client_id,\n );\n } else if (grant_type === 'refresh_token') {\n return this.handleRefreshTokenGrant(refresh_token);\n } else {\n throw new BadRequestException('Unsupported grant_type');\n }\n }\n\n async handleAuthorizationCodeGrant(\n code: string,\n code_verifier: string,\n _redirect_uri: string,\n client_id: string,\n ): Promise<TokenPair> {\n this.logger.debug('handleAuthorizationCodeGrant - Params:', {\n code,\n client_id,\n });\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 !== client_id) {\n this.logger.error(\n 'handleAuthorizationCodeGrant - Client ID mismatch:',\n { expected: authCode.client_id, got: client_id },\n );\n throw new BadRequestException('Client ID mismatch');\n }\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 const tokens = this.jwtTokenService.generateTokenPair(\n authCode.user_id,\n 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 handleRefreshTokenGrant(refresh_token: string): TokenPair {\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 @Get(endpoints.validate)\n @UseGuards(McpAuthJwtGuard)\n validateToken(@Req() req: AuthenticatedRequest) {\n return {\n valid: true,\n user_id: req.user.sub,\n client_id: req.user.client_id,\n scope: req.user.scope,\n expires_at: req.user.exp! * 1000,\n };\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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-oauth.module.d.ts","sourceRoot":"","sources":["../../src/authz/mcp-oauth.module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAkB,MAAM,gBAAgB,CAAC;AAO/D,OAAO,EACL,sBAAsB,IAAI,qBAAqB,EAE/C,mBAAmB,EAEpB,MAAM,sCAAsC,CAAC;AAc9C,eAAO,MAAM,eAAe,EAAE,
|
|
1
|
+
{"version":3,"file":"mcp-oauth.module.d.ts","sourceRoot":"","sources":["../../src/authz/mcp-oauth.module.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAkB,MAAM,gBAAgB,CAAC;AAO/D,OAAO,EACL,sBAAsB,IAAI,qBAAqB,EAE/C,mBAAmB,EAEpB,MAAM,sCAAsC,CAAC;AAc9C,eAAO,MAAM,eAAe,EAAE,mBAqB7B,CAAC;AAEF,qBAEa,aAAa;IACxB,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,qBAAqB,GAAG,aAAa;IAsG7D,OAAO,CAAC,MAAM,CAAC,uBAAuB;IAwBtC,OAAO,CAAC,MAAM,CAAC,uBAAuB;IAiBtC,OAAO,CAAC,MAAM,CAAC,uBAAuB;IA0BtC,OAAO,CAAC,MAAM,CAAC,mBAAmB;CA+BnC"}
|
|
@@ -24,6 +24,7 @@ const typeorm_store_service_1 = require("./stores/typeorm/typeorm-store.service"
|
|
|
24
24
|
const normalize_endpoint_1 = require("../mcp/utils/normalize-endpoint");
|
|
25
25
|
exports.DEFAULT_OPTIONS = {
|
|
26
26
|
serverUrl: 'https://localhost:3000',
|
|
27
|
+
resource: 'https://localhost:3000/mcp',
|
|
27
28
|
jwtIssuer: 'https://localhost:3000',
|
|
28
29
|
jwtAudience: 'mcp-client',
|
|
29
30
|
jwtAccessTokenExpiresIn: '60s',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-oauth.module.js","sourceRoot":"","sources":["../../src/authz/mcp-oauth.module.ts"],"names":[],"mappings":"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","sourcesContent":["import { DynamicModule, Global, Module } from '@nestjs/common';\nimport { ConfigModule } from '@nestjs/config';\nimport { JwtModule } from '@nestjs/jwt';\nimport { PassportModule } from '@nestjs/passport';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { McpAuthJwtGuard } from './guards/jwt-auth.guard';\nimport { createMcpOAuthController } from './mcp-oauth.controller';\nimport {\n OAuthUserModuleOptions as AuthUserModuleOptions,\n OAuthEndpointConfiguration,\n OAuthModuleDefaults,\n OAuthModuleOptions,\n} from './providers/oauth-provider.interface';\nimport { ClientService } from './services/client.service';\nimport { JwtTokenService } from './services/jwt-token.service';\nimport { OAuthStrategyService } from './services/oauth-strategy.service';\nimport { MemoryStore } from './stores/memory-store.service';\nimport {\n AuthorizationCodeEntity,\n OAuthClientEntity,\n OAuthSessionEntity,\n} from './stores/typeorm/entities';\nimport { TypeOrmStore } from './stores/typeorm/typeorm-store.service';\nimport { normalizeEndpoint } from '../mcp/utils/normalize-endpoint';\n\n// Default configuration values\nexport const DEFAULT_OPTIONS: OAuthModuleDefaults = {\n serverUrl: 'https://localhost:3000',\n jwtIssuer: 'https://localhost:3000',\n jwtAudience: 'mcp-client',\n jwtAccessTokenExpiresIn: '60s',\n jwtRefreshTokenExpiresIn: '30d',\n cookieMaxAge: 24 * 60 * 60 * 1000, // 24 hours\n oauthSessionExpiresIn: 10 * 60 * 1000, // 10 minutes\n authCodeExpiresIn: 10 * 60 * 1000, // 10 minutes\n nodeEnv: 'development',\n apiPrefix: '',\n endpoints: {\n wellKnown: '/.well-known/oauth-authorization-server',\n register: '/register',\n authorize: '/authorize',\n callback: '/callback',\n token: '/token',\n validate: '/validate',\n revoke: '/revoke',\n },\n};\n\n@Global()\n@Module({})\nexport class McpAuthModule {\n static forRoot(options: AuthUserModuleOptions): DynamicModule {\n // Merge user options with defaults and validate\n const resolvedOptions = this.mergeAndValidateOptions(\n DEFAULT_OPTIONS,\n options,\n );\n\n resolvedOptions.endpoints = prepareEndpoints(\n resolvedOptions.apiPrefix,\n DEFAULT_OPTIONS.endpoints,\n options.endpoints || {},\n );\n const oauthModuleOptions = {\n provide: 'OAUTH_MODULE_OPTIONS',\n useValue: resolvedOptions,\n };\n\n // Determine imports based on configuration\n const imports = [\n ConfigModule,\n PassportModule.register({\n defaultStrategy: 'jwt',\n session: false,\n }),\n JwtModule.register({\n secret: resolvedOptions.jwtSecret,\n signOptions: {\n issuer: resolvedOptions.jwtIssuer,\n audience: resolvedOptions.jwtAudience,\n },\n }),\n ];\n\n // Add TypeORM configuration if using TypeORM store\n const storeConfig = resolvedOptions.storeConfiguration;\n const isTypeOrmStore = storeConfig?.type === 'typeorm';\n if (storeConfig && storeConfig.type === 'typeorm') {\n const typeormOptions = storeConfig.options;\n imports.push(\n TypeOrmModule.forRoot({\n ...typeormOptions,\n entities: [\n ...((typeormOptions.entities || []) as any[]),\n OAuthClientEntity,\n AuthorizationCodeEntity,\n OAuthSessionEntity,\n ],\n }),\n TypeOrmModule.forFeature([\n OAuthClientEntity,\n AuthorizationCodeEntity,\n OAuthSessionEntity,\n ]),\n );\n }\n\n // Create store provider based on configuration\n const oauthStoreProvider = this.createStoreProvider(\n resolvedOptions.storeConfiguration,\n );\n\n // Create alias for compatibility with injection\n const oauthStoreAliasProvider = {\n provide: MemoryStore,\n useExisting: 'IOAuthStore',\n };\n\n const providers: any[] = [\n oauthModuleOptions,\n oauthStoreProvider,\n oauthStoreAliasProvider,\n OAuthStrategyService,\n ClientService,\n JwtTokenService,\n McpAuthJwtGuard,\n ];\n\n // Add TypeOrmStore to providers if using TypeORM\n if (isTypeOrmStore) {\n providers.push(TypeOrmStore);\n }\n\n // Create controller with apiPrefix\n const OAuthControllerClass = createMcpOAuthController(\n resolvedOptions.endpoints,\n );\n\n return {\n module: McpAuthModule,\n imports,\n controllers: [OAuthControllerClass],\n providers,\n exports: [\n JwtTokenService,\n 'IOAuthStore',\n MemoryStore,\n McpAuthJwtGuard,\n OAuthStrategyService,\n ],\n };\n }\n\n private static mergeAndValidateOptions(\n defaults: OAuthModuleDefaults,\n options: AuthUserModuleOptions,\n ): OAuthModuleOptions {\n // Validate required options first\n this.validateRequiredOptions(options);\n\n // Merge with defaults\n const resolvedOptions: OAuthModuleOptions = {\n ...defaults,\n ...options,\n // Ensure jwtIssuer defaults to serverUrl if not provided\n jwtIssuer:\n options.jwtIssuer || options.serverUrl || DEFAULT_OPTIONS.jwtIssuer,\n cookieSecure:\n options.cookieSecure || process.env.NODE_ENV === 'production',\n };\n\n // Final validation of resolved options\n this.validateResolvedOptions(resolvedOptions);\n\n return resolvedOptions;\n }\n\n private static validateRequiredOptions(options: AuthUserModuleOptions): void {\n const requiredFields: (keyof AuthUserModuleOptions)[] = [\n 'provider',\n 'clientId',\n 'clientSecret',\n 'jwtSecret',\n ];\n\n for (const field of requiredFields) {\n if (!options[field]) {\n throw new Error(\n `OAuthModuleOptions: ${String(field)} is required and must be provided by the user`,\n );\n }\n }\n }\n\n private static validateResolvedOptions(options: OAuthModuleOptions): void {\n // Validate JWT secret is strong enough\n if (options.jwtSecret.length < 32) {\n throw new Error(\n 'OAuthModuleOptions: jwtSecret must be at least 32 characters long',\n );\n }\n\n // Validate URLs are proper format\n try {\n new URL(options.serverUrl);\n new URL(options.jwtIssuer);\n } catch (error) {\n throw new Error(\n 'OAuthModuleOptions: serverUrl and jwtIssuer must be valid URLs',\n );\n }\n\n // Validate provider configuration\n if (!options.provider.name || !options.provider.strategy) {\n throw new Error(\n 'OAuthModuleOptions: provider must have name and strategy',\n );\n }\n }\n\n private static createStoreProvider(\n storeConfiguration: OAuthModuleOptions['storeConfiguration'],\n ) {\n if (!storeConfiguration || storeConfiguration.type === 'memory') {\n // Default memory store\n return {\n provide: 'IOAuthStore',\n useValue: new MemoryStore(),\n };\n }\n\n if (storeConfiguration.type === 'typeorm') {\n // TypeORM store\n return {\n provide: 'IOAuthStore',\n useClass: TypeOrmStore,\n };\n }\n\n if (storeConfiguration.type === 'custom') {\n // Custom store\n return {\n provide: 'IOAuthStore',\n useValue: storeConfiguration.store,\n };\n }\n\n throw new Error(\n `Unknown store configuration type: ${(storeConfiguration as any).type}`,\n );\n }\n}\n\nfunction prepareEndpoints(\n apiPrefix: string,\n defaultEndpoints: OAuthEndpointConfiguration,\n configuredEndpoints: OAuthEndpointConfiguration,\n) {\n const updatedDefaultEndpoints = {\n wellKnown: defaultEndpoints.wellKnown,\n callback: normalizeEndpoint(`/${apiPrefix}/${defaultEndpoints.callback}`),\n token: normalizeEndpoint(`/${apiPrefix}/${defaultEndpoints.token}`),\n validate: normalizeEndpoint(`/${apiPrefix}/${defaultEndpoints.validate}`),\n revoke: normalizeEndpoint(`/${apiPrefix}/${defaultEndpoints.revoke}`),\n authorize: normalizeEndpoint(`/${apiPrefix}/${defaultEndpoints.authorize}`),\n register: normalizeEndpoint(`/${apiPrefix}/${defaultEndpoints.register}`),\n } as OAuthEndpointConfiguration;\n\n return {\n ...updatedDefaultEndpoints,\n ...configuredEndpoints,\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"mcp-oauth.module.js","sourceRoot":"","sources":["../../src/authz/mcp-oauth.module.ts"],"names":[],"mappings":"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","sourcesContent":["import { DynamicModule, Global, Module } from '@nestjs/common';\nimport { ConfigModule } from '@nestjs/config';\nimport { JwtModule } from '@nestjs/jwt';\nimport { PassportModule } from '@nestjs/passport';\nimport { TypeOrmModule } from '@nestjs/typeorm';\nimport { McpAuthJwtGuard } from './guards/jwt-auth.guard';\nimport { createMcpOAuthController } from './mcp-oauth.controller';\nimport {\n OAuthUserModuleOptions as AuthUserModuleOptions,\n OAuthEndpointConfiguration,\n OAuthModuleDefaults,\n OAuthModuleOptions,\n} from './providers/oauth-provider.interface';\nimport { ClientService } from './services/client.service';\nimport { JwtTokenService } from './services/jwt-token.service';\nimport { OAuthStrategyService } from './services/oauth-strategy.service';\nimport { MemoryStore } from './stores/memory-store.service';\nimport {\n AuthorizationCodeEntity,\n OAuthClientEntity,\n OAuthSessionEntity,\n} from './stores/typeorm/entities';\nimport { TypeOrmStore } from './stores/typeorm/typeorm-store.service';\nimport { normalizeEndpoint } from '../mcp/utils/normalize-endpoint';\n\n// Default configuration values\nexport const DEFAULT_OPTIONS: OAuthModuleDefaults = {\n serverUrl: 'https://localhost:3000',\n resource: 'https://localhost:3000/mcp',\n jwtIssuer: 'https://localhost:3000',\n jwtAudience: 'mcp-client',\n jwtAccessTokenExpiresIn: '60s',\n jwtRefreshTokenExpiresIn: '30d',\n cookieMaxAge: 24 * 60 * 60 * 1000, // 24 hours\n oauthSessionExpiresIn: 10 * 60 * 1000, // 10 minutes\n authCodeExpiresIn: 10 * 60 * 1000, // 10 minutes\n nodeEnv: 'development',\n apiPrefix: '',\n endpoints: {\n wellKnown: '/.well-known/oauth-authorization-server',\n register: '/register',\n authorize: '/authorize',\n callback: '/callback',\n token: '/token',\n validate: '/validate',\n revoke: '/revoke',\n },\n};\n\n@Global()\n@Module({})\nexport class McpAuthModule {\n static forRoot(options: AuthUserModuleOptions): DynamicModule {\n // Merge user options with defaults and validate\n const resolvedOptions = this.mergeAndValidateOptions(\n DEFAULT_OPTIONS,\n options,\n );\n\n resolvedOptions.endpoints = prepareEndpoints(\n resolvedOptions.apiPrefix,\n DEFAULT_OPTIONS.endpoints,\n options.endpoints || {},\n );\n const oauthModuleOptions = {\n provide: 'OAUTH_MODULE_OPTIONS',\n useValue: resolvedOptions,\n };\n\n // Determine imports based on configuration\n const imports = [\n ConfigModule,\n PassportModule.register({\n defaultStrategy: 'jwt',\n session: false,\n }),\n JwtModule.register({\n secret: resolvedOptions.jwtSecret,\n signOptions: {\n issuer: resolvedOptions.jwtIssuer,\n audience: resolvedOptions.jwtAudience,\n },\n }),\n ];\n\n // Add TypeORM configuration if using TypeORM store\n const storeConfig = resolvedOptions.storeConfiguration;\n const isTypeOrmStore = storeConfig?.type === 'typeorm';\n if (storeConfig && storeConfig.type === 'typeorm') {\n const typeormOptions = storeConfig.options;\n imports.push(\n TypeOrmModule.forRoot({\n ...typeormOptions,\n entities: [\n ...((typeormOptions.entities || []) as any[]),\n OAuthClientEntity,\n AuthorizationCodeEntity,\n OAuthSessionEntity,\n ],\n }),\n TypeOrmModule.forFeature([\n OAuthClientEntity,\n AuthorizationCodeEntity,\n OAuthSessionEntity,\n ]),\n );\n }\n\n // Create store provider based on configuration\n const oauthStoreProvider = this.createStoreProvider(\n resolvedOptions.storeConfiguration,\n );\n\n // Create alias for compatibility with injection\n const oauthStoreAliasProvider = {\n provide: MemoryStore,\n useExisting: 'IOAuthStore',\n };\n\n const providers: any[] = [\n oauthModuleOptions,\n oauthStoreProvider,\n oauthStoreAliasProvider,\n OAuthStrategyService,\n ClientService,\n JwtTokenService,\n McpAuthJwtGuard,\n ];\n\n // Add TypeOrmStore to providers if using TypeORM\n if (isTypeOrmStore) {\n providers.push(TypeOrmStore);\n }\n\n // Create controller with apiPrefix\n const OAuthControllerClass = createMcpOAuthController(\n resolvedOptions.endpoints,\n );\n\n return {\n module: McpAuthModule,\n imports,\n controllers: [OAuthControllerClass],\n providers,\n exports: [\n JwtTokenService,\n 'IOAuthStore',\n MemoryStore,\n McpAuthJwtGuard,\n OAuthStrategyService,\n ],\n };\n }\n\n private static mergeAndValidateOptions(\n defaults: OAuthModuleDefaults,\n options: AuthUserModuleOptions,\n ): OAuthModuleOptions {\n // Validate required options first\n this.validateRequiredOptions(options);\n\n // Merge with defaults\n const resolvedOptions: OAuthModuleOptions = {\n ...defaults,\n ...options,\n // Ensure jwtIssuer defaults to serverUrl if not provided\n jwtIssuer:\n options.jwtIssuer || options.serverUrl || DEFAULT_OPTIONS.jwtIssuer,\n cookieSecure:\n options.cookieSecure || process.env.NODE_ENV === 'production',\n };\n\n // Final validation of resolved options\n this.validateResolvedOptions(resolvedOptions);\n\n return resolvedOptions;\n }\n\n private static validateRequiredOptions(options: AuthUserModuleOptions): void {\n const requiredFields: (keyof AuthUserModuleOptions)[] = [\n 'provider',\n 'clientId',\n 'clientSecret',\n 'jwtSecret',\n ];\n\n for (const field of requiredFields) {\n if (!options[field]) {\n throw new Error(\n `OAuthModuleOptions: ${String(field)} is required and must be provided by the user`,\n );\n }\n }\n }\n\n private static validateResolvedOptions(options: OAuthModuleOptions): void {\n // Validate JWT secret is strong enough\n if (options.jwtSecret.length < 32) {\n throw new Error(\n 'OAuthModuleOptions: jwtSecret must be at least 32 characters long',\n );\n }\n\n // Validate URLs are proper format\n try {\n new URL(options.serverUrl);\n new URL(options.jwtIssuer);\n } catch (error) {\n throw new Error(\n 'OAuthModuleOptions: serverUrl and jwtIssuer must be valid URLs',\n );\n }\n\n // Validate provider configuration\n if (!options.provider.name || !options.provider.strategy) {\n throw new Error(\n 'OAuthModuleOptions: provider must have name and strategy',\n );\n }\n }\n\n private static createStoreProvider(\n storeConfiguration: OAuthModuleOptions['storeConfiguration'],\n ) {\n if (!storeConfiguration || storeConfiguration.type === 'memory') {\n // Default memory store\n return {\n provide: 'IOAuthStore',\n useValue: new MemoryStore(),\n };\n }\n\n if (storeConfiguration.type === 'typeorm') {\n // TypeORM store\n return {\n provide: 'IOAuthStore',\n useClass: TypeOrmStore,\n };\n }\n\n if (storeConfiguration.type === 'custom') {\n // Custom store\n return {\n provide: 'IOAuthStore',\n useValue: storeConfiguration.store,\n };\n }\n\n throw new Error(\n `Unknown store configuration type: ${(storeConfiguration as any).type}`,\n );\n }\n}\n\nfunction prepareEndpoints(\n apiPrefix: string,\n defaultEndpoints: OAuthEndpointConfiguration,\n configuredEndpoints: OAuthEndpointConfiguration,\n) {\n const updatedDefaultEndpoints = {\n wellKnown: defaultEndpoints.wellKnown,\n callback: normalizeEndpoint(`/${apiPrefix}/${defaultEndpoints.callback}`),\n token: normalizeEndpoint(`/${apiPrefix}/${defaultEndpoints.token}`),\n validate: normalizeEndpoint(`/${apiPrefix}/${defaultEndpoints.validate}`),\n revoke: normalizeEndpoint(`/${apiPrefix}/${defaultEndpoints.revoke}`),\n authorize: normalizeEndpoint(`/${apiPrefix}/${defaultEndpoints.authorize}`),\n register: normalizeEndpoint(`/${apiPrefix}/${defaultEndpoints.register}`),\n } as OAuthEndpointConfiguration;\n\n return {\n ...updatedDefaultEndpoints,\n ...configuredEndpoints,\n };\n}\n"]}
|
|
@@ -45,6 +45,7 @@ export interface OAuthUserModuleOptions {
|
|
|
45
45
|
clientSecret: string;
|
|
46
46
|
jwtSecret: string;
|
|
47
47
|
serverUrl?: string;
|
|
48
|
+
resource?: string;
|
|
48
49
|
jwtIssuer?: string;
|
|
49
50
|
jwtAudience?: string;
|
|
50
51
|
jwtAccessTokenExpiresIn?: string;
|
|
@@ -59,6 +60,7 @@ export interface OAuthUserModuleOptions {
|
|
|
59
60
|
}
|
|
60
61
|
export interface OAuthModuleDefaults {
|
|
61
62
|
serverUrl: string;
|
|
63
|
+
resource: string;
|
|
62
64
|
jwtIssuer: string;
|
|
63
65
|
jwtAudience: string;
|
|
64
66
|
jwtAccessTokenExpiresIn: string;
|
|
@@ -82,6 +84,7 @@ export interface OAuthSession {
|
|
|
82
84
|
codeChallenge?: string;
|
|
83
85
|
codeChallengeMethod?: string;
|
|
84
86
|
oauthState?: string;
|
|
87
|
+
scope?: string;
|
|
85
88
|
resource?: string;
|
|
86
89
|
expiresAt: number;
|
|
87
90
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"oauth-provider.interface.d.ts","sourceRoot":"","sources":["../../../src/authz/providers/oauth-provider.interface.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAE9D,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,GAAG,CAAC;IACd,eAAe,EAAE,CAAC,OAAO,EAAE;QACzB,SAAS,EAAE,MAAM,CAAC;QAClB,QAAQ,EAAE,MAAM,CAAC;QACjB,YAAY,EAAE,MAAM,CAAC;QACrB,YAAY,CAAC,EAAE,MAAM,CAAC;KACvB,KAAK,GAAG,CAAC;IACV,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,aAAa,EAAE,CAAC,OAAO,EAAE,GAAG,KAAK,gBAAgB,CAAC;CACnD;AAED,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,GAAG,CAAC,EAAE,GAAG,CAAC;CACX;AAGD,MAAM,MAAM,kBAAkB,GAC1B;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,oBAAoB,CAAA;CAAE,GAClD;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,KAAK,EAAE,WAAW,CAAA;CAAE,GACtC;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,GAClB,SAAS,CAAC;AAEd,MAAM,WAAW,0BAA0B;IACzC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,mBAAmB,CAAC;IAG9B,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IAGrB,SAAS,EAAE,MAAM,CAAC;IAGlB,SAAS,CAAC,EAAE,MAAM,CAAC;
|
|
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 wellKnown?: string; // Default: '/.well-known/oauth-authorization-server'\n register?: string; // Default: '/register'\n authorize?: string; // Default: '/authorize'\n callback?: string; // Default: '/callback'\n token?: string; // Default: '/token'\n validate?: string; // Default: '/validate'\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\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 // 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 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}\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 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 wellKnown?: string; // Default: '/.well-known/oauth-authorization-server'\n register?: string; // Default: '/register'\n authorize?: string; // Default: '/authorize'\n callback?: string; // Default: '/callback'\n token?: string; // Default: '/token'\n validate?: string; // Default: '/validate'\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 // 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}\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"]}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { JwtService as NestJwtService } from '@nestjs/jwt';
|
|
2
1
|
import { OAuthModuleOptions } from '../providers/oauth-provider.interface';
|
|
3
2
|
export interface JwtPayload {
|
|
4
3
|
sub: string;
|
|
5
4
|
client_id?: string;
|
|
6
5
|
scope?: string;
|
|
6
|
+
resource?: string;
|
|
7
7
|
type: 'access' | 'refresh' | 'user';
|
|
8
8
|
user_data?: any;
|
|
9
9
|
iat?: number;
|
|
@@ -14,16 +14,14 @@ export interface TokenPair {
|
|
|
14
14
|
refresh_token: string;
|
|
15
15
|
token_type: string;
|
|
16
16
|
expires_in: number;
|
|
17
|
-
scope
|
|
17
|
+
scope?: string;
|
|
18
18
|
}
|
|
19
19
|
export declare class JwtTokenService {
|
|
20
|
-
private
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
generateTokenPair(userId: string, clientId: string, scope?: string): TokenPair;
|
|
20
|
+
private jwtSecret;
|
|
21
|
+
constructor(options: OAuthModuleOptions);
|
|
22
|
+
generateTokenPair(userId: string, clientId: string, scope?: string, resource?: string): TokenPair;
|
|
24
23
|
validateToken(token: string): JwtPayload | null;
|
|
25
24
|
refreshAccessToken(refreshToken: string): TokenPair | null;
|
|
26
25
|
generateUserToken(userId: string, userData: any): string;
|
|
27
|
-
private parseExpiresIn;
|
|
28
26
|
}
|
|
29
27
|
//# sourceMappingURL=jwt-token.service.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"jwt-token.service.d.ts","sourceRoot":"","sources":["../../../src/authz/services/jwt-token.service.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"jwt-token.service.d.ts","sourceRoot":"","sources":["../../../src/authz/services/jwt-token.service.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,kBAAkB,EAAE,MAAM,uCAAuC,CAAC;AAE3E,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,QAAQ,GAAG,SAAS,GAAG,MAAM,CAAC;IACpC,SAAS,CAAC,EAAE,GAAG,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,SAAS;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,qBACa,eAAe;IAC1B,OAAO,CAAC,SAAS,CAAS;gBAEkB,OAAO,EAAE,kBAAkB;IAWvE,iBAAiB,CACf,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,KAAK,SAAK,EACV,QAAQ,CAAC,EAAE,MAAM,GAChB,SAAS;IA6CZ,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI;IAU/C,kBAAkB,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI;IAe1D,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,GAAG,MAAM;CAkBzD"}
|