mcp-server-db2i 1.2.1 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/README.md +90 -308
  2. package/dist/auth/authMiddleware.d.ts +66 -0
  3. package/dist/auth/authMiddleware.d.ts.map +1 -0
  4. package/dist/auth/authMiddleware.js +217 -0
  5. package/dist/auth/authMiddleware.js.map +1 -0
  6. package/dist/auth/index.d.ts +9 -0
  7. package/dist/auth/index.d.ts.map +1 -0
  8. package/dist/auth/index.js +10 -0
  9. package/dist/auth/index.js.map +1 -0
  10. package/dist/auth/tokenManager.d.ts +114 -0
  11. package/dist/auth/tokenManager.d.ts.map +1 -0
  12. package/dist/auth/tokenManager.js +255 -0
  13. package/dist/auth/tokenManager.js.map +1 -0
  14. package/dist/auth/types.d.ts +103 -0
  15. package/dist/auth/types.d.ts.map +1 -0
  16. package/dist/auth/types.js +10 -0
  17. package/dist/auth/types.js.map +1 -0
  18. package/dist/config.d.ts +128 -0
  19. package/dist/config.d.ts.map +1 -1
  20. package/dist/config.js +185 -0
  21. package/dist/config.js.map +1 -1
  22. package/dist/db/connection.d.ts +53 -3
  23. package/dist/db/connection.d.ts.map +1 -1
  24. package/dist/db/connection.js +154 -15
  25. package/dist/db/connection.js.map +1 -1
  26. package/dist/db/queries.d.ts +29 -6
  27. package/dist/db/queries.d.ts.map +1 -1
  28. package/dist/db/queries.js +35 -12
  29. package/dist/db/queries.js.map +1 -1
  30. package/dist/index.d.ts +9 -0
  31. package/dist/index.d.ts.map +1 -1
  32. package/dist/index.js +97 -42
  33. package/dist/index.js.map +1 -1
  34. package/dist/openapi.d.ts +49 -0
  35. package/dist/openapi.d.ts.map +1 -0
  36. package/dist/openapi.js +634 -0
  37. package/dist/openapi.js.map +1 -0
  38. package/dist/server.d.ts +26 -2
  39. package/dist/server.d.ts.map +1 -1
  40. package/dist/server.js +68 -22
  41. package/dist/server.js.map +1 -1
  42. package/dist/tools/metadata.d.ts +10 -0
  43. package/dist/tools/metadata.d.ts.map +1 -1
  44. package/dist/tools/metadata.js +10 -6
  45. package/dist/tools/metadata.js.map +1 -1
  46. package/dist/tools/query.d.ts +4 -0
  47. package/dist/tools/query.d.ts.map +1 -1
  48. package/dist/tools/query.js +5 -3
  49. package/dist/tools/query.js.map +1 -1
  50. package/dist/transports/http.d.ts +26 -0
  51. package/dist/transports/http.d.ts.map +1 -0
  52. package/dist/transports/http.js +552 -0
  53. package/dist/transports/http.js.map +1 -0
  54. package/dist/transports/index.d.ts +8 -0
  55. package/dist/transports/index.d.ts.map +1 -0
  56. package/dist/transports/index.js +8 -0
  57. package/dist/transports/index.js.map +1 -0
  58. package/dist/transports/sessionManager.d.ts +106 -0
  59. package/dist/transports/sessionManager.d.ts.map +1 -0
  60. package/dist/transports/sessionManager.js +260 -0
  61. package/dist/transports/sessionManager.js.map +1 -0
  62. package/package.json +9 -5
@@ -0,0 +1,217 @@
1
+ /**
2
+ * Authentication Middleware for HTTP Transport
3
+ *
4
+ * Express middleware to validate Bearer tokens on protected routes.
5
+ * Supports multiple authentication modes:
6
+ * - 'required': Full /auth flow with per-user DB credentials (default)
7
+ * - 'token': Pre-shared static token, uses env DB credentials
8
+ * - 'none': No authentication required, uses env DB credentials
9
+ */
10
+ import { timingSafeEqual } from 'node:crypto';
11
+ import { getTokenManager } from './tokenManager.js';
12
+ import { createChildLogger } from '../utils/logger.js';
13
+ import { getHttpConfig } from '../config.js';
14
+ const log = createChildLogger({ component: 'auth-middleware' });
15
+ /**
16
+ * Extract Bearer token from Authorization header
17
+ */
18
+ function extractBearerToken(authHeader) {
19
+ if (!authHeader) {
20
+ return null;
21
+ }
22
+ const parts = authHeader.split(' ');
23
+ if (parts.length !== 2 || parts[0].toLowerCase() !== 'bearer') {
24
+ return null;
25
+ }
26
+ return parts[1];
27
+ }
28
+ /**
29
+ * Authentication middleware for protected routes
30
+ *
31
+ * Behavior depends on MCP_AUTH_MODE:
32
+ * - 'required': Validates Bearer token from /auth flow, attaches token session
33
+ * - 'token': Validates Bearer token against static MCP_AUTH_TOKEN
34
+ * - 'none': Skips authentication entirely
35
+ *
36
+ * @example
37
+ * app.post('/mcp', authMiddleware, (req, res) => {
38
+ * const session = (req as AuthenticatedRequest).tokenSession;
39
+ * // Use session.config for DB connection (only in 'required' mode)
40
+ * });
41
+ */
42
+ export function authMiddleware(req, res, next) {
43
+ const httpConfig = getHttpConfig();
44
+ // No auth mode - skip authentication entirely
45
+ if (httpConfig.authMode === 'none') {
46
+ log.debug({ path: req.path, method: req.method, authMode: 'none' }, 'Auth disabled, allowing request');
47
+ return next();
48
+ }
49
+ // Token mode - validate against static token
50
+ if (httpConfig.authMode === 'token') {
51
+ const authHeader = req.headers.authorization;
52
+ const token = extractBearerToken(authHeader);
53
+ if (!token) {
54
+ log.debug({ path: req.path, method: req.method }, 'Missing or invalid Authorization header (token mode)');
55
+ res.status(401).json({
56
+ error: 'unauthorized',
57
+ error_description: 'Missing or invalid Authorization header. Use: Authorization: Bearer <token>',
58
+ });
59
+ return;
60
+ }
61
+ // Use constant-time comparison to prevent timing attacks
62
+ const staticToken = httpConfig.staticToken ?? '';
63
+ const tokenBuffer = Buffer.from(token);
64
+ const staticTokenBuffer = Buffer.from(staticToken);
65
+ const tokensMatch = tokenBuffer.length === staticTokenBuffer.length &&
66
+ timingSafeEqual(tokenBuffer, staticTokenBuffer);
67
+ if (tokensMatch) {
68
+ log.debug({ path: req.path, method: req.method, authMode: 'token' }, 'Static token validated');
69
+ // Store token for session keying (will use global config for DB)
70
+ req.authToken = token;
71
+ return next();
72
+ }
73
+ log.debug({ path: req.path, method: req.method }, 'Invalid static token');
74
+ res.status(401).json({
75
+ error: 'invalid_token',
76
+ error_description: 'Invalid authentication token',
77
+ });
78
+ return;
79
+ }
80
+ // Required mode - full token validation with per-user credentials
81
+ const authHeader = req.headers.authorization;
82
+ const token = extractBearerToken(authHeader);
83
+ if (!token) {
84
+ log.debug({ path: req.path, method: req.method }, 'Missing or invalid Authorization header');
85
+ res.status(401).json({
86
+ error: 'unauthorized',
87
+ error_description: 'Missing or invalid Authorization header. Use: Authorization: Bearer <token>',
88
+ });
89
+ return;
90
+ }
91
+ const tokenManager = getTokenManager();
92
+ const result = tokenManager.validateToken(token);
93
+ if (!result.valid || !result.session) {
94
+ log.debug({ path: req.path, method: req.method, error: result.error }, 'Token validation failed');
95
+ res.status(401).json({
96
+ error: 'invalid_token',
97
+ error_description: result.error ?? 'Token validation failed',
98
+ });
99
+ return;
100
+ }
101
+ // Attach session to request
102
+ req.tokenSession = result.session;
103
+ req.authToken = token;
104
+ log.debug({
105
+ path: req.path,
106
+ method: req.method,
107
+ user: result.session.config.username,
108
+ host: result.session.config.hostname,
109
+ }, 'Request authenticated');
110
+ next();
111
+ }
112
+ /**
113
+ * Get the current auth mode for use in route handlers
114
+ */
115
+ export function getAuthModeFromConfig() {
116
+ return getHttpConfig().authMode;
117
+ }
118
+ /**
119
+ * Optional authentication middleware
120
+ *
121
+ * Similar to authMiddleware but doesn't require authentication.
122
+ * If a valid token is provided, attaches the session to the request.
123
+ * If no token or invalid token, continues without error.
124
+ *
125
+ * Useful for endpoints that work with or without authentication.
126
+ */
127
+ export function optionalAuthMiddleware(req, res, next) {
128
+ const authHeader = req.headers.authorization;
129
+ const token = extractBearerToken(authHeader);
130
+ if (token) {
131
+ const tokenManager = getTokenManager();
132
+ const result = tokenManager.validateToken(token);
133
+ if (result.valid && result.session) {
134
+ req.tokenSession = result.session;
135
+ req.authToken = token;
136
+ }
137
+ }
138
+ next();
139
+ }
140
+ /**
141
+ * Rate limiting middleware for auth endpoints
142
+ *
143
+ * Simple in-memory rate limiter to prevent brute force attacks.
144
+ * Tracks failed attempts by IP address.
145
+ */
146
+ const authAttempts = new Map();
147
+ const AUTH_RATE_LIMIT = {
148
+ maxAttempts: 5,
149
+ windowMs: 60000, // 1 minute
150
+ };
151
+ /**
152
+ * Get client IP from request
153
+ *
154
+ * Uses Express's req.ip which respects the 'trust proxy' setting.
155
+ * If proxy is trusted, req.ip will contain the client IP from X-Forwarded-For.
156
+ * If proxy is not trusted, req.ip will be the direct connection IP.
157
+ *
158
+ * To trust proxy headers, set app.set('trust proxy', true) or configure
159
+ * specific trusted proxies. Without this, X-Forwarded-For headers are ignored.
160
+ */
161
+ function getClientIp(req) {
162
+ // Use Express's req.ip which respects 'trust proxy' setting
163
+ // This prevents IP spoofing when proxy is not trusted
164
+ return req.ip ?? req.socket.remoteAddress ?? 'unknown';
165
+ }
166
+ /**
167
+ * Auth rate limiting middleware
168
+ *
169
+ * Limits authentication attempts per IP to prevent brute force.
170
+ * Should be applied to the /auth endpoint.
171
+ */
172
+ export function authRateLimitMiddleware(req, res, next) {
173
+ const ip = getClientIp(req);
174
+ const now = Date.now();
175
+ // Clean up expired entries
176
+ const entry = authAttempts.get(ip);
177
+ if (entry && entry.resetAt < now) {
178
+ authAttempts.delete(ip);
179
+ }
180
+ const current = authAttempts.get(ip);
181
+ if (current && current.count >= AUTH_RATE_LIMIT.maxAttempts) {
182
+ const retryAfter = Math.ceil((current.resetAt - now) / 1000);
183
+ log.warn({ ip, attempts: current.count }, 'Auth rate limit exceeded');
184
+ res.status(429).json({
185
+ error: 'too_many_requests',
186
+ error_description: `Too many authentication attempts. Try again in ${retryAfter} seconds.`,
187
+ retry_after: retryAfter,
188
+ });
189
+ return;
190
+ }
191
+ next();
192
+ }
193
+ /**
194
+ * Record a failed auth attempt for rate limiting
195
+ */
196
+ export function recordFailedAuthAttempt(req) {
197
+ const ip = getClientIp(req);
198
+ const now = Date.now();
199
+ const current = authAttempts.get(ip);
200
+ if (current && current.resetAt > now) {
201
+ current.count++;
202
+ }
203
+ else {
204
+ authAttempts.set(ip, {
205
+ count: 1,
206
+ resetAt: now + AUTH_RATE_LIMIT.windowMs,
207
+ });
208
+ }
209
+ }
210
+ /**
211
+ * Clear rate limit for an IP (on successful auth)
212
+ */
213
+ export function clearAuthRateLimit(req) {
214
+ const ip = getClientIp(req);
215
+ authAttempts.delete(ip);
216
+ }
217
+ //# sourceMappingURL=authMiddleware.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"authMiddleware.js","sourceRoot":"","sources":["../../src/auth/authMiddleware.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Authentication module for HTTP transport
3
+ *
4
+ * Exports all auth-related types, middleware, and utilities.
5
+ */
6
+ export type { AuthRequest, AuthResponse, AuthErrorResponse, TokenSession, TokenValidationResult, AuthValidationResult, } from './types.js';
7
+ export { getTokenManager, TokenManager, type SessionCleanupCallback } from './tokenManager.js';
8
+ export { authMiddleware, optionalAuthMiddleware, authRateLimitMiddleware, recordFailedAuthAttempt, clearAuthRateLimit, type AuthenticatedRequest, } from './authMiddleware.js';
9
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,YAAY,EACV,WAAW,EACX,YAAY,EACZ,iBAAiB,EACjB,YAAY,EACZ,qBAAqB,EACrB,oBAAoB,GACrB,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,KAAK,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAG/F,OAAO,EACL,cAAc,EACd,sBAAsB,EACtB,uBAAuB,EACvB,uBAAuB,EACvB,kBAAkB,EAClB,KAAK,oBAAoB,GAC1B,MAAM,qBAAqB,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Authentication module for HTTP transport
3
+ *
4
+ * Exports all auth-related types, middleware, and utilities.
5
+ */
6
+ // Token Manager
7
+ export { getTokenManager, TokenManager } from './tokenManager.js';
8
+ // Middleware
9
+ export { authMiddleware, optionalAuthMiddleware, authRateLimitMiddleware, recordFailedAuthAttempt, clearAuthRateLimit, } from './authMiddleware.js';
10
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/auth/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAYH,gBAAgB;AAChB,OAAO,EAAE,eAAe,EAAE,YAAY,EAA+B,MAAM,mBAAmB,CAAC;AAE/F,aAAa;AACb,OAAO,EACL,cAAc,EACd,sBAAsB,EACtB,uBAAuB,EACvB,uBAAuB,EACvB,kBAAkB,GAEnB,MAAM,qBAAqB,CAAC"}
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Token Manager for HTTP Authentication
3
+ *
4
+ * Handles secure token generation, validation, session storage, and cleanup.
5
+ * Tokens are stored in memory with automatic cleanup of expired sessions.
6
+ */
7
+ import type { DB2iConfig } from '../config.js';
8
+ import type { TokenSession, TokenValidationResult } from './types.js';
9
+ /**
10
+ * Callback type for session cleanup notification
11
+ * Used to close associated resources (e.g., connection pools) when tokens expire
12
+ */
13
+ export type SessionCleanupCallback = (token: string) => Promise<void> | void;
14
+ /**
15
+ * Token Manager singleton for managing authentication tokens
16
+ */
17
+ declare class TokenManager {
18
+ private static instance;
19
+ private sessions;
20
+ private cleanupTimer;
21
+ private readonly cleanupIntervalMs;
22
+ private cleanupCallback;
23
+ private constructor();
24
+ /**
25
+ * Get the singleton instance
26
+ */
27
+ static getInstance(): TokenManager;
28
+ /**
29
+ * Generate a cryptographically secure token
30
+ * Uses 32 bytes (256 bits) of randomness encoded as base64url
31
+ */
32
+ private generateTokenString;
33
+ /**
34
+ * Create a new token session
35
+ *
36
+ * @param config - DB2i configuration for this session
37
+ * @param durationSeconds - Optional custom token duration
38
+ * @returns The generated token and session info
39
+ */
40
+ createSession(config: DB2iConfig, durationSeconds?: number): {
41
+ token: string;
42
+ expiresAt: Date;
43
+ expiresIn: number;
44
+ };
45
+ /**
46
+ * Validate a token and return the session
47
+ *
48
+ * @param token - The token to validate
49
+ * @returns Validation result with session if valid
50
+ */
51
+ validateToken(token: string): TokenValidationResult;
52
+ /**
53
+ * Get a session by token without validation
54
+ * Used internally when token is already validated
55
+ */
56
+ getSession(token: string): TokenSession | undefined;
57
+ /**
58
+ * Update the MCP session ID for a token
59
+ * Used when a stateful MCP session is established
60
+ */
61
+ setMcpSessionId(token: string, mcpSessionId: string): void;
62
+ /**
63
+ * Revoke a token
64
+ *
65
+ * @param token - The token to revoke
66
+ * @returns true if token was found and revoked
67
+ */
68
+ revokeToken(token: string): Promise<boolean>;
69
+ /**
70
+ * Get session statistics
71
+ */
72
+ getStats(): {
73
+ totalSessions: number;
74
+ activeSessions: number;
75
+ expiredSessions: number;
76
+ };
77
+ /**
78
+ * Clean up expired sessions
79
+ */
80
+ private cleanupExpiredSessions;
81
+ /**
82
+ * Start the cleanup timer
83
+ */
84
+ private startCleanupTimer;
85
+ /**
86
+ * Stop the cleanup timer and clear all sessions
87
+ * Used for graceful shutdown
88
+ */
89
+ shutdown(): Promise<void>;
90
+ /**
91
+ * Check if a new session can be created (advisory)
92
+ *
93
+ * Note: This is an advisory check. In Node.js single-threaded environment,
94
+ * there's no race condition between synchronous operations. However, if async
95
+ * operations occur between calling this method and createSession(), the count
96
+ * could change. The hard limit is enforced in createSession() which throws
97
+ * an error if the limit is exceeded.
98
+ */
99
+ canCreateSession(): boolean;
100
+ /**
101
+ * Set a callback to be called when sessions are cleaned up
102
+ * Used to close associated resources (e.g., connection pools)
103
+ *
104
+ * @param callback - Function called with the token when a session is removed
105
+ */
106
+ setCleanupCallback(callback: SessionCleanupCallback): void;
107
+ /**
108
+ * Internal method to notify about session cleanup
109
+ */
110
+ private notifyCleanup;
111
+ }
112
+ export declare function getTokenManager(): TokenManager;
113
+ export { TokenManager };
114
+ //# sourceMappingURL=tokenManager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokenManager.d.ts","sourceRoot":"","sources":["../../src/auth/tokenManager.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAG/C,OAAO,KAAK,EACV,YAAY,EACZ,qBAAqB,EACtB,MAAM,YAAY,CAAC;AAIpB;;;GAGG;AACH,MAAM,MAAM,sBAAsB,GAAG,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;AAE7E;;GAEG;AACH,cAAM,YAAY;IAChB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAe;IACtC,OAAO,CAAC,QAAQ,CAAwC;IACxD,OAAO,CAAC,YAAY,CAA+B;IACnD,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAS;IAC3C,OAAO,CAAC,eAAe,CAAuC;IAE9D,OAAO;IAKP;;OAEG;IACH,MAAM,CAAC,WAAW,IAAI,YAAY;IAOlC;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IAI3B;;;;;;OAMG;IACH,aAAa,CACX,MAAM,EAAE,UAAU,EAClB,eAAe,CAAC,EAAE,MAAM,GACvB;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,IAAI,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE;IAsCxD;;;;;OAKG;IACH,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,qBAAqB;IA4BnD;;;OAGG;IACH,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS;IAInD;;;OAGG;IACH,eAAe,CAAC,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,IAAI;IAW1D;;;;;OAKG;IACG,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAqBlD;;OAEG;IACH,QAAQ,IAAI;QACV,aAAa,EAAE,MAAM,CAAC;QACtB,cAAc,EAAE,MAAM,CAAC;QACvB,eAAe,EAAE,MAAM,CAAC;KACzB;IAoBD;;OAEG;YACW,sBAAsB;IA0BpC;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAkBzB;;;OAGG;IACG,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAkB/B;;;;;;;;OAQG;IACH,gBAAgB,IAAI,OAAO;IAK3B;;;;;OAKG;IACH,kBAAkB,CAAC,QAAQ,EAAE,sBAAsB,GAAG,IAAI;IAK1D;;OAEG;YACW,aAAa;CAS5B;AAGD,wBAAgB,eAAe,IAAI,YAAY,CAE9C;AAGD,OAAO,EAAE,YAAY,EAAE,CAAC"}
@@ -0,0 +1,255 @@
1
+ /**
2
+ * Token Manager for HTTP Authentication
3
+ *
4
+ * Handles secure token generation, validation, session storage, and cleanup.
5
+ * Tokens are stored in memory with automatic cleanup of expired sessions.
6
+ */
7
+ import crypto from 'node:crypto';
8
+ import { getHttpConfig } from '../config.js';
9
+ import { createChildLogger } from '../utils/logger.js';
10
+ const log = createChildLogger({ component: 'token-manager' });
11
+ /**
12
+ * Token Manager singleton for managing authentication tokens
13
+ */
14
+ class TokenManager {
15
+ static instance;
16
+ sessions = new Map();
17
+ cleanupTimer = null;
18
+ cleanupIntervalMs = 60000; // 1 minute
19
+ cleanupCallback = null;
20
+ constructor() {
21
+ this.startCleanupTimer();
22
+ log.debug('Token manager initialized');
23
+ }
24
+ /**
25
+ * Get the singleton instance
26
+ */
27
+ static getInstance() {
28
+ if (!TokenManager.instance) {
29
+ TokenManager.instance = new TokenManager();
30
+ }
31
+ return TokenManager.instance;
32
+ }
33
+ /**
34
+ * Generate a cryptographically secure token
35
+ * Uses 32 bytes (256 bits) of randomness encoded as base64url
36
+ */
37
+ generateTokenString() {
38
+ return crypto.randomBytes(32).toString('base64url');
39
+ }
40
+ /**
41
+ * Create a new token session
42
+ *
43
+ * @param config - DB2i configuration for this session
44
+ * @param durationSeconds - Optional custom token duration
45
+ * @returns The generated token and session info
46
+ */
47
+ createSession(config, durationSeconds) {
48
+ const httpConfig = getHttpConfig();
49
+ // Check max sessions limit
50
+ if (this.sessions.size >= httpConfig.maxSessions) {
51
+ throw new Error(`Maximum concurrent sessions (${httpConfig.maxSessions}) reached. Please try again later.`);
52
+ }
53
+ const token = this.generateTokenString();
54
+ const now = new Date();
55
+ const expiresIn = durationSeconds ?? httpConfig.tokenExpiry;
56
+ const expiresAt = new Date(now.getTime() + expiresIn * 1000);
57
+ const session = {
58
+ token,
59
+ config,
60
+ createdAt: now,
61
+ expiresAt,
62
+ lastUsedAt: now,
63
+ };
64
+ this.sessions.set(token, session);
65
+ log.info({
66
+ sessionCount: this.sessions.size,
67
+ expiresIn,
68
+ host: config.hostname,
69
+ // Note: username intentionally omitted for PII compliance
70
+ }, 'Token session created');
71
+ return { token, expiresAt, expiresIn };
72
+ }
73
+ /**
74
+ * Validate a token and return the session
75
+ *
76
+ * @param token - The token to validate
77
+ * @returns Validation result with session if valid
78
+ */
79
+ validateToken(token) {
80
+ if (!token || typeof token !== 'string') {
81
+ return { valid: false, error: 'Invalid token format' };
82
+ }
83
+ const session = this.sessions.get(token);
84
+ if (!session) {
85
+ log.debug({ tokenPrefix: token.substring(0, 8) }, 'Token not found');
86
+ return { valid: false, error: 'Token not found or expired' };
87
+ }
88
+ // Check expiration
89
+ if (new Date() > session.expiresAt) {
90
+ log.debug({ tokenPrefix: token.substring(0, 8), expiredAt: session.expiresAt }, 'Token expired');
91
+ this.sessions.delete(token);
92
+ return { valid: false, error: 'Token expired' };
93
+ }
94
+ // Update last used timestamp
95
+ session.lastUsedAt = new Date();
96
+ return { valid: true, session };
97
+ }
98
+ /**
99
+ * Get a session by token without validation
100
+ * Used internally when token is already validated
101
+ */
102
+ getSession(token) {
103
+ return this.sessions.get(token);
104
+ }
105
+ /**
106
+ * Update the MCP session ID for a token
107
+ * Used when a stateful MCP session is established
108
+ */
109
+ setMcpSessionId(token, mcpSessionId) {
110
+ const session = this.sessions.get(token);
111
+ if (session) {
112
+ session.mcpSessionId = mcpSessionId;
113
+ log.debug({ tokenPrefix: token.substring(0, 8), mcpSessionId }, 'MCP session ID associated with token');
114
+ }
115
+ }
116
+ /**
117
+ * Revoke a token
118
+ *
119
+ * @param token - The token to revoke
120
+ * @returns true if token was found and revoked
121
+ */
122
+ async revokeToken(token) {
123
+ const session = this.sessions.get(token);
124
+ if (!session) {
125
+ return false;
126
+ }
127
+ this.sessions.delete(token);
128
+ // Notify cleanup callback to close associated resources
129
+ await this.notifyCleanup(token);
130
+ log.info({
131
+ tokenPrefix: token.substring(0, 8),
132
+ sessionCount: this.sessions.size,
133
+ }, 'Token revoked');
134
+ return true;
135
+ }
136
+ /**
137
+ * Get session statistics
138
+ */
139
+ getStats() {
140
+ const now = new Date();
141
+ let activeSessions = 0;
142
+ let expiredSessions = 0;
143
+ for (const session of this.sessions.values()) {
144
+ if (now <= session.expiresAt) {
145
+ activeSessions++;
146
+ }
147
+ else {
148
+ expiredSessions++;
149
+ }
150
+ }
151
+ return {
152
+ totalSessions: this.sessions.size,
153
+ activeSessions,
154
+ expiredSessions,
155
+ };
156
+ }
157
+ /**
158
+ * Clean up expired sessions
159
+ */
160
+ async cleanupExpiredSessions() {
161
+ const now = new Date();
162
+ const expiredTokens = [];
163
+ for (const [token, session] of this.sessions.entries()) {
164
+ if (now > session.expiresAt) {
165
+ expiredTokens.push(token);
166
+ }
167
+ }
168
+ if (expiredTokens.length > 0) {
169
+ for (const token of expiredTokens) {
170
+ this.sessions.delete(token);
171
+ // Notify cleanup callback to close associated resources
172
+ await this.notifyCleanup(token);
173
+ }
174
+ log.info({
175
+ expiredCount: expiredTokens.length,
176
+ remainingCount: this.sessions.size,
177
+ }, 'Cleaned up expired sessions');
178
+ }
179
+ }
180
+ /**
181
+ * Start the cleanup timer
182
+ */
183
+ startCleanupTimer() {
184
+ if (this.cleanupTimer) {
185
+ return;
186
+ }
187
+ this.cleanupTimer = setInterval(() => {
188
+ this.cleanupExpiredSessions();
189
+ }, this.cleanupIntervalMs);
190
+ // Don't block process exit
191
+ this.cleanupTimer.unref();
192
+ log.debug({ intervalMs: this.cleanupIntervalMs }, 'Session cleanup timer started');
193
+ }
194
+ /**
195
+ * Stop the cleanup timer and clear all sessions
196
+ * Used for graceful shutdown
197
+ */
198
+ async shutdown() {
199
+ if (this.cleanupTimer) {
200
+ clearInterval(this.cleanupTimer);
201
+ this.cleanupTimer = null;
202
+ }
203
+ // Notify cleanup callback for all remaining sessions
204
+ const tokens = Array.from(this.sessions.keys());
205
+ for (const token of tokens) {
206
+ await this.notifyCleanup(token);
207
+ }
208
+ const sessionCount = this.sessions.size;
209
+ this.sessions.clear();
210
+ log.info({ clearedSessions: sessionCount }, 'Token manager shutdown');
211
+ }
212
+ /**
213
+ * Check if a new session can be created (advisory)
214
+ *
215
+ * Note: This is an advisory check. In Node.js single-threaded environment,
216
+ * there's no race condition between synchronous operations. However, if async
217
+ * operations occur between calling this method and createSession(), the count
218
+ * could change. The hard limit is enforced in createSession() which throws
219
+ * an error if the limit is exceeded.
220
+ */
221
+ canCreateSession() {
222
+ const httpConfig = getHttpConfig();
223
+ return this.sessions.size < httpConfig.maxSessions;
224
+ }
225
+ /**
226
+ * Set a callback to be called when sessions are cleaned up
227
+ * Used to close associated resources (e.g., connection pools)
228
+ *
229
+ * @param callback - Function called with the token when a session is removed
230
+ */
231
+ setCleanupCallback(callback) {
232
+ this.cleanupCallback = callback;
233
+ log.debug('Session cleanup callback registered');
234
+ }
235
+ /**
236
+ * Internal method to notify about session cleanup
237
+ */
238
+ async notifyCleanup(token) {
239
+ if (this.cleanupCallback) {
240
+ try {
241
+ await this.cleanupCallback(token);
242
+ }
243
+ catch (err) {
244
+ log.error({ err, tokenPrefix: token.substring(0, 8) }, 'Error in cleanup callback');
245
+ }
246
+ }
247
+ }
248
+ }
249
+ // Export singleton getter
250
+ export function getTokenManager() {
251
+ return TokenManager.getInstance();
252
+ }
253
+ // Export the class type for testing
254
+ export { TokenManager };
255
+ //# sourceMappingURL=tokenManager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokenManager.js","sourceRoot":"","sources":["../../src/auth/tokenManager.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,MAAM,MAAM,aAAa,CAAC;AAEjC,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAMvD,MAAM,GAAG,GAAG,iBAAiB,CAAC,EAAE,SAAS,EAAE,eAAe,EAAE,CAAC,CAAC;AAQ9D;;GAEG;AACH,MAAM,YAAY;IACR,MAAM,CAAC,QAAQ,CAAe;IAC9B,QAAQ,GAA8B,IAAI,GAAG,EAAE,CAAC;IAChD,YAAY,GAA0B,IAAI,CAAC;IAClC,iBAAiB,GAAG,KAAK,CAAC,CAAC,WAAW;IAC/C,eAAe,GAAkC,IAAI,CAAC;IAE9D;QACE,IAAI,CAAC,iBAAiB,EAAE,CAAC;QACzB,GAAG,CAAC,KAAK,CAAC,2BAA2B,CAAC,CAAC;IACzC,CAAC;IAED;;OAEG;IACH,MAAM,CAAC,WAAW;QAChB,IAAI,CAAC,YAAY,CAAC,QAAQ,EAAE,CAAC;YAC3B,YAAY,CAAC,QAAQ,GAAG,IAAI,YAAY,EAAE,CAAC;QAC7C,CAAC;QACD,OAAO,YAAY,CAAC,QAAQ,CAAC;IAC/B,CAAC;IAED;;;OAGG;IACK,mBAAmB;QACzB,OAAO,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;IACtD,CAAC;IAED;;;;;;OAMG;IACH,aAAa,CACX,MAAkB,EAClB,eAAwB;QAExB,MAAM,UAAU,GAAG,aAAa,EAAE,CAAC;QAEnC,2BAA2B;QAC3B,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,IAAI,UAAU,CAAC,WAAW,EAAE,CAAC;YACjD,MAAM,IAAI,KAAK,CACb,gCAAgC,UAAU,CAAC,WAAW,oCAAoC,CAC3F,CAAC;QACJ,CAAC;QAED,MAAM,KAAK,GAAG,IAAI,CAAC,mBAAmB,EAAE,CAAC;QACzC,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,SAAS,GAAG,eAAe,IAAI,UAAU,CAAC,WAAW,CAAC;QAC5D,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,SAAS,GAAG,IAAI,CAAC,CAAC;QAE7D,MAAM,OAAO,GAAiB;YAC5B,KAAK;YACL,MAAM;YACN,SAAS,EAAE,GAAG;YACd,SAAS;YACT,UAAU,EAAE,GAAG;SAChB,CAAC;QAEF,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;QAElC,GAAG,CAAC,IAAI,CACN;YACE,YAAY,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI;YAChC,SAAS;YACT,IAAI,EAAE,MAAM,CAAC,QAAQ;YACrB,0DAA0D;SAC3D,EACD,uBAAuB,CACxB,CAAC;QAEF,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,EAAE,CAAC;IACzC,CAAC;IAED;;;;;OAKG;IACH,aAAa,CAAC,KAAa;QACzB,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YACxC,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,sBAAsB,EAAE,CAAC;QACzD,CAAC;QAED,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAEzC,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,GAAG,CAAC,KAAK,CAAC,EAAE,WAAW,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,iBAAiB,CAAC,CAAC;YACrE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,4BAA4B,EAAE,CAAC;QAC/D,CAAC;QAED,mBAAmB;QACnB,IAAI,IAAI,IAAI,EAAE,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;YACnC,GAAG,CAAC,KAAK,CACP,EAAE,WAAW,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,EACpE,eAAe,CAChB,CAAC;YACF,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAC5B,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,eAAe,EAAE,CAAC;QAClD,CAAC;QAED,6BAA6B;QAC7B,OAAO,CAAC,UAAU,GAAG,IAAI,IAAI,EAAE,CAAC;QAEhC,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC;IAClC,CAAC;IAED;;;OAGG;IACH,UAAU,CAAC,KAAa;QACtB,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAClC,CAAC;IAED;;;OAGG;IACH,eAAe,CAAC,KAAa,EAAE,YAAoB;QACjD,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACzC,IAAI,OAAO,EAAE,CAAC;YACZ,OAAO,CAAC,YAAY,GAAG,YAAY,CAAC;YACpC,GAAG,CAAC,KAAK,CACP,EAAE,WAAW,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,YAAY,EAAE,EACpD,sCAAsC,CACvC,CAAC;QACJ,CAAC;IACH,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,WAAW,CAAC,KAAa;QAC7B,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACzC,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO,KAAK,CAAC;QACf,CAAC;QAED,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAE5B,wDAAwD;QACxD,MAAM,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;QAEhC,GAAG,CAAC,IAAI,CACN;YACE,WAAW,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC;YAClC,YAAY,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI;SACjC,EACD,eAAe,CAChB,CAAC;QACF,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;OAEG;IACH,QAAQ;QAKN,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,IAAI,cAAc,GAAG,CAAC,CAAC;QACvB,IAAI,eAAe,GAAG,CAAC,CAAC;QAExB,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC;YAC7C,IAAI,GAAG,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;gBAC7B,cAAc,EAAE,CAAC;YACnB,CAAC;iBAAM,CAAC;gBACN,eAAe,EAAE,CAAC;YACpB,CAAC;QACH,CAAC;QAED,OAAO;YACL,aAAa,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI;YACjC,cAAc;YACd,eAAe;SAChB,CAAC;IACJ,CAAC;IAED;;OAEG;IACK,KAAK,CAAC,sBAAsB;QAClC,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,aAAa,GAAa,EAAE,CAAC;QAEnC,KAAK,MAAM,CAAC,KAAK,EAAE,OAAO,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,EAAE,CAAC;YACvD,IAAI,GAAG,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC;gBAC5B,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC5B,CAAC;QACH,CAAC;QAED,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC7B,KAAK,MAAM,KAAK,IAAI,aAAa,EAAE,CAAC;gBAClC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;gBAC5B,wDAAwD;gBACxD,MAAM,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;YAClC,CAAC;YACD,GAAG,CAAC,IAAI,CACN;gBACE,YAAY,EAAE,aAAa,CAAC,MAAM;gBAClC,cAAc,EAAE,IAAI,CAAC,QAAQ,CAAC,IAAI;aACnC,EACD,6BAA6B,CAC9B,CAAC;QACJ,CAAC;IACH,CAAC;IAED;;OAEG;IACK,iBAAiB;QACvB,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;YACtB,OAAO;QACT,CAAC;QAED,IAAI,CAAC,YAAY,GAAG,WAAW,CAAC,GAAG,EAAE;YACnC,IAAI,CAAC,sBAAsB,EAAE,CAAC;QAChC,CAAC,EAAE,IAAI,CAAC,iBAAiB,CAAC,CAAC;QAE3B,2BAA2B;QAC3B,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,CAAC;QAE1B,GAAG,CAAC,KAAK,CACP,EAAE,UAAU,EAAE,IAAI,CAAC,iBAAiB,EAAE,EACtC,+BAA+B,CAChC,CAAC;IACJ,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,QAAQ;QACZ,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;YACtB,aAAa,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;YACjC,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;QAC3B,CAAC;QAED,qDAAqD;QACrD,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;QAChD,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;YAC3B,MAAM,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC;QAClC,CAAC;QAED,MAAM,YAAY,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;QACxC,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;QAEtB,GAAG,CAAC,IAAI,CAAC,EAAE,eAAe,EAAE,YAAY,EAAE,EAAE,wBAAwB,CAAC,CAAC;IACxE,CAAC;IAED;;;;;;;;OAQG;IACH,gBAAgB;QACd,MAAM,UAAU,GAAG,aAAa,EAAE,CAAC;QACnC,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,GAAG,UAAU,CAAC,WAAW,CAAC;IACrD,CAAC;IAED;;;;;OAKG;IACH,kBAAkB,CAAC,QAAgC;QACjD,IAAI,CAAC,eAAe,GAAG,QAAQ,CAAC;QAChC,GAAG,CAAC,KAAK,CAAC,qCAAqC,CAAC,CAAC;IACnD,CAAC;IAED;;OAEG;IACK,KAAK,CAAC,aAAa,CAAC,KAAa;QACvC,IAAI,IAAI,CAAC,eAAe,EAAE,CAAC;YACzB,IAAI,CAAC;gBACH,MAAM,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;YACpC,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,GAAG,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,WAAW,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,2BAA2B,CAAC,CAAC;YACtF,CAAC;QACH,CAAC;IACH,CAAC;CACF;AAED,0BAA0B;AAC1B,MAAM,UAAU,eAAe;IAC7B,OAAO,YAAY,CAAC,WAAW,EAAE,CAAC;AACpC,CAAC;AAED,oCAAoC;AACpC,OAAO,EAAE,YAAY,EAAE,CAAC"}