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

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.
Files changed (62) hide show
  1. package/dist/authz/guards/jwt-auth.guard.d.ts +4 -2
  2. package/dist/authz/guards/jwt-auth.guard.d.ts.map +1 -1
  3. package/dist/authz/guards/jwt-auth.guard.js +32 -4
  4. package/dist/authz/guards/jwt-auth.guard.js.map +1 -1
  5. package/dist/authz/index.d.ts +1 -0
  6. package/dist/authz/index.d.ts.map +1 -1
  7. package/dist/authz/index.js +1 -0
  8. package/dist/authz/index.js.map +1 -1
  9. package/dist/authz/interfaces/request-with-user.d.ts +13 -0
  10. package/dist/authz/interfaces/request-with-user.d.ts.map +1 -0
  11. package/dist/authz/interfaces/request-with-user.js +3 -0
  12. package/dist/authz/interfaces/request-with-user.js.map +1 -0
  13. package/dist/authz/mcp-oauth.controller.d.ts.map +1 -1
  14. package/dist/authz/mcp-oauth.controller.js +45 -4
  15. package/dist/authz/mcp-oauth.controller.js.map +1 -1
  16. package/dist/authz/mcp-oauth.module.d.ts.map +1 -1
  17. package/dist/authz/mcp-oauth.module.js +2 -0
  18. package/dist/authz/mcp-oauth.module.js.map +1 -1
  19. package/dist/authz/services/client.service.d.ts.map +1 -1
  20. package/dist/authz/services/client.service.js.map +1 -1
  21. package/dist/authz/services/jwt-token.service.d.ts +5 -1
  22. package/dist/authz/services/jwt-token.service.d.ts.map +1 -1
  23. package/dist/authz/services/jwt-token.service.js +14 -2
  24. package/dist/authz/services/jwt-token.service.js.map +1 -1
  25. package/dist/authz/stores/memory-store.service.d.ts +9 -1
  26. package/dist/authz/stores/memory-store.service.d.ts.map +1 -1
  27. package/dist/authz/stores/memory-store.service.js +23 -0
  28. package/dist/authz/stores/memory-store.service.js.map +1 -1
  29. package/dist/authz/stores/oauth-store.interface.d.ts +7 -1
  30. package/dist/authz/stores/oauth-store.interface.d.ts.map +1 -1
  31. package/dist/authz/stores/oauth-store.interface.js.map +1 -1
  32. package/dist/authz/stores/typeorm/entities/authorization-code.entity.d.ts +1 -0
  33. package/dist/authz/stores/typeorm/entities/authorization-code.entity.d.ts.map +1 -1
  34. package/dist/authz/stores/typeorm/entities/authorization-code.entity.js +4 -0
  35. package/dist/authz/stores/typeorm/entities/authorization-code.entity.js.map +1 -1
  36. package/dist/authz/stores/typeorm/entities/index.d.ts +1 -0
  37. package/dist/authz/stores/typeorm/entities/index.d.ts.map +1 -1
  38. package/dist/authz/stores/typeorm/entities/index.js +3 -1
  39. package/dist/authz/stores/typeorm/entities/index.js.map +1 -1
  40. package/dist/authz/stores/typeorm/entities/user-profile.entity.d.ts +13 -0
  41. package/dist/authz/stores/typeorm/entities/user-profile.entity.d.ts.map +1 -0
  42. package/dist/authz/stores/typeorm/entities/user-profile.entity.js +61 -0
  43. package/dist/authz/stores/typeorm/entities/user-profile.entity.js.map +1 -0
  44. package/dist/authz/stores/typeorm/typeorm-store.service.d.ts +10 -3
  45. package/dist/authz/stores/typeorm/typeorm-store.service.d.ts.map +1 -1
  46. package/dist/authz/stores/typeorm/typeorm-store.service.js +51 -1
  47. package/dist/authz/stores/typeorm/typeorm-store.service.js.map +1 -1
  48. package/package.json +1 -1
  49. package/src/authz/guards/jwt-auth.guard.ts +36 -3
  50. package/src/authz/index.ts +1 -0
  51. package/src/authz/interfaces/request-with-user.ts +16 -0
  52. package/src/authz/mcp-oauth.controller.ts +65 -3
  53. package/src/authz/mcp-oauth.module.ts +3 -0
  54. package/src/authz/services/client.service.ts +11 -10
  55. package/src/authz/services/jwt-token.service.ts +16 -1
  56. package/src/authz/stores/memory-store.service.ts +42 -1
  57. package/src/authz/stores/oauth-store.interface.ts +23 -1
  58. package/src/authz/stores/typeorm/README.md +7 -0
  59. package/src/authz/stores/typeorm/entities/authorization-code.entity.ts +3 -0
  60. package/src/authz/stores/typeorm/entities/index.ts +1 -0
  61. package/src/authz/stores/typeorm/entities/user-profile.entity.ts +45 -0
  62. package/src/authz/stores/typeorm/typeorm-store.service.ts +68 -2
@@ -1,13 +1,15 @@
1
1
  import { CanActivate, ExecutionContext } from '@nestjs/common';
