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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/dist/authz/guards/jwt-auth.guard.d.ts +13 -0
  2. package/dist/authz/guards/jwt-auth.guard.d.ts.map +1 -0
  3. package/dist/authz/guards/jwt-auth.guard.js +46 -0
  4. package/dist/authz/guards/jwt-auth.guard.js.map +1 -0
  5. package/dist/authz/index.d.ts +8 -1
  6. package/dist/authz/index.d.ts.map +1 -1
  7. package/dist/authz/index.js +22 -0
  8. package/dist/authz/index.js.map +1 -1
  9. package/dist/authz/interfaces/index.d.ts +3 -0
  10. package/dist/authz/interfaces/index.d.ts.map +1 -0
  11. package/dist/authz/interfaces/index.js +19 -0
  12. package/dist/authz/interfaces/index.js.map +1 -0
  13. package/dist/authz/mcp-oauth.controller.d.ts +53 -0
  14. package/dist/authz/mcp-oauth.controller.d.ts.map +1 -0
  15. package/dist/authz/mcp-oauth.controller.js +305 -0
  16. package/dist/authz/mcp-oauth.controller.js.map +1 -0
  17. package/dist/authz/mcp-oauth.module.d.ts +11 -0
  18. package/dist/authz/mcp-oauth.module.d.ts.map +1 -0
  19. package/dist/authz/mcp-oauth.module.js +173 -0
  20. package/dist/authz/mcp-oauth.module.js.map +1 -0
  21. package/dist/authz/providers/github.provider.d.ts +3 -0
  22. package/dist/authz/providers/github.provider.d.ts.map +1 -0
  23. package/dist/authz/providers/github.provider.js +23 -0
  24. package/dist/authz/providers/github.provider.js.map +1 -0
  25. package/dist/authz/providers/google.provider.d.ts +3 -0
  26. package/dist/authz/providers/google.provider.d.ts.map +1 -0
  27. package/dist/authz/providers/google.provider.js +24 -0
  28. package/dist/authz/providers/google.provider.js.map +1 -0
  29. package/dist/authz/providers/oauth-provider.interface.d.ts +75 -0
  30. package/dist/authz/providers/oauth-provider.interface.d.ts.map +1 -0
  31. package/dist/authz/providers/oauth-provider.interface.js +3 -0
  32. package/dist/authz/providers/oauth-provider.interface.js.map +1 -0
  33. package/dist/authz/services/client.service.d.ts +10 -0
  34. package/dist/authz/services/client.service.d.ts.map +1 -0
  35. package/dist/authz/services/client.service.js +84 -0
  36. package/dist/authz/services/client.service.js.map +1 -0
  37. package/dist/authz/services/jwt-token.service.d.ts +29 -0
  38. package/dist/authz/services/jwt-token.service.d.ts.map +1 -0
  39. package/dist/authz/services/jwt-token.service.js +103 -0
  40. package/dist/authz/services/jwt-token.service.js.map +1 -0
  41. package/dist/authz/services/oauth-strategy.service.d.ts +11 -0
  42. package/dist/authz/services/oauth-strategy.service.d.ts.map +1 -0
  43. package/dist/authz/services/oauth-strategy.service.js +64 -0
  44. package/dist/authz/services/oauth-strategy.service.js.map +1 -0
  45. package/dist/authz/stores/memory-store.service.d.ts +19 -0
  46. package/dist/authz/stores/memory-store.service.d.ts.map +1 -0
  47. package/dist/authz/stores/memory-store.service.js +84 -0
  48. package/dist/authz/stores/memory-store.service.js.map +1 -0
  49. package/dist/authz/stores/memory-store.service.spec.d.ts +2 -0
  50. package/dist/authz/stores/memory-store.service.spec.d.ts.map +1 -0
  51. package/dist/authz/stores/memory-store.service.spec.js +195 -0
  52. package/dist/authz/stores/memory-store.service.spec.js.map +1 -0
  53. package/dist/authz/stores/oauth-store.interface.d.ts +52 -0
  54. package/dist/authz/stores/oauth-store.interface.d.ts.map +1 -0
  55. package/dist/authz/stores/oauth-store.interface.js +3 -0
  56. package/dist/authz/stores/oauth-store.interface.js.map +1 -0
  57. package/dist/authz/stores/sqlite/sqlite-store.service.d.ts +18 -0
  58. package/dist/authz/stores/sqlite/sqlite-store.service.d.ts.map +1 -0
  59. package/dist/authz/stores/sqlite/sqlite-store.service.js +206 -0
  60. package/dist/authz/stores/sqlite/sqlite-store.service.js.map +1 -0
  61. package/dist/authz/stores/typeorm/entities/authorization-code.entity.d.ts +13 -0
  62. package/dist/authz/stores/typeorm/entities/authorization-code.entity.d.ts.map +1 -0
  63. package/dist/authz/stores/typeorm/entities/authorization-code.entity.js +60 -0
  64. package/dist/authz/stores/typeorm/entities/authorization-code.entity.js.map +1 -0
  65. package/dist/authz/stores/typeorm/entities/index.d.ts +4 -0
  66. package/dist/authz/stores/typeorm/entities/index.d.ts.map +1 -0
  67. package/dist/authz/stores/typeorm/entities/index.js +10 -0
  68. package/dist/authz/stores/typeorm/entities/index.js.map +1 -0
  69. package/dist/authz/stores/typeorm/entities/oauth-client.entity.d.ts +16 -0
  70. package/dist/authz/stores/typeorm/entities/oauth-client.entity.d.ts.map +1 -0
  71. package/dist/authz/stores/typeorm/entities/oauth-client.entity.js +72 -0
  72. package/dist/authz/stores/typeorm/entities/oauth-client.entity.js.map +1 -0
  73. package/dist/authz/stores/typeorm/entities/oauth-session.entity.d.ts +13 -0
  74. package/dist/authz/stores/typeorm/entities/oauth-session.entity.d.ts.map +1 -0
  75. package/dist/authz/stores/typeorm/entities/oauth-session.entity.js +60 -0
  76. package/dist/authz/stores/typeorm/entities/oauth-session.entity.js.map +1 -0
  77. package/dist/authz/stores/typeorm/typeorm-store.service.d.ts +21 -0
  78. package/dist/authz/stores/typeorm/typeorm-store.service.d.ts.map +1 -0
  79. package/dist/authz/stores/typeorm/typeorm-store.service.js +87 -0
  80. package/dist/authz/stores/typeorm/typeorm-store.service.js.map +1 -0
  81. package/dist/mcp/services/handlers/mcp-tools.handler.d.ts.map +1 -1
  82. package/dist/mcp/services/handlers/mcp-tools.handler.js.map +1 -1
  83. package/package.json +17 -2
  84. package/src/authz/guards/jwt-auth.guard.ts +45 -0
  85. package/src/authz/index.ts +8 -1
  86. package/src/authz/mcp-oauth.controller.ts +394 -0
  87. package/src/authz/mcp-oauth.module.ts +235 -0
  88. package/src/authz/providers/github.provider.ts +24 -0
  89. package/src/authz/providers/google.provider.ts +22 -0
  90. package/src/authz/providers/oauth-provider.interface.ts +102 -0
  91. package/src/authz/services/client.service.ts +110 -0
  92. package/src/authz/services/jwt-token.service.ts +127 -0
  93. package/src/authz/services/oauth-strategy.service.ts +55 -0
  94. package/src/authz/stores/memory-store.service.spec.ts +240 -0
  95. package/src/authz/stores/memory-store.service.ts +100 -0
  96. package/src/authz/stores/oauth-store.interface.ts +105 -0
  97. package/src/authz/stores/sqlite/sqlite-store.service.ts +279 -0
  98. package/src/authz/stores/typeorm/README.md +133 -0
  99. package/src/authz/stores/typeorm/entities/authorization-code.entity.ts +34 -0
  100. package/src/authz/stores/typeorm/entities/index.ts +3 -0
  101. package/src/authz/stores/typeorm/entities/oauth-client.entity.ts +49 -0
  102. package/src/authz/stores/typeorm/entities/oauth-session.entity.ts +34 -0
  103. package/src/authz/stores/typeorm/typeorm-store.service.ts +98 -0
  104. package/src/mcp/services/handlers/mcp-tools.handler.ts +5 -2
@@ -0,0 +1,240 @@
1
+ import { Test, TestingModule } from '@nestjs/testing';
2
+ import { MemoryStore } from './memory-store.service';
3
+ import { OAuthClient } from './oauth-store.interface';
4
+
5
+ describe('MemoryStore', () => {
6
+ let service: MemoryStore;
7
+
8
+ beforeEach(async () => {
9
+ const module: TestingModule = await Test.createTestingModule({
10
+ providers: [MemoryStore],
11
+ }).compile();
12
+
13
+ service = module.get<MemoryStore>(MemoryStore);
14
+ });
15
+
16
+ it('should be defined', () => {
17
+ expect(service).toBeDefined();
18
+ });
19
+
20
+ describe('generateClientId', () => {
21
+ it('should generate consistent client IDs for identical objects', () => {
22
+ const client1: Partial<OAuthClient> = {
23
+ client_name: 'MCP Inspector',
24
+ client_uri: 'https://github.com/modelcontextprotocol/inspector',
25
+ redirect_uris: ['http://localhost:6274/oauth/callback'],
26
+ token_endpoint_auth_method: 'none',
27
+ grant_types: ['authorization_code', 'refresh_token'],
28
+ response_types: ['code'],
29
+ };
30
+
31
+ const client2: Partial<OAuthClient> = {
32
+ client_name: 'MCP Inspector',
33
+ client_uri: 'https://github.com/modelcontextprotocol/inspector',
34
+ redirect_uris: ['http://localhost:6274/oauth/callback'],
35
+ token_endpoint_auth_method: 'none',
36
+ grant_types: ['authorization_code', 'refresh_token'],
37
+ response_types: ['code'],
38
+ };
39
+
40
+ const id1 = service.generateClientId(client1 as OAuthClient);
41
+ const id2 = service.generateClientId(client2 as OAuthClient);
42
+
43
+ expect(id1).toBe(id2);
44
+ });
45
+
46
+ it('should generate consistent client IDs regardless of property order', () => {
47
+ // First object with properties in one order
48
+ const clientJson1 = `{
49
+ "client_name": "MCP Inspector",
50
+ "client_uri": "https://github.com/modelcontextprotocol/inspector",
51
+ "redirect_uris": ["http://localhost:6274/oauth/callback"],
52
+ "token_endpoint_auth_method": "none",
53
+ "grant_types": ["authorization_code", "refresh_token"],
54
+ "response_types": ["code"]
55
+ }`;
56
+
57
+ // Second object with properties in different order
58
+ const clientJson2 = `{
59
+ "response_types": ["code"],
60
+ "grant_types": ["authorization_code", "refresh_token"],
61
+ "token_endpoint_auth_method": "none",
62
+ "redirect_uris": ["http://localhost:6274/oauth/callback"],
63
+ "client_uri": "https://github.com/modelcontextprotocol/inspector",
64
+ "client_name": "MCP Inspector"
65
+ }`;
66
+
67
+ const client1 = JSON.parse(clientJson1) as OAuthClient;
68
+ const client2 = JSON.parse(clientJson2) as OAuthClient;
69
+
70
+ const id1 = service.generateClientId(client1);
71
+ const id2 = service.generateClientId(client2);
72
+
73
+ expect(id1).toBe(id2);
74
+ });
75
+
76
+ it('should generate consistent client IDs regardless of array order', () => {
77
+ // First object with arrays in one order
78
+ const clientJson1 = `{
79
+ "client_name": "MCP Inspector",
80
+ "client_uri": "https://github.com/modelcontextprotocol/inspector",
81
+ "redirect_uris": [
82
+ "http://localhost:6274/oauth/callback",
83
+ "http://localhost:8080/callback",
84
+ "http://127.0.0.1:3000/auth"
85
+ ],
86
+ "token_endpoint_auth_method": "none",
87
+ "grant_types": [
88
+ "authorization_code",
89
+ "refresh_token",
90
+ "client_credentials"
91
+ ],
92
+ "response_types": ["code", "token"]
93
+ }`;
94
+
95
+ // Second object with arrays in different order
96
+ const clientJson2 = `{
97
+ "client_name": "MCP Inspector",
98
+ "client_uri": "https://github.com/modelcontextprotocol/inspector",
99
+ "redirect_uris": [
100
+ "http://127.0.0.1:3000/auth",
101
+ "http://localhost:6274/oauth/callback",
102
+ "http://localhost:8080/callback"
103
+ ],
104
+ "token_endpoint_auth_method": "none",
105
+ "grant_types": ["client_credentials", "authorization_code", "refresh_token"],
106
+ "response_types": ["token", "code"]
107
+ }`;
108
+
109
+ const client1 = JSON.parse(clientJson1) as OAuthClient;
110
+ const client2 = JSON.parse(clientJson2) as OAuthClient;
111
+
112
+ const id1 = service.generateClientId(client1);
113
+ const id2 = service.generateClientId(client2);
114
+
115
+ expect(id1).toBe(id2);
116
+ });
117
+
118
+ it('should generate consistent client IDs regardless of both property and array order', () => {
119
+ // First object with mixed ordering
120
+ const clientJson1 = `{
121
+ "grant_types": ["refresh_token", "authorization_code"],
122
+ "client_name": "MCP Inspector",
123
+ "response_types": ["code"],
124
+ "redirect_uris": [
125
+ "http://localhost:8080/callback",
126
+ "http://localhost:6274/oauth/callback"
127
+ ],
128
+ "token_endpoint_auth_method": "none",
129
+ "client_uri": "https://github.com/modelcontextprotocol/inspector"
130
+ }`;
131
+
132
+ // Second object with different mixed ordering
133
+ const clientJson2 = `{
134
+ "client_uri": "https://github.com/modelcontextprotocol/inspector",
135
+ "token_endpoint_auth_method": "none",
136
+ "redirect_uris": [
137
+ "http://localhost:6274/oauth/callback",
138
+ "http://localhost:8080/callback"
139
+ ],
140
+ "response_types": ["code"],
141
+ "client_name": "MCP Inspector",
142
+ "grant_types": ["authorization_code", "refresh_token"]
143
+ }`;
144
+
145
+ const client1 = JSON.parse(clientJson1) as OAuthClient;
146
+ const client2 = JSON.parse(clientJson2) as OAuthClient;
147
+
148
+ const id1 = service.generateClientId(client1);
149
+ const id2 = service.generateClientId(client2);
150
+
151
+ expect(id1).toBe(id2);
152
+ });
153
+
154
+ it('should generate different client IDs for different objects', () => {
155
+ const client1: Partial<OAuthClient> = {
156
+ client_name: 'MCP Inspector',
157
+ client_uri: 'https://github.com/modelcontextprotocol/inspector',
158
+ redirect_uris: ['http://localhost:6274/oauth/callback'],
159
+ token_endpoint_auth_method: 'none',
160
+ grant_types: ['authorization_code', 'refresh_token'],
161
+ response_types: ['code'],
162
+ };
163
+
164
+ const client2: Partial<OAuthClient> = {
165
+ client_name: 'Different App', // Changed client name
166
+ client_uri: 'https://github.com/modelcontextprotocol/inspector',
167
+ redirect_uris: ['http://localhost:6274/oauth/callback'],
168
+ token_endpoint_auth_method: 'none',
169
+ grant_types: ['authorization_code', 'refresh_token'],
170
+ response_types: ['code'],
171
+ };
172
+
173
+ const id1 = service.generateClientId(client1 as OAuthClient);
174
+ const id2 = service.generateClientId(client2 as OAuthClient);
175
+
176
+ expect(id1).not.toBe(id2);
177
+ });
178
+
179
+ it('should generate different client IDs when array contents differ', () => {
180
+ const client1: Partial<OAuthClient> = {
181
+ client_name: 'MCP Inspector',
182
+ client_uri: 'https://github.com/modelcontextprotocol/inspector',
183
+ redirect_uris: ['http://localhost:6274/oauth/callback'],
184
+ token_endpoint_auth_method: 'none',
185
+ grant_types: ['authorization_code', 'refresh_token'],
186
+ response_types: ['code'],
187
+ };
188
+
189
+ const client2: Partial<OAuthClient> = {
190
+ client_name: 'MCP Inspector',
191
+ client_uri: 'https://github.com/modelcontextprotocol/inspector',
192
+ redirect_uris: ['http://localhost:6274/oauth/callback'],
193
+ token_endpoint_auth_method: 'none',
194
+ grant_types: ['authorization_code'], // Removed 'refresh_token'
195
+ response_types: ['code'],
196
+ };
197
+
198
+ const id1 = service.generateClientId(client1 as OAuthClient);
199
+ const id2 = service.generateClientId(client2 as OAuthClient);
200
+
201
+ expect(id1).not.toBe(id2);
202
+ });
203
+
204
+ it('should include normalized client name in the generated ID', () => {
205
+ const client: Partial<OAuthClient> = {
206
+ client_name: 'MCP Inspector!@#', // Special characters
207
+ client_uri: 'https://github.com/modelcontextprotocol/inspector',
208
+ redirect_uris: ['http://localhost:6274/oauth/callback'],
209
+ token_endpoint_auth_method: 'none',
210
+ grant_types: ['authorization_code', 'refresh_token'],
211
+ response_types: ['code'],
212
+ };
213
+
214
+ const clientId = service.generateClientId(client as OAuthClient);
215
+
216
+ // Should start with normalized name (lowercase, alphanumeric only)
217
+ expect(clientId).toMatch(/^mcpinspector_[a-f0-9]{16}$/);
218
+ });
219
+
220
+ it('should generate IDs with consistent format', () => {
221
+ const client: Partial<OAuthClient> = {
222
+ client_name: 'Test App',
223
+ client_uri: 'https://example.com',
224
+ redirect_uris: ['http://localhost:3000/callback'],
225
+ token_endpoint_auth_method: 'none',
226
+ grant_types: ['authorization_code'],
227
+ response_types: ['code'],
228
+ };
229
+
230
+ const clientId = service.generateClientId(client as OAuthClient);
231
+
232
+ // Should match pattern: normalizedname_16hexchars
233
+ expect(clientId).toMatch(/^[a-z0-9]+_[a-f0-9]{16}$/);
234
+
235
+ // Should be consistent across multiple calls
236
+ const clientId2 = service.generateClientId(client as OAuthClient);
237
+ expect(clientId).toBe(clientId2);
238
+ });
239
+ });
240
+ });
@@ -0,0 +1,100 @@
1
+ import { Injectable } from '@nestjs/common';
2
+ import { createHash } from 'crypto';
3
+ import { OAuthSession } from '../providers/oauth-provider.interface';
4
+ import {
5
+ AuthorizationCode,
6
+ IOAuthStore,
7
+ OAuthClient,
8
+ } from './oauth-store.interface';
9
+
10
+ // In-memory storage (in production, use a database)
11
+ @Injectable()
12
+ export class MemoryStore implements IOAuthStore {
13
+ private clients = new Map<string, OAuthClient>();
14
+ private authCodes = new Map<string, AuthorizationCode>();
15
+ private oauthSessions = new Map<string, OAuthSession>();
16
+
17
+ async storeClient(client: OAuthClient): Promise<OAuthClient> {
18
+ this.clients.set(client.client_id, client);
19
+ return client;
20
+ }
21
+
22
+ async getClient(client_id: string): Promise<OAuthClient | undefined> {
23
+ return this.clients.get(client_id);
24
+ }
25
+
26
+ async findClient(client_name: string): Promise<OAuthClient | undefined> {
27
+ for (const client of this.clients.values()) {
28
+ if (client.client_name === client_name) {
29
+ return client;
30
+ }
31
+ }
32
+ return undefined;
33
+ }
34
+
35
+ async storeAuthCode(code: AuthorizationCode): Promise<void> {
36
+ this.authCodes.set(code.code, code);
37
+ }
38
+
39
+ async getAuthCode(code: string): Promise<AuthorizationCode | undefined> {
40
+ return this.authCodes.get(code);
41
+ }
42
+
43
+ async removeAuthCode(code: string): Promise<void> {
44
+ this.authCodes.delete(code);
45
+ }
46
+
47
+ // New OAuth session methods for provider-agnostic flow
48
+ async storeOAuthSession(
49
+ sessionId: string,
50
+ session: OAuthSession,
51
+ ): Promise<void> {
52
+ this.oauthSessions.set(sessionId, session);
53
+ }
54
+
55
+ async getOAuthSession(sessionId: string): Promise<OAuthSession | undefined> {
56
+ const session = this.oauthSessions.get(sessionId);
57
+ if (session && session.expiresAt < Date.now()) {
58
+ this.oauthSessions.delete(sessionId);
59
+ return undefined;
60
+ }
61
+ return session;
62
+ }
63
+
64
+ async removeOAuthSession(sessionId: string): Promise<void> {
65
+ this.oauthSessions.delete(sessionId);
66
+ }
67
+
68
+ generateClientId(client: OAuthClient): string {
69
+ // Create deterministic client ID based on entire client object
70
+ const normalizedClient = this.normalizeClientObject(client);
71
+ const clientString = JSON.stringify(normalizedClient);
72
+ const hash = createHash('sha256').update(clientString).digest('hex');
73
+
74
+ // Use first 16 characters of hash with client name prefix for readability
75
+ const normalizedName = client.client_name
76
+ .toLowerCase()
77
+ .replace(/[^a-z0-9]/g, '');
78
+ return `${normalizedName}_${hash.substring(0, 16)}`;
79
+ }
80
+
81
+ private normalizeClientObject(client: OAuthClient): any {
82
+ // Create a normalized version of the client object for consistent hashing
83
+ const normalized: any = {};
84
+
85
+ // Sort object keys to ensure consistent ordering
86
+ const sortedKeys = Object.keys(client).sort();
87
+
88
+ for (const key of sortedKeys) {
89
+ const value = (client as any)[key];
90
+ if (Array.isArray(value)) {
91
+ // Sort arrays to ensure consistent ordering
92
+ normalized[key] = [...value].sort();
93
+ } else {
94
+ normalized[key] = value;
95
+ }
96
+ }
97
+
98
+ return normalized;
99
+ }
100
+ }
@@ -0,0 +1,105 @@
1
+ import { OAuthSession } from '../providers/oauth-provider.interface';
2
+
3
+ export interface OAuthClient {
4
+ client_id: string;
5
+ client_name: string;
6
+ client_description?: string;
7
+ logo_uri?: string;
8
+ client_uri?: string;
9
+ developer_name?: string;
10
+ developer_email?: string;
11
+ redirect_uris: string[];
12
+ grant_types: string[];
13
+ response_types: string[];
14
+ token_endpoint_auth_method: string;
15
+ created_at: Date;
16
+ updated_at: Date;
17
+ }
18
+
19
+ export interface AuthorizationCode {
20
+ code: string;
21
+ user_id: string;
22
+ client_id: string;
23
+ redirect_uri: string;
24
+ code_challenge: string;
25
+ code_challenge_method: string;
26
+ expires_at: number;
27
+ used_at?: Date;
28
+ github_access_token: string;
29
+ }
30
+
31
+ export interface ClientRegistrationDto {
32
+ client_name: string;
33
+ client_description?: string;
34
+ logo_uri?: string;
35
+ client_uri?: string;
36
+ developer_name?: string;
37
+ developer_email?: string;
38
+ redirect_uris: string[];
39
+ grant_types?: string[];
40
+ response_types?: string[];
41
+ token_endpoint_auth_method?: string;
42
+ }
43
+
44
+ /**
45
+ * Interface for OAuth store implementations.
46
+ *
47
+ * Implement this interface to create custom storage solutions (e.g., Redis, Database, etc.).
48
+ * The default implementation is an in-memory store suitable for development.
49
+ *
50
+ * @example
51
+ * ```typescript
52
+ * class RedisOAuthStore implements IOAuthStore {
53
+ * constructor(private redisClient: RedisClient) {}
54
+ *
55
+ * async storeClient(client: OAuthClient): Promise<void> {
56
+ * await this.redisClient.set(`client:${client.client_id}`, JSON.stringify(client));
57
+ * }
58
+ *
59
+ * async getClient(client_id: string): Promise<OAuthClient | undefined> {
60
+ * const data = await this.redisClient.get(`client:${client_id}`);
61
+ * return data ? JSON.parse(data) : undefined;
62
+ * }
63
+ *
64
+ * async findClient(client_name: string): Promise<OAuthClient | undefined> {
65
+ * const data = await this.redisClient.get(`client_name:${client_name}`);
66
+ * return data ? JSON.parse(data) : undefined;
67
+ * }
68
+ *
69
+ * generateClientId(client: OAuthClient): string {
70
+ * // Custom client ID generation logic
71
+ * const normalizedName = client.client_name.toLowerCase().replace(/[^a-z0-9]/g, '');
72
+ * const timestamp = Date.now().toString(36);
73
+ * return `${normalizedName}_${timestamp}`;
74
+ * }
75
+ *
76
+ * // ... implement other methods
77
+ * }
78
+ *
79
+ * // Usage in module:
80
+ * McpOAuthModule.forRoot({
81
+ * provider: GoogleOAuthProvider,
82
+ * clientId: process.env.GOOGLE_CLIENT_ID!,
83
+ * clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
84
+ * jwtSecret: process.env.JWT_SECRET!,
85
+ * memoryStore: new RedisOAuthStore(redisClient), // Custom implementation
86
+ * })
87
+ * ```
88
+ */
89
+ export interface IOAuthStore {
90
+ // Client management
91
+ storeClient(client: OAuthClient): Promise<OAuthClient>;
92
+ getClient(client_id: string): Promise<OAuthClient | undefined>;
93
+ findClient(client_name: string): Promise<OAuthClient | undefined>;
94
+ generateClientId(client: OAuthClient): string;
95
+
96
+ // Authorization code management
97
+ storeAuthCode(code: AuthorizationCode): Promise<void>;
98
+ getAuthCode(code: string): Promise<AuthorizationCode | undefined>;
99
+ removeAuthCode(code: string): Promise<void>;
100
+
101
+ // OAuth session management
102
+ storeOAuthSession(sessionId: string, session: OAuthSession): Promise<void>;
103
+ getOAuthSession(sessionId: string): Promise<OAuthSession | undefined>;
104
+ removeOAuthSession(sessionId: string): Promise<void>;
105
+ }