@nestr/mcp 0.1.52 → 0.1.54
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/http.js +124 -55
- package/build/http.js.map +1 -1
- package/build/oauth/file-store.d.ts +14 -0
- package/build/oauth/file-store.d.ts.map +1 -0
- package/build/oauth/file-store.js +366 -0
- package/build/oauth/file-store.js.map +1 -0
- package/build/oauth/flow.d.ts +13 -13
- package/build/oauth/flow.d.ts.map +1 -1
- package/build/oauth/flow.js +21 -19
- package/build/oauth/flow.js.map +1 -1
- package/build/oauth/redis-store.d.ts +17 -0
- package/build/oauth/redis-store.d.ts.map +1 -0
- package/build/oauth/redis-store.js +174 -0
- package/build/oauth/redis-store.js.map +1 -0
- package/build/oauth/storage.d.ts +28 -103
- package/build/oauth/storage.d.ts.map +1 -1
- package/build/oauth/storage.js +49 -478
- package/build/oauth/storage.js.map +1 -1
- package/build/oauth/store.d.ts +80 -0
- package/build/oauth/store.d.ts.map +1 -0
- package/build/oauth/store.js +37 -0
- package/build/oauth/store.js.map +1 -0
- package/package.json +2 -1
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Redis-backed OAuthStore Implementation
|
|
3
|
+
*
|
|
4
|
+
* Uses Redis for shared state across multiple pods.
|
|
5
|
+
* Activated when REDIS_URL environment variable is set.
|
|
6
|
+
*
|
|
7
|
+
* Features:
|
|
8
|
+
* - Native TTL for automatic expiry (no cleanup timers needed)
|
|
9
|
+
* - Atomic GETDEL for consume-once operations (pending auth, PKCE)
|
|
10
|
+
* - Optional AES-256-GCM encryption for session values (OAUTH_ENCRYPTION_KEY)
|
|
11
|
+
*/
|
|
12
|
+
import { Redis } from "ioredis";
|
|
13
|
+
import { randomBytes, createCipheriv, createDecipheriv } from "node:crypto";
|
|
14
|
+
// Key prefixes
|
|
15
|
+
const PREFIX = {
|
|
16
|
+
client: "oauth:client:",
|
|
17
|
+
clientCount: "oauth:client:count",
|
|
18
|
+
pending: "oauth:pending:",
|
|
19
|
+
pkce: "oauth:pkce:",
|
|
20
|
+
session: "oauth:session:",
|
|
21
|
+
};
|
|
22
|
+
// TTLs in seconds
|
|
23
|
+
const PENDING_AUTH_TTL = 300; // 5 minutes
|
|
24
|
+
const PKCE_TTL = 300; // 5 minutes
|
|
25
|
+
const CLIENT_TTL = 86400; // 24 hours (clients re-register on reconnect)
|
|
26
|
+
const SESSION_REFRESH_TTL = 30 * 86400; // 30 days for sessions with refresh tokens
|
|
27
|
+
// Encryption constants
|
|
28
|
+
const ALGORITHM = "aes-256-gcm";
|
|
29
|
+
const IV_LENGTH = 16;
|
|
30
|
+
function getEncryptionKey() {
|
|
31
|
+
if (!process.env.OAUTH_ENCRYPTION_KEY)
|
|
32
|
+
return null;
|
|
33
|
+
const key = Buffer.from(process.env.OAUTH_ENCRYPTION_KEY, "base64");
|
|
34
|
+
if (key.length !== 32) {
|
|
35
|
+
throw new Error("OAUTH_ENCRYPTION_KEY must be 32 bytes (256 bits) base64-encoded");
|
|
36
|
+
}
|
|
37
|
+
return key;
|
|
38
|
+
}
|
|
39
|
+
function encrypt(data, key) {
|
|
40
|
+
const iv = randomBytes(IV_LENGTH);
|
|
41
|
+
const cipher = createCipheriv(ALGORITHM, key, iv);
|
|
42
|
+
let encrypted = cipher.update(data, "utf8", "base64");
|
|
43
|
+
encrypted += cipher.final("base64");
|
|
44
|
+
const authTag = cipher.getAuthTag();
|
|
45
|
+
return `${iv.toString("base64")}:${authTag.toString("base64")}:${encrypted}`;
|
|
46
|
+
}
|
|
47
|
+
function decrypt(encryptedData, key) {
|
|
48
|
+
const parts = encryptedData.split(":");
|
|
49
|
+
if (parts.length !== 3)
|
|
50
|
+
throw new Error("Invalid encrypted data format");
|
|
51
|
+
const iv = Buffer.from(parts[0], "base64");
|
|
52
|
+
const authTag = Buffer.from(parts[1], "base64");
|
|
53
|
+
const data = parts[2];
|
|
54
|
+
const decipher = createDecipheriv(ALGORITHM, key, iv);
|
|
55
|
+
decipher.setAuthTag(authTag);
|
|
56
|
+
let decrypted = decipher.update(data, "base64", "utf8");
|
|
57
|
+
decrypted += decipher.final("utf8");
|
|
58
|
+
return decrypted;
|
|
59
|
+
}
|
|
60
|
+
class RedisStore {
|
|
61
|
+
redis;
|
|
62
|
+
encryptionKey;
|
|
63
|
+
constructor(redis) {
|
|
64
|
+
this.redis = redis;
|
|
65
|
+
this.encryptionKey = getEncryptionKey();
|
|
66
|
+
}
|
|
67
|
+
// ---- Helpers ----
|
|
68
|
+
serialize(data) {
|
|
69
|
+
const json = JSON.stringify(data);
|
|
70
|
+
if (this.encryptionKey)
|
|
71
|
+
return encrypt(json, this.encryptionKey);
|
|
72
|
+
return json;
|
|
73
|
+
}
|
|
74
|
+
deserialize(raw) {
|
|
75
|
+
if (this.encryptionKey) {
|
|
76
|
+
const json = decrypt(raw, this.encryptionKey);
|
|
77
|
+
return JSON.parse(json);
|
|
78
|
+
}
|
|
79
|
+
return JSON.parse(raw);
|
|
80
|
+
}
|
|
81
|
+
// ---- Clients ----
|
|
82
|
+
async registerClient(client) {
|
|
83
|
+
const key = PREFIX.client + client.client_id;
|
|
84
|
+
// Only increment the counter for genuinely new clients (SET NX returns 1 if key didn't exist).
|
|
85
|
+
// Without this, the counter drifts upward as clients re-register and eventually blocks
|
|
86
|
+
// all registrations when it hits MAX_REGISTERED_CLIENTS.
|
|
87
|
+
const isNew = await this.redis.set(key, this.serialize(client), "EX", CLIENT_TTL, "GET");
|
|
88
|
+
if (isNew === null) {
|
|
89
|
+
await this.redis.incr(PREFIX.clientCount);
|
|
90
|
+
}
|
|
91
|
+
console.log(`Registered OAuth client: ${client.client_id}`);
|
|
92
|
+
}
|
|
93
|
+
async getClient(clientId) {
|
|
94
|
+
const raw = await this.redis.get(PREFIX.client + clientId);
|
|
95
|
+
if (!raw)
|
|
96
|
+
return undefined;
|
|
97
|
+
return this.deserialize(raw);
|
|
98
|
+
}
|
|
99
|
+
async getClientCount() {
|
|
100
|
+
const count = await this.redis.get(PREFIX.clientCount);
|
|
101
|
+
return count ? parseInt(count, 10) : 0;
|
|
102
|
+
}
|
|
103
|
+
async clientExists(clientId) {
|
|
104
|
+
return (await this.redis.exists(PREFIX.client + clientId)) === 1;
|
|
105
|
+
}
|
|
106
|
+
// ---- Pending Auth ----
|
|
107
|
+
async storePendingAuth(pending) {
|
|
108
|
+
await this.redis.set(PREFIX.pending + pending.state, this.serialize(pending), "EX", PENDING_AUTH_TTL);
|
|
109
|
+
}
|
|
110
|
+
async consumePendingAuth(state) {
|
|
111
|
+
const raw = await this.redis.getdel(PREFIX.pending + state);
|
|
112
|
+
if (!raw)
|
|
113
|
+
return undefined;
|
|
114
|
+
return this.deserialize(raw);
|
|
115
|
+
}
|
|
116
|
+
// ---- PKCE Codes ----
|
|
117
|
+
async storePkceForCode(code, codeChallenge, codeChallengeMethod) {
|
|
118
|
+
const data = { codeChallenge, codeChallengeMethod, createdAt: Date.now() };
|
|
119
|
+
await this.redis.set(PREFIX.pkce + code, this.serialize(data), "EX", PKCE_TTL);
|
|
120
|
+
}
|
|
121
|
+
async consumePkceForCode(code) {
|
|
122
|
+
const raw = await this.redis.getdel(PREFIX.pkce + code);
|
|
123
|
+
if (!raw)
|
|
124
|
+
return undefined;
|
|
125
|
+
return this.deserialize(raw);
|
|
126
|
+
}
|
|
127
|
+
// ---- Sessions ----
|
|
128
|
+
sessionTtl(session) {
|
|
129
|
+
if (session.refreshToken)
|
|
130
|
+
return SESSION_REFRESH_TTL;
|
|
131
|
+
// TTL = time until expiry (minimum 60s to avoid immediate deletion)
|
|
132
|
+
const ttl = Math.max(60, Math.ceil((session.expiresAt - Date.now()) / 1000));
|
|
133
|
+
return ttl;
|
|
134
|
+
}
|
|
135
|
+
async storeSession(sessionId, session) {
|
|
136
|
+
await this.redis.set(PREFIX.session + sessionId, this.serialize(session), "EX", this.sessionTtl(session));
|
|
137
|
+
}
|
|
138
|
+
async getSession(sessionId) {
|
|
139
|
+
const raw = await this.redis.get(PREFIX.session + sessionId);
|
|
140
|
+
if (!raw)
|
|
141
|
+
return undefined;
|
|
142
|
+
return this.deserialize(raw);
|
|
143
|
+
}
|
|
144
|
+
async updateSession(sessionId, session) {
|
|
145
|
+
// Unconditional SET — the EXISTS + SET pattern has a TOCTOU race across pods.
|
|
146
|
+
// If the session was deleted between the two calls, this would silently re-create it.
|
|
147
|
+
// Matching FileStore behavior: just overwrite.
|
|
148
|
+
await this.redis.set(PREFIX.session + sessionId, this.serialize(session), "EX", this.sessionTtl(session));
|
|
149
|
+
}
|
|
150
|
+
async removeSession(sessionId) {
|
|
151
|
+
await this.redis.del(PREFIX.session + sessionId);
|
|
152
|
+
}
|
|
153
|
+
// ---- Lifecycle ----
|
|
154
|
+
async close() {
|
|
155
|
+
await this.redis.quit();
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Create a Redis-backed OAuthStore instance.
|
|
160
|
+
*/
|
|
161
|
+
export async function createRedisStore(redisUrl) {
|
|
162
|
+
const redis = new Redis(redisUrl, {
|
|
163
|
+
maxRetriesPerRequest: 3,
|
|
164
|
+
retryStrategy(times) {
|
|
165
|
+
// Exponential backoff: 50ms, 100ms, 200ms, ... capped at 2s
|
|
166
|
+
return Math.min(times * 50, 2000);
|
|
167
|
+
},
|
|
168
|
+
});
|
|
169
|
+
// Verify connection
|
|
170
|
+
await redis.ping();
|
|
171
|
+
console.log("Redis connected for OAuth storage");
|
|
172
|
+
return new RedisStore(redis);
|
|
173
|
+
}
|
|
174
|
+
//# sourceMappingURL=redis-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redis-store.js","sourceRoot":"","sources":["../../src/oauth/redis-store.ts"],"names":[],"mappings":"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"}
|
package/build/oauth/storage.d.ts
CHANGED
|
@@ -1,111 +1,36 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Backward-compatibility re-exports from the OAuthStore abstraction.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
* Registered OAuth Client (RFC 7591)
|
|
10
|
-
*/
|
|
11
|
-
export interface RegisteredClient {
|
|
12
|
-
client_id: string;
|
|
13
|
-
client_secret?: string;
|
|
14
|
-
client_name?: string;
|
|
15
|
-
redirect_uris: string[];
|
|
16
|
-
grant_types: string[];
|
|
17
|
-
response_types: string[];
|
|
18
|
-
token_endpoint_auth_method: string;
|
|
19
|
-
scope?: string;
|
|
20
|
-
registered_at: number;
|
|
21
|
-
}
|
|
22
|
-
/**
|
|
23
|
-
* Pending OAuth authorization with PKCE
|
|
24
|
-
*/
|
|
25
|
-
export interface PendingAuthWithPKCE {
|
|
26
|
-
state: string;
|
|
27
|
-
redirectUri: string;
|
|
28
|
-
clientId: string;
|
|
29
|
-
codeChallenge?: string;
|
|
30
|
-
codeChallengeMethod?: string;
|
|
31
|
-
createdAt: number;
|
|
32
|
-
scope?: string;
|
|
33
|
-
/** Identifier for the MCP client (e.g., "claude-code", "cursor") for token metadata */
|
|
34
|
-
clientConsumer?: string;
|
|
35
|
-
/** GA4 client_id for cross-domain analytics tracking */
|
|
36
|
-
gaClientId?: string;
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* Stored OAuth session after successful authentication
|
|
40
|
-
*/
|
|
41
|
-
export interface StoredOAuthSession {
|
|
42
|
-
accessToken: string;
|
|
43
|
-
refreshToken?: string;
|
|
44
|
-
expiresAt: number;
|
|
45
|
-
scope?: string;
|
|
46
|
-
/** Nestr user ID for analytics (GA4 user_id) */
|
|
47
|
-
userId?: string;
|
|
48
|
-
}
|
|
49
|
-
/**
|
|
50
|
-
* Register a new OAuth client
|
|
51
|
-
*/
|
|
52
|
-
export declare function registerClient(client: RegisteredClient): void;
|
|
53
|
-
/**
|
|
54
|
-
* Get a registered client by ID
|
|
55
|
-
*/
|
|
56
|
-
export declare function getClient(clientId: string): RegisteredClient | undefined;
|
|
57
|
-
/**
|
|
58
|
-
* Check if a client ID exists
|
|
59
|
-
*/
|
|
60
|
-
export declare function clientExists(clientId: string): boolean;
|
|
61
|
-
/**
|
|
62
|
-
* Validate client credentials
|
|
63
|
-
*/
|
|
64
|
-
export declare function validateClientCredentials(clientId: string, clientSecret?: string): boolean;
|
|
65
|
-
/**
|
|
66
|
-
* Validate redirect URI for a client
|
|
67
|
-
*/
|
|
68
|
-
export declare function validateRedirectUri(clientId: string, redirectUri: string): boolean;
|
|
69
|
-
/**
|
|
70
|
-
* Store a pending auth request
|
|
71
|
-
*/
|
|
72
|
-
export declare function storePendingAuth(pending: PendingAuthWithPKCE): void;
|
|
73
|
-
/**
|
|
74
|
-
* Get and remove a pending auth request
|
|
75
|
-
*/
|
|
76
|
-
export declare function consumePendingAuth(state: string): PendingAuthWithPKCE | undefined;
|
|
77
|
-
/**
|
|
78
|
-
* Cleanup expired pending auth requests
|
|
79
|
-
*/
|
|
80
|
-
export declare function cleanupExpiredPendingAuth(): void;
|
|
81
|
-
interface PkceForCodeData {
|
|
82
|
-
codeChallenge: string;
|
|
83
|
-
codeChallengeMethod: string;
|
|
84
|
-
createdAt: number;
|
|
85
|
-
}
|
|
86
|
-
export declare function storePkceForCode(code: string, codeChallenge: string, codeChallengeMethod: string): void;
|
|
87
|
-
export declare function consumePkceForCode(code: string): PkceForCodeData | undefined;
|
|
88
|
-
/**
|
|
89
|
-
* Store an OAuth session
|
|
90
|
-
*/
|
|
91
|
-
export declare function storeSession(sessionId: string, session: StoredOAuthSession): void;
|
|
92
|
-
/**
|
|
93
|
-
* Get an OAuth session by ID
|
|
94
|
-
*/
|
|
95
|
-
export declare function getSession(sessionId: string): StoredOAuthSession | undefined;
|
|
96
|
-
/**
|
|
97
|
-
* Update an existing OAuth session (e.g., after token refresh)
|
|
4
|
+
* All types and the store singleton are canonical in store.ts.
|
|
5
|
+
* This file provides synchronous-looking wrappers that delegate to the
|
|
6
|
+
* initialized store for callers that haven't migrated yet.
|
|
7
|
+
*
|
|
8
|
+
* TODO: Remove this file once all callers import from store.ts directly.
|
|
98
9
|
*/
|
|
99
|
-
|
|
10
|
+
import { getStore } from "./store.js";
|
|
11
|
+
export type { RegisteredClient, PendingAuthWithPKCE, StoredOAuthSession, PkceForCodeData, } from "./store.js";
|
|
100
12
|
/**
|
|
101
|
-
*
|
|
13
|
+
* Constant-time string comparison to prevent timing attacks on secrets.
|
|
14
|
+
* Standalone utility — not part of the store interface.
|
|
102
15
|
*/
|
|
103
|
-
export declare function
|
|
16
|
+
export declare function constantTimeCompare(a: string, b: string): boolean;
|
|
104
17
|
/**
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
* and they have no refresh token
|
|
18
|
+
* Validate redirect URI against a registered client's allowed URIs.
|
|
19
|
+
* Accepts the client object directly to avoid an extra async lookup.
|
|
108
20
|
*/
|
|
109
|
-
export declare function
|
|
110
|
-
|
|
21
|
+
export declare function validateRedirectUri(client: {
|
|
22
|
+
redirect_uris: string[];
|
|
23
|
+
}, redirectUri: string): boolean;
|
|
24
|
+
export declare function registerClient(...args: Parameters<ReturnType<typeof getStore>["registerClient"]>): Promise<void>;
|
|
25
|
+
export declare function getClient(...args: Parameters<ReturnType<typeof getStore>["getClient"]>): Promise<import("./store.js").RegisteredClient | undefined>;
|
|
26
|
+
export declare function getClientCount(): Promise<number>;
|
|
27
|
+
export declare function clientExists(...args: Parameters<ReturnType<typeof getStore>["clientExists"]>): Promise<boolean>;
|
|
28
|
+
export declare function storePendingAuth(...args: Parameters<ReturnType<typeof getStore>["storePendingAuth"]>): Promise<void>;
|
|
29
|
+
export declare function consumePendingAuth(...args: Parameters<ReturnType<typeof getStore>["consumePendingAuth"]>): Promise<import("./store.js").PendingAuthWithPKCE | undefined>;
|
|
30
|
+
export declare function storePkceForCode(...args: Parameters<ReturnType<typeof getStore>["storePkceForCode"]>): Promise<void>;
|
|
31
|
+
export declare function consumePkceForCode(...args: Parameters<ReturnType<typeof getStore>["consumePkceForCode"]>): Promise<import("./store.js").PkceForCodeData | undefined>;
|
|
32
|
+
export declare function storeSession(...args: Parameters<ReturnType<typeof getStore>["storeSession"]>): Promise<void>;
|
|
33
|
+
export declare function getSession(...args: Parameters<ReturnType<typeof getStore>["getSession"]>): Promise<import("./store.js").StoredOAuthSession | undefined>;
|
|
34
|
+
export declare function updateSession(...args: Parameters<ReturnType<typeof getStore>["updateSession"]>): Promise<void>;
|
|
35
|
+
export declare function removeSession(...args: Parameters<ReturnType<typeof getStore>["removeSession"]>): Promise<void>;
|
|
111
36
|
//# sourceMappingURL=storage.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../src/oauth/storage.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../src/oauth/storage.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAGtC,YAAY,EACV,gBAAgB,EAChB,mBAAmB,EACnB,kBAAkB,EAClB,eAAe,GAChB,MAAM,YAAY,CAAC;AAEpB;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAKjE;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE;IAAE,aAAa,EAAE,MAAM,EAAE,CAAA;CAAE,EACnC,WAAW,EAAE,MAAM,GAClB,OAAO,CAwBT;AAKD,wBAAsB,cAAc,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,UAAU,CAAC,OAAO,QAAQ,CAAC,CAAC,gBAAgB,CAAC,CAAC,iBAEtG;AAED,wBAAsB,SAAS,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,UAAU,CAAC,OAAO,QAAQ,CAAC,CAAC,WAAW,CAAC,CAAC,8DAE5F;AAED,wBAAsB,cAAc,oBAEnC;AAED,wBAAsB,YAAY,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,UAAU,CAAC,OAAO,QAAQ,CAAC,CAAC,cAAc,CAAC,CAAC,oBAElG;AAED,wBAAsB,gBAAgB,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,UAAU,CAAC,OAAO,QAAQ,CAAC,CAAC,kBAAkB,CAAC,CAAC,iBAE1G;AAED,wBAAsB,kBAAkB,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,UAAU,CAAC,OAAO,QAAQ,CAAC,CAAC,oBAAoB,CAAC,CAAC,iEAE9G;AAED,wBAAsB,gBAAgB,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,UAAU,CAAC,OAAO,QAAQ,CAAC,CAAC,kBAAkB,CAAC,CAAC,iBAE1G;AAED,wBAAsB,kBAAkB,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,UAAU,CAAC,OAAO,QAAQ,CAAC,CAAC,oBAAoB,CAAC,CAAC,6DAE9G;AAED,wBAAsB,YAAY,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,UAAU,CAAC,OAAO,QAAQ,CAAC,CAAC,cAAc,CAAC,CAAC,iBAElG;AAED,wBAAsB,UAAU,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,UAAU,CAAC,OAAO,QAAQ,CAAC,CAAC,YAAY,CAAC,CAAC,gEAE9F;AAED,wBAAsB,aAAa,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,UAAU,CAAC,OAAO,QAAQ,CAAC,CAAC,eAAe,CAAC,CAAC,iBAEpG;AAED,wBAAsB,aAAa,CAAC,GAAG,IAAI,EAAE,UAAU,CAAC,UAAU,CAAC,OAAO,QAAQ,CAAC,CAAC,eAAe,CAAC,CAAC,iBAEpG"}
|