2
2
  import { Request } from 'express';
3
3
  import { JwtPayload, JwtTokenService } from '../services/jwt-token.service';
4
+ import { IOAuthStore } from '../stores/oauth-store.interface';
4
5
  export interface AuthenticatedRequest extends Request {
5
6
  user: JwtPayload;
6
7
  }
7
8
  export declare class McpAuthJwtGuard implements CanActivate {
8
9
  private readonly jwtTokenService;
9
- constructor(jwtTokenService: JwtTokenService);
10
- canActivate(context: ExecutionContext): boolean;
10
+ private readonly store;
11
+ constructor(jwtTokenService: JwtTokenService, store: IOAuthStore);
12
+ canActivate(context: ExecutionContext): Promise<boolean>;
11
13
  private extractTokenFromHeader;
12
14
  }
13
15
  //# sourceMappingURL=jwt-auth.guard.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"jwt-auth.guard.d.ts","sourceRoot":"","sources":["../../../src/authz/guards/jwt-auth.guard.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,WAAW,EACX,gBAAgB,EAEjB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAE5E,MAAM,WAAW,oBAAqB,SAAQ,OAAO;IACnD,IAAI,EAAE,UAAU,CAAC;CAClB;AAED,qBACa,eAAgB,YAAW,WAAW;IACrC,OAAO,CAAC,QAAQ,CAAC,eAAe;gBAAf,eAAe,EAAE,eAAe;IAE7D,WAAW,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO;IAkB/C,OAAO,CAAC,sBAAsB;CAS/B"}
1
+ {"version":3,"file":"jwt-auth.guard.d.ts","sourceRoot":"","sources":["../../../src/authz/guards/jwt-auth.guard.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,WAAW,EACX,gBAAgB,EAGjB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAC5E,OAAO,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAE9D,MAAM,WAAW,oBAAqB,SAAQ,OAAO;IACnD,IAAI,EAAE,UAAU,CAAC;CAClB;AAED,qBACa,eAAgB,YAAW,WAAW;IAE/C,OAAO,CAAC,QAAQ,CAAC,eAAe;IACT,OAAO,CAAC,QAAQ,CAAC,KAAK;gBAD5B,eAAe,EAAE,eAAe,EACT,KAAK,EAAE,WAAW;IAGtD,WAAW,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,OAAO,CAAC;IA8C9D,OAAO,CAAC,sBAAsB;CAS/B"}
@@ -8,15 +8,19 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
8
8
  var __metadata = (this && this.__metadata) || function (k, v) {
9
9
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
10
  };
11
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
+ return function (target, key) { decorator(target, key, paramIndex); }
13
+ };
11
14
  Object.defineProperty(exports, "__esModule", { value: true });
12
15
  exports.McpAuthJwtGuard = void 0;
13
16
  const common_1 = require("@nestjs/common");
14
17
  const jwt_token_service_1 = require("../services/jwt-token.service");
15
18
  let McpAuthJwtGuard = class McpAuthJwtGuard {
16
- constructor(jwtTokenService) {
19
+ constructor(jwtTokenService, store) {
17
20
  this.jwtTokenService = jwtTokenService;
21
+ this.store = store;
18
22
  }
19
- canActivate(context) {
23
+ async canActivate(context) {
20
24
  const request = context.switchToHttp().getRequest();
21
25
  const token = this.extractTokenFromHeader(request);
22
26
  if (!token) {
@@ -26,7 +30,30 @@ let McpAuthJwtGuard = class McpAuthJwtGuard {
26
30
  if (!payload) {
27
31
  throw new common_1.UnauthorizedException('Invalid or expired access token');
28
32
  }
29
- request.user = payload;
33
+ const enriched = { ...payload };
34
+ try {
35
+ if (!enriched.user_data && enriched.user_profile_id) {
36
+ const profile = await this.store.getUserProfileById(enriched.user_profile_id);
37
+ if (profile) {
38
+ enriched.user_data = profile;
39
+ }
40
+ }
41
+ const ud = enriched.user_data || {};
42
+ enriched.username =
43
+ enriched.username || ud.username || ud.id || enriched.sub;
44
+ enriched.email = enriched.email || ud.email;
45
+ enriched.displayName = enriched.displayName || ud.displayName;
46
+ enriched.avatarUrl = enriched.avatarUrl || ud.avatarUrl;
47
+ enriched.name =
48
+ enriched.name ||
49
+ ud.displayName ||
50
+ ud.username ||
51
+ ud.email ||
52
+ enriched.sub;
53
+ }
54
+ catch {
55
+ }
56
+ request.user = enriched;
30
57
  return true;
31
58
  }
32
59
  extractTokenFromHeader(request) {
@@ -41,6 +68,7 @@ let McpAuthJwtGuard = class McpAuthJwtGuard {
41
68
  exports.McpAuthJwtGuard = McpAuthJwtGuard;
42
69
  exports.McpAuthJwtGuard = McpAuthJwtGuard = __decorate([
43
70
  (0, common_1.Injectable)(),
44
- __metadata("design:paramtypes", [jwt_token_service_1.JwtTokenService])
71
+ __param(1, (0, common_1.Inject)('IOAuthStore')),
72
+ __metadata("design:paramtypes", [jwt_token_service_1.JwtTokenService, Object])
45
73
  ], McpAuthJwtGuard);
46
74
  //# sourceMappingURL=jwt-auth.guard.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"jwt-auth.guard.js","sourceRoot":"","sources":["../../../src/authz/guards/jwt-auth.guard.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,2CAKwB;AAExB,qEAA4E;AAOrE,IAAM,eAAe,GAArB,MAAM,eAAe;IAC1B,YAA6B,eAAgC;QAAhC,oBAAe,GAAf,eAAe,CAAiB;IAAG,CAAC;IAEjE,WAAW,CAAC,OAAyB;QACnC,MAAM,OAAO,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,UAAU,EAAwB,CAAC;QAC1E,MAAM,KAAK,GAAG,IAAI,CAAC,sBAAsB,CAAC,OAAO,CAAC,CAAC;QAEnD,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,IAAI,8BAAqB,CAAC,uBAAuB,CAAC,CAAC;QAC3D,CAAC;QAED,MAAM,OAAO,GAAG,IAAI,CAAC,eAAe,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;QAE1D,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,8BAAqB,CAAC,iCAAiC,CAAC,CAAC;QACrE,CAAC;QAED,OAAO,CAAC,IAAI,GAAG,OAAO,CAAC;QACvB,OAAO,IAAI,CAAC;IACd,CAAC;IAEO,sBAAsB,CAAC,OAAgB;QAC7C,MAAM,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC;QACjD,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,GAAG,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC5C,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;IAC/C,CAAC;CACF,CAAA;AA9BY,0CAAe;0BAAf,eAAe;IAD3B,IAAA,mBAAU,GAAE;qCAEmC,mCAAe;GADlD,eAAe,CA8B3B","sourcesContent":["import {\n Injectable,\n CanActivate,\n ExecutionContext,\n UnauthorizedException,\n} from '@nestjs/common';\nimport { Request } from 'express';\nimport { JwtPayload, JwtTokenService } from '../services/jwt-token.service';\n\nexport interface AuthenticatedRequest extends Request {\n user: JwtPayload;\n}\n\n@Injectable()\nexport class McpAuthJwtGuard implements CanActivate {\n constructor(private readonly jwtTokenService: JwtTokenService) {}\n\n canActivate(context: ExecutionContext): boolean {\n const request = context.switchToHttp().getRequest<AuthenticatedRequest>();\n const token = this.extractTokenFromHeader(request);\n\n if (!token) {\n throw new UnauthorizedException('Access token required');\n }\n\n const payload = this.jwtTokenService.validateToken(token);\n\n if (!payload) {\n throw new UnauthorizedException('Invalid or expired access token');\n }\n\n request.user = payload;\n return true;\n }\n\n private extractTokenFromHeader(request: Request): string | undefined {\n const authHeader = request.headers.authorization;\n if (!authHeader) {\n return undefined;\n }\n\n const [type, token] = authHeader.split(' ');\n return type === 'Bearer' ? token : undefined;\n }\n}\n"]}
1
+ {"version":3,"file":"jwt-auth.guard.js","sourceRoot":"","sources":["../../../src/authz/guards/jwt-auth.guard.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAAA,2CAMwB;AAExB,qEAA4E;AAQrE,IAAM,eAAe,GAArB,MAAM,eAAe;IAC1B,YACmB,eAAgC,EACT,KAAkB;QADzC,oBAAe,GAAf,eAAe,CAAiB;QACT,UAAK,GAAL,KAAK,CAAa;IACzD,CAAC;IAEJ,KAAK,CAAC,WAAW,CAAC,OAAyB;QACzC,MAAM,OAAO,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC,UAAU,EAAwB,CAAC;QAC1E,MAAM,KAAK,GAAG,IAAI,CAAC,sBAAsB,CAAC,OAAO,CAAC,CAAC;QAEnD,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,IAAI,8BAAqB,CAAC,uBAAuB,CAAC,CAAC;QAC3D,CAAC;QAED,MAAM,OAAO,GAAG,IAAI,CAAC,eAAe,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;QAE1D,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,8BAAqB,CAAC,iCAAiC,CAAC,CAAC;QACrE,CAAC;QAGD,MAAM,QAAQ,GAAQ,EAAE,GAAG,OAAO,EAAE,CAAC;QACrC,IAAI,CAAC;YACH,IAAI,CAAC,QAAQ,CAAC,SAAS,IAAI,QAAQ,CAAC,eAAe,EAAE,CAAC;gBACpD,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,kBAAkB,CACjD,QAAQ,CAAC,eAAe,CACzB,CAAC;gBACF,IAAI,OAAO,EAAE,CAAC;oBACZ,QAAQ,CAAC,SAAS,GAAG,OAAO,CAAC;gBAC/B,CAAC;YACH,CAAC;YACD,MAAM,EAAE,GAAG,QAAQ,CAAC,SAAS,IAAI,EAAE,CAAC;YAEpC,QAAQ,CAAC,QAAQ;gBACf,QAAQ,CAAC,QAAQ,IAAI,EAAE,CAAC,QAAQ,IAAI,EAAE,CAAC,EAAE,IAAI,QAAQ,CAAC,GAAG,CAAC;YAC5D,QAAQ,CAAC,KAAK,GAAG,QAAQ,CAAC,KAAK,IAAI,EAAE,CAAC,KAAK,CAAC;YAC5C,QAAQ,CAAC,WAAW,GAAG,QAAQ,CAAC,WAAW,IAAI,EAAE,CAAC,WAAW,CAAC;YAC9D,QAAQ,CAAC,SAAS,GAAG,QAAQ,CAAC,SAAS,IAAI,EAAE,CAAC,SAAS,CAAC;YACxD,QAAQ,CAAC,IAAI;gBACX,QAAQ,CAAC,IAAI;oBACb,EAAE,CAAC,WAAW;oBACd,EAAE,CAAC,QAAQ;oBACX,EAAE,CAAC,KAAK;oBACR,QAAQ,CAAC,GAAG,CAAC;QACjB,CAAC;QAAC,MAAM,CAAC;QAET,CAAC;QAED,OAAO,CAAC,IAAI,GAAG,QAAsB,CAAC;QACtC,OAAO,IAAI,CAAC;IACd,CAAC;IAEO,sBAAsB,CAAC,OAAgB;QAC7C,MAAM,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC;QACjD,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,GAAG,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC5C,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;IAC/C,CAAC;CACF,CAAA;AA7DY,0CAAe;0BAAf,eAAe;IAD3B,IAAA,mBAAU,GAAE;IAIR,WAAA,IAAA,eAAM,EAAC,aAAa,CAAC,CAAA;qCADY,mCAAe;GAFxC,eAAe,CA6D3B","sourcesContent":["import {\n Injectable,\n CanActivate,\n ExecutionContext,\n UnauthorizedException,\n Inject,\n} from '@nestjs/common';\nimport { Request } from 'express';\nimport { JwtPayload, JwtTokenService } from '../services/jwt-token.service';\nimport { IOAuthStore } from '../stores/oauth-store.interface';\n\nexport interface AuthenticatedRequest extends Request {\n user: JwtPayload;\n}\n\n@Injectable()\nexport class McpAuthJwtGuard implements CanActivate {\n constructor(\n private readonly jwtTokenService: JwtTokenService,\n @Inject('IOAuthStore') private readonly store: IOAuthStore,\n ) {}\n\n async canActivate(context: ExecutionContext): Promise<boolean> {\n const request = context.switchToHttp().getRequest<AuthenticatedRequest>();\n const token = this.extractTokenFromHeader(request);\n\n if (!token) {\n throw new UnauthorizedException('Access token required');\n }\n\n const payload = this.jwtTokenService.validateToken(token);\n\n if (!payload) {\n throw new UnauthorizedException('Invalid or expired access token');\n }\n\n // Enrich request.user with friendly fields for tools\n const enriched: any = { ...payload };\n try {\n if (!enriched.user_data && enriched.user_profile_id) {\n const profile = await this.store.getUserProfileById(\n enriched.user_profile_id,\n );\n if (profile) {\n enriched.user_data = profile;\n }\n }\n const ud = enriched.user_data || {};\n // Provide convenient top-level fields commonly used by tools\n enriched.username =\n enriched.username || ud.username || ud.id || enriched.sub;\n enriched.email = enriched.email || ud.email;\n enriched.displayName = enriched.displayName || ud.displayName;\n enriched.avatarUrl = enriched.avatarUrl || ud.avatarUrl;\n enriched.name =\n enriched.name ||\n ud.displayName ||\n ud.username ||\n ud.email ||\n enriched.sub;\n } catch {\n // Non-fatal; proceed with raw payload\n }\n\n request.user = enriched as JwtPayload;\n return true;\n }\n\n private extractTokenFromHeader(request: Request): string | undefined {\n const authHeader = request.headers.authorization;\n if (!authHeader) {\n return undefined;\n }\n\n const [type, token] = authHeader.split(' ');\n return type === 'Bearer' ? token : undefined;\n }\n}\n"]}
@@ -6,4 +6,5 @@ export * from './providers/github.provider';
6
6
  export * from './stores/oauth-store.interface';
7
7
  export * from './stores/memory-store.service';
8
8
  export * from './stores/typeorm/typeorm-store.service';
9
+ export * from './interfaces/request-with-user';
9
10
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/authz/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC;AACvC,cAAc,oBAAoB,CAAC;AACnC,cAAc,sCAAsC,CAAC;AACrD,cAAc,6BAA6B,CAAC;AAC5C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,wCAAwC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/authz/index.ts"],"names":[],"mappings":"AAAA,cAAc,wBAAwB,CAAC;AACvC,cAAc,oBAAoB,CAAC;AACnC,cAAc,sCAAsC,CAAC;AACrD,cAAc,6BAA6B,CAAC;AAC5C,cAAc,6BAA6B,CAAC;AAC5C,cAAc,gCAAgC,CAAC;AAC/C,cAAc,+BAA+B,CAAC;AAC9C,cAAc,wCAAwC,CAAC;AACvD,cAAc,gCAAgC,CAAC"}
@@ -22,4 +22,5 @@ __exportStar(require("./providers/github.provider"), exports);
22
22
  __exportStar(require("./stores/oauth-store.interface"), exports);
23
23
  __exportStar(require("./stores/memory-store.service"), exports);
24
24
  __exportStar(require("./stores/typeorm/typeorm-store.service"), exports);
25
+ __exportStar(require("./interfaces/request-with-user"), exports);
25
26
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/authz/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,yDAAuC;AACvC,qDAAmC;AACnC,uEAAqD;AACrD,8DAA4C;AAC5C,8DAA4C;AAC5C,iEAA+C;AAC/C,gEAA8C;AAC9C,yEAAuD","sourcesContent":["export * from './mcp-oauth.controller';\nexport * from './mcp-oauth.module';\nexport * from './providers/oauth-provider.interface';\nexport * from './providers/google.provider';\nexport * from './providers/github.provider';\nexport * from './stores/oauth-store.interface';\nexport * from './stores/memory-store.service';\nexport * from './stores/typeorm/typeorm-store.service';\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/authz/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,yDAAuC;AACvC,qDAAmC;AACnC,uEAAqD;AACrD,8DAA4C;AAC5C,8DAA4C;AAC5C,iEAA+C;AAC/C,gEAA8C;AAC9C,yEAAuD;AACvD,iEAA+C","sourcesContent":["export * from './mcp-oauth.controller';\nexport * from './mcp-oauth.module';\nexport * from './providers/oauth-provider.interface';\nexport * from './providers/google.provider';\nexport * from './providers/github.provider';\nexport * from './stores/oauth-store.interface';\nexport * from './stores/memory-store.service';\nexport * from './stores/typeorm/typeorm-store.service';\nexport * from './interfaces/request-with-user';\n"]}
@@ -0,0 +1,13 @@
1
+ import type { Request } from 'express';
2
+ import type { JwtPayload } from '../services/jwt-token.service';
3
+ export type McpUserPayload = JwtPayload & {
4
+ name?: string;
5
+ username?: string;
6
+ email?: string;
7
+ displayName?: string;
8
+ avatarUrl?: string;
9
+ };
10
+ export interface McpRequestWithUser extends Request {
11
+ user: McpUserPayload;
12
+ }
13
+ //# sourceMappingURL=request-with-user.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request-with-user.d.ts","sourceRoot":"","sources":["../../../src/authz/interfaces/request-with-user.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,+BAA+B,CAAC;AAGhE,MAAM,MAAM,cAAc,GAAG,UAAU,GAAG;IACxC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAGF,MAAM,WAAW,kBAAmB,SAAQ,OAAO;IACjD,IAAI,EAAE,cAAc,CAAC;CACtB"}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=request-with-user.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request-with-user.js","sourceRoot":"","sources":["../../../src/authz/interfaces/request-with-user.ts"],"names":[],"mappings":"","sourcesContent":["import type { Request } from 'express';\nimport type { JwtPayload } from '../services/jwt-token.service';\n\n// Enriched user payload placed on request.user by McpAuthJwtGuard\nexport type McpUserPayload = JwtPayload & {\n name?: string;\n username?: string;\n email?: string;\n displayName?: string;\n avatarUrl?: string;\n};\n\n// Express Request with enriched user information\nexport interface McpRequestWithUser extends Request {\n user: McpUserPayload;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"mcp-oauth.controller.d.ts","sourceRoot":"","sources":["../../src/authz/mcp-oauth.controller.ts"],"names":[],"mappings":"AAAA,OAAO,EAQL,MAAM,EAMP,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAG5E,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,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAC;AAE7D,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;;;;;;;;;;;;;;;;;;;;;wCA0FO,GAAG;yBAM/B,GAAG,OAEd,GAAG,OACI,QAAQ,QACN,YAAY;oCA2Ed,oBAAoB,OACpB,QAAQ,QACN,YAAY;0CA2BrB,oBAAoB,OACpB,QAAQ;4BA4EC,GAAG,OACL,GAAG,GACd,OAAO,CAAC,SAAS,CAAC;sCAsCd,GAAG,QACF,GAAG,GACR;YAAE,SAAS,EAAE,MAAM,CAAC;YAAC,aAAa,CAAC,EAAE,MAAM,CAAA;SAAE;6CA4BtC,GAAG,qBACQ;YAAE,SAAS,EAAE,MAAM,CAAC;YAAC,aAAa,CAAC,EAAE,MAAM,CAAA;SAAE,GAC/D,IAAI;2CAqCC,MAAM,iBACG,MAAM,iBACN,MAAM,qBACF;YAAE,SAAS,EAAE,MAAM,CAAC;YAAC,aAAa,CAAC,EAAE,MAAM,CAAA;SAAE,GAC/D,OAAO,CAAC,SAAS,CAAC;+CAyEJ,MAAM,qBACF;YAAE,SAAS,EAAE,MAAM,CAAC;YAAC,aAAa,CAAC,EAAE,MAAM,CAAA;SAAE,GAC/D,OAAO,CAAC,SAAS,CAAC;oCAyCJ,MAAM,kBACL,MAAM,UACd,MAAM,GACb,OAAO;;EAcb"}
1
+ {"version":3,"file":"mcp-oauth.controller.d.ts","sourceRoot":"","sources":["../../src/authz/mcp-oauth.controller.ts"],"names":[],"mappings":"AAAA,OAAO,EAQL,MAAM,EAMP,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAG5E,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,EAAE,WAAW,EAAE,MAAM,gCAAgC,CAAC;AAE7D,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;;;;;;;;;;;;;;;;;;;;;wCA0FO,GAAG;yBAM/B,GAAG,OAEd,GAAG,OACI,QAAQ,QACN,YAAY;oCA2Ed,oBAAoB,OACpB,QAAQ,QACN,YAAY;0CA2BrB,oBAAoB,OACpB,QAAQ;4BAmFC,GAAG,OACL,GAAG,GACd,OAAO,CAAC,SAAS,CAAC;sCAsCd,GAAG,QACF,GAAG,GACR;YAAE,SAAS,EAAE,MAAM,CAAC;YAAC,aAAa,CAAC,EAAE,MAAM,CAAA;SAAE;6CA4BtC,GAAG,qBACQ;YAAE,SAAS,EAAE,MAAM,CAAC;YAAC,aAAa,CAAC,EAAE,MAAM,CAAA;SAAE,GAC/D,IAAI;2CAqCC,MAAM,iBACG,MAAM,iBACN,MAAM,qBACF;YAAE,SAAS,EAAE,MAAM,CAAC;YAAC,aAAa,CAAC,EAAE,MAAM,CAAA;SAAE,GAC/D,OAAO,CAAC,SAAS,CAAC;+CA4FJ,MAAM,qBACF;YAAE,SAAS,EAAE,MAAM,CAAC;YAAC,aAAa,CAAC,EAAE,MAAM,CAAA;SAAE,GAC/D,OAAO,CAAC,SAAS,CAAC;oCA6EJ,MAAM,kBACL,MAAM,UACd,MAAM,GACb,OAAO;;EAcb"}
@@ -156,6 +156,7 @@ function createMcpOAuthController(endpoints = {}) {
156
156
  });
157
157
  res.clearCookie('oauth_session');
158
158
  res.clearCookie('oauth_state');
159
+ const user_profile_id = await this.store.upsertUserProfile(user.profile, user.provider);
159
160
  const authCode = (0, crypto_1.randomBytes)(32).toString('base64url');
160
161
  await this.store.storeAuthCode({
161
162
  code: authCode,
@@ -168,6 +169,7 @@ function createMcpOAuthController(endpoints = {}) {
168
169
  resource: session.resource,
169
170
  scope: session.scope,
170
171
  github_access_token: '',
172
+ user_profile_id,
171
173
  });
172
174
  const redirectUrl = new URL(session.redirectUri);
173
175
  redirectUrl.searchParams.set('code', authCode);
@@ -271,7 +273,22 @@ function createMcpOAuthController(endpoints = {}) {
271
273
  this.logger.error('handleAuthorizationCodeGrant - No resource associated with code');
272
274
  throw new common_1.BadRequestException('Authorization code is not associated with a resource');
273
275
  }
274
- const tokens = this.jwtTokenService.generateTokenPair(authCode.user_id, clientCredentials.client_id, authCode.scope, authCode.resource);
276
+ let userData = undefined;
277
+ if (authCode.user_profile_id) {
278
+ try {
279
+ const profile = await this.store.getUserProfileById(authCode.user_profile_id);
280
+ if (profile) {
281
+ userData = { ...profile };
282
+ }
283
+ }
284
+ catch (e) {
285
+ this.logger.warn('Failed to load user profile for token payload', e);
286
+ }
287
+ }
288
+ const tokens = this.jwtTokenService.generateTokenPair(authCode.user_id, clientCredentials.client_id, authCode.scope, authCode.resource, {
289
+ user_profile_id: authCode.user_profile_id,
290
+ user_data: userData,
291
+ });
275
292
  await this.store.removeAuthCode(code);
276
293
  this.logger.log('handleAuthorizationCodeGrant - Token pair generated for user:', authCode.user_id);
277
294
  return tokens;
@@ -295,10 +312,34 @@ function createMcpOAuthController(endpoints = {}) {
295
312
  if (payload.client_id !== clientId) {
296
313
  throw new common_1.BadRequestException('Invalid refresh token or token does not belong to this client');
297
314
  }
298
- const newTokens = this.jwtTokenService.refreshAccessToken(refresh_token);
299
- if (!newTokens) {
300
- throw new common_1.BadRequestException('Failed to refresh token');
315
+ let newTokens = null;
316
+ try {
317
+ const payload = this.jwtTokenService.validateToken(refresh_token);
318
+ if (!payload || payload.type !== 'refresh') {
319
+ throw new common_1.BadRequestException('Invalid or expired refresh token');
320
+ }
321
+ let userData = undefined;
322
+ if (payload.user_profile_id) {
323
+ try {
324
+ const profile = await this.store.getUserProfileById(payload.user_profile_id);
325
+ if (profile)
326
+ userData = { ...profile };
327
+ }
328
+ catch (e) {
329
+ this.logger.warn('Failed to load user profile for refreshed token payload', e);
330
+ }
331
+ }
332
+ newTokens = this.jwtTokenService.generateTokenPair(payload.sub, clientId, payload.scope, payload.resource, {
333
+ user_profile_id: payload.user_profile_id,
334
+ user_data: userData,
335
+ });
336
+ }
337
+ catch (e) {
338
+ this.logger.warn('Refresh flow failed using enriched path, fallback', e);
339
+ newTokens = this.jwtTokenService.refreshAccessToken(refresh_token);
301
340
  }
341
+ if (!newTokens)
342
+ throw new common_1.BadRequestException('Failed to refresh token');
302
343
  return newTokens;
303
344
  }
304
345
  validatePKCE(code_verifier, code_challenge, method) {
@@ -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(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"]}
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 // Persist user profile and get stable profile_id\n const user_profile_id = await this.store.upsertUserProfile(\n user.profile,\n user.provider,\n );\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 user_profile_id,\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 let userData: any | undefined = undefined;\n if (authCode.user_profile_id) {\n try {\n const profile = await this.store.getUserProfileById(\n authCode.user_profile_id,\n );\n if (profile) {\n // Avoid circular/large raw payloads if present\n userData = { ...profile };\n }\n } catch (e) {\n this.logger.warn('Failed to load user profile for token payload', e);\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 user_profile_id: authCode.user_profile_id,\n user_data: userData,\n },\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 let newTokens: TokenPair | null = null;\n try {\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 let userData: any | undefined = undefined;\n if (payload.user_profile_id) {\n try {\n const profile = await this.store.getUserProfileById(\n payload.user_profile_id,\n );\n if (profile) userData = { ...profile };\n } catch (e) {\n this.logger.warn(\n 'Failed to load user profile for refreshed token payload',\n e,\n );\n }\n }\n\n newTokens = this.jwtTokenService.generateTokenPair(\n payload.sub,\n clientId,\n payload.scope,\n payload.resource,\n {\n user_profile_id: payload.user_profile_id,\n user_data: userData,\n },\n );\n } catch (e) {\n this.logger.warn(\n 'Refresh flow failed using enriched path, fallback',\n e,\n );\n newTokens = this.jwtTokenService.refreshAccessToken(refresh_token);\n }\n\n if (!newTokens) throw new BadRequestException('Failed to refresh token');\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 +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,mBAuC7B,CAAC;AAEF,qBAEa,aAAa;IACxB,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,qBAAqB,GAAG,aAAa;IAsG7D,OAAO,CAAC,MAAM,CAAC,uBAAuB;IAkCtC,OAAO,CAAC,MAAM,CAAC,uBAAuB;IAiBtC,OAAO,CAAC,MAAM,CAAC,uBAAuB;IA0BtC,OAAO,CAAC,MAAM,CAAC,mBAAmB;CA+BnC"}
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;AAe9C,eAAO,MAAM,eAAe,EAAE,mBAuC7B,CAAC;AAEF,qBAEa,aAAa;IACxB,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,qBAAqB,GAAG,aAAa;IAwG7D,OAAO,CAAC,MAAM,CAAC,uBAAuB;IAkCtC,OAAO,CAAC,MAAM,CAAC,uBAAuB;IAiBtC,OAAO,CAAC,MAAM,CAAC,uBAAuB;IA0BtC,OAAO,CAAC,MAAM,CAAC,mBAAmB;CA+BnC"}
@@ -94,11 +94,13 @@ let McpAuthModule = McpAuthModule_1 = class McpAuthModule {
94
94
  entities_1.OAuthClientEntity,
95
95
  entities_1.AuthorizationCodeEntity,
96
96
  entities_1.OAuthSessionEntity,
97
+ entities_1.OAuthUserProfileEntity,
97
98
  ],
98
99
  }), typeorm_1.TypeOrmModule.forFeature([
99
100
  entities_1.OAuthClientEntity,
100
101
  entities_1.AuthorizationCodeEntity,
101
102
  entities_1.OAuthSessionEntity,
103
+ entities_1.OAuthUserProfileEntity,
102
104
  ]));
103
105
  }
104
106
  const oauthStoreProvider = this.createStoreProvider(resolvedOptions.storeConfiguration);
@@ -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 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 wellKnownAuthorizationServerMetadata:\n '/.well-known/oauth-authorization-server',\n wellKnownProtectedResourceMetadata: '/.well-known/oauth-protected-resource',\n register: '/register',\n authorize: '/authorize',\n callback: '/callback',\n token: '/token',\n revoke: '/revoke',\n },\n protectedResourceMetadata: {\n scopesSupported: ['offline_access'],\n bearerMethodsSupported: ['header'],\n mcpVersionsSupported: ['2025-06-18'],\n },\n authorizationServerMetadata: {\n responseTypesSupported: ['code'],\n responseModesSupported: ['query'],\n grantTypesSupported: ['authorization_code', 'refresh_token'],\n tokenEndpointAuthMethodsSupported: [\n 'client_secret_basic',\n 'client_secret_post',\n 'none',\n ],\n scopesSupported: ['offline_access'],\n codeChallengeMethodsSupported: ['plain', 'S256'],\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 // Merge protectedResourceMetadata with defaults\n protectedResourceMetadata: {\n ...defaults.protectedResourceMetadata,\n ...options.protectedResourceMetadata,\n },\n // Merge authorizationServerMetadata with defaults\n authorizationServerMetadata: {\n ...defaults.authorizationServerMetadata,\n ...options.authorizationServerMetadata,\n },\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 {\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 wellKnownAuthorizationServerMetadata:\n defaultEndpoints.wellKnownAuthorizationServerMetadata,\n wellKnownProtectedResourceMetadata:\n defaultEndpoints.wellKnownProtectedResourceMetadata,\n callback: normalizeEndpoint(`/${apiPrefix}/${defaultEndpoints.callback}`),\n token: normalizeEndpoint(`/${apiPrefix}/${defaultEndpoints.token}`),\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 OAuthUserProfileEntity,\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 wellKnownAuthorizationServerMetadata:\n '/.well-known/oauth-authorization-server',\n wellKnownProtectedResourceMetadata: '/.well-known/oauth-protected-resource',\n register: '/register',\n authorize: '/authorize',\n callback: '/callback',\n token: '/token',\n revoke: '/revoke',\n },\n protectedResourceMetadata: {\n scopesSupported: ['offline_access'],\n bearerMethodsSupported: ['header'],\n mcpVersionsSupported: ['2025-06-18'],\n },\n authorizationServerMetadata: {\n responseTypesSupported: ['code'],\n responseModesSupported: ['query'],\n grantTypesSupported: ['authorization_code', 'refresh_token'],\n tokenEndpointAuthMethodsSupported: [\n 'client_secret_basic',\n 'client_secret_post',\n 'none',\n ],\n scopesSupported: ['offline_access'],\n codeChallengeMethodsSupported: ['plain', 'S256'],\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 OAuthUserProfileEntity,\n ],\n }),\n TypeOrmModule.forFeature([\n OAuthClientEntity,\n AuthorizationCodeEntity,\n OAuthSessionEntity,\n OAuthUserProfileEntity,\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 // Merge protectedResourceMetadata with defaults\n protectedResourceMetadata: {\n ...defaults.protectedResourceMetadata,\n ...options.protectedResourceMetadata,\n },\n // Merge authorizationServerMetadata with defaults\n authorizationServerMetadata: {\n ...defaults.authorizationServerMetadata,\n ...options.authorizationServerMetadata,\n },\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 {\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 wellKnownAuthorizationServerMetadata:\n defaultEndpoints.wellKnownAuthorizationServerMetadata,\n wellKnownProtectedResourceMetadata:\n defaultEndpoints.wellKnownProtectedResourceMetadata,\n callback: normalizeEndpoint(`/${apiPrefix}/${defaultEndpoints.callback}`),\n token: normalizeEndpoint(`/${apiPrefix}/${defaultEndpoints.token}`),\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 +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;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"}
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,CACnC,IAAI,EAAE,qBAAqB,GAC1B,OAAO,CAAC,IAAI,CAAC;IAIV,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;CAIpB"}
@@ -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 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"]}
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(\n _dto: ClientRegistrationDto,\n ): 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"]}
@@ -7,6 +7,7 @@ export interface JwtPayload {
7
7
  resource?: string;
8
8
  type: 'access' | 'refresh' | 'user';
9
9
  user_data?: any;
10
+ user_profile_id?: string;
10
11
  iat?: number;
11
12
  exp?: number;
12
13
  }
@@ -20,7 +21,10 @@ export interface TokenPair {
20
21
  export declare class JwtTokenService {
21
22
  private jwtSecret;
22
23
  constructor(options: OAuthModuleOptions);
23
- generateTokenPair(userId: string, clientId: string, scope?: string, resource?: string): TokenPair;
24
+ generateTokenPair(userId: string, clientId: string, scope?: string, resource?: string, extras?: {
25
+ user_profile_id?: string;
26
+ user_data?: any;
27
+ }): TokenPair;
24
28
  validateToken(token: string): JwtPayload | null;
25
29
  refreshAccessToken(refreshToken: string): TokenPair | null;
26
30
  generateUserToken(userId: string, userData: any): string;
@@ -1 +1 @@
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,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,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;IAoDZ,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"}
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,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,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,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,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,EACjB,MAAM,CAAC,EAAE;QAAE,eAAe,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,GAAG,CAAA;KAAE,GACrD,SAAS;IA6DZ,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI;IAU/C,kBAAkB,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI;IAmB1D,iBAAiB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,GAAG,MAAM;CAkBzD"}