fastmcp 4.12.5 → 4.12.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/FastMCP.cjs +2 -2
- package/dist/FastMCP.d.cts +2 -2
- package/dist/FastMCP.d.ts +2 -2
- package/dist/FastMCP.js +1 -1
- package/dist/{OAuthProvider-B_E71LUD.d.cts → OAuthProvider-B_OJFNC0.d.cts} +25 -5
- package/dist/{OAuthProvider-B_E71LUD.d.ts → OAuthProvider-B_OJFNC0.d.ts} +25 -5
- package/dist/auth/index.cjs +2 -2
- package/dist/auth/index.d.cts +2 -2
- package/dist/auth/index.d.ts +2 -2
- package/dist/auth/index.js +1 -1
- package/dist/{chunk-ENMHHQJF.cjs → chunk-6DTYLKSC.cjs} +97 -41
- package/dist/chunk-6DTYLKSC.cjs.map +1 -0
- package/dist/{chunk-2ZFQSPXZ.js → chunk-VFBUPSNI.js} +98 -42
- package/dist/chunk-VFBUPSNI.js.map +1 -0
- package/dist/examples/custom-routes.cjs +1 -1
- package/dist/examples/custom-routes.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-2ZFQSPXZ.js.map +0 -1
- package/dist/chunk-ENMHHQJF.cjs.map +0 -1
package/README.md
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
A TypeScript framework for building [MCP](https://glama.ai/mcp) servers capable of handling client sessions.
|
|
4
4
|
|
|
5
|
-
> [!
|
|
5
|
+
> [!IMPORTANT]
|
|
6
6
|
>
|
|
7
|
-
> For a
|
|
7
|
+
> FastMCP implements the legacy, handshake-based MCP revisions (`2025-11-25` and earlier). It does not support the current specification, [`2026-07-28`](https://modelcontextprotocol.io/specification/2026-07-28/), which made the protocol stateless — no `initialize` handshake and no `Mcp-Session-Id`. For a framework targeting the current spec, use [ViteMCP](https://github.com/vitemcp/server).
|
|
8
8
|
|
|
9
9
|
## Features
|
|
10
10
|
|
package/dist/FastMCP.cjs
CHANGED
|
@@ -24,7 +24,7 @@ var _chunkU36NARZGcjs = require('./chunk-U36NARZG.cjs');
|
|
|
24
24
|
|
|
25
25
|
|
|
26
26
|
|
|
27
|
-
var
|
|
27
|
+
var _chunk6DTYLKSCcjs = require('./chunk-6DTYLKSC.cjs');
|
|
28
28
|
|
|
29
29
|
|
|
30
30
|
|
|
@@ -49,5 +49,5 @@ var _chunkENMHHQJFcjs = require('./chunk-ENMHHQJF.cjs');
|
|
|
49
49
|
|
|
50
50
|
|
|
51
51
|
|
|
52
|
-
exports.AuthProvider =
|
|
52
|
+
exports.AuthProvider = _chunk6DTYLKSCcjs.AuthProvider; exports.AzureProvider = _chunk6DTYLKSCcjs.AzureProvider; exports.DiscoveryDocumentCache = _chunkU36NARZGcjs.DiscoveryDocumentCache; exports.FastMCP = _chunkU36NARZGcjs.FastMCP; exports.FastMCPError = _chunkU36NARZGcjs.FastMCPError; exports.FastMCPSession = _chunkU36NARZGcjs.FastMCPSession; exports.GitHubProvider = _chunk6DTYLKSCcjs.GitHubProvider; exports.GoogleProvider = _chunk6DTYLKSCcjs.GoogleProvider; exports.MEDIA_FETCH_TIMEOUT_MS = _chunkU36NARZGcjs.MEDIA_FETCH_TIMEOUT_MS; exports.OAuthProvider = _chunk6DTYLKSCcjs.OAuthProvider; exports.ServerState = _chunkU36NARZGcjs.ServerState; exports.SessionError = _chunkU36NARZGcjs.SessionError; exports.UnexpectedStateError = _chunkU36NARZGcjs.UnexpectedStateError; exports.UserError = _chunkU36NARZGcjs.UserError; exports.audioContent = _chunkU36NARZGcjs.audioContent; exports.getAuthSession = _chunk6DTYLKSCcjs.getAuthSession; exports.imageContent = _chunkU36NARZGcjs.imageContent; exports.jsonSchemaAdapter = _chunkU36NARZGcjs.jsonSchemaAdapter; exports.requireAll = _chunk6DTYLKSCcjs.requireAll; exports.requireAny = _chunk6DTYLKSCcjs.requireAny; exports.requireAuth = _chunk6DTYLKSCcjs.requireAuth; exports.requireRole = _chunk6DTYLKSCcjs.requireRole; exports.requireScopes = _chunk6DTYLKSCcjs.requireScopes;
|
|
53
53
|
//# sourceMappingURL=FastMCP.cjs.map
|
package/dist/FastMCP.d.cts
CHANGED
|
@@ -12,8 +12,8 @@ import { CorsOptions } from 'mcp-proxy';
|
|
|
12
12
|
export { CorsOptions } from 'mcp-proxy';
|
|
13
13
|
import { StrictEventEmitter } from 'strict-event-emitter-types';
|
|
14
14
|
import { z } from 'zod';
|
|
15
|
-
import { A as AuthProvider, O as OAuthSession, a as OAuthProxy } from './OAuthProvider-
|
|
16
|
-
export { j as AuthProviderConfig, b as AzureProvider, k as AzureProviderConfig, l as AzureSession, m as GenericOAuthProviderConfig, G as GitHubProvider, n as GitHubSession, c as GoogleProvider, o as GoogleSession, d as OAuthProvider, g as getAuthSession, r as requireAll, e as requireAny, f as requireAuth, h as requireRole, i as requireScopes } from './OAuthProvider-
|
|
15
|
+
import { A as AuthProvider, O as OAuthSession, a as OAuthProxy } from './OAuthProvider-B_OJFNC0.cjs';
|
|
16
|
+
export { j as AuthProviderConfig, b as AzureProvider, k as AzureProviderConfig, l as AzureSession, m as GenericOAuthProviderConfig, G as GitHubProvider, n as GitHubSession, c as GoogleProvider, o as GoogleSession, d as OAuthProvider, g as getAuthSession, r as requireAll, e as requireAny, f as requireAuth, h as requireRole, i as requireScopes } from './OAuthProvider-B_OJFNC0.cjs';
|
|
17
17
|
import 'node:http';
|
|
18
18
|
|
|
19
19
|
declare class DiscoveryDocumentCache {
|
package/dist/FastMCP.d.ts
CHANGED
|
@@ -12,8 +12,8 @@ import { CorsOptions } from 'mcp-proxy';
|
|
|
12
12
|
export { CorsOptions } from 'mcp-proxy';
|
|
13
13
|
import { StrictEventEmitter } from 'strict-event-emitter-types';
|
|
14
14
|
import { z } from 'zod';
|
|
15
|
-
import { A as AuthProvider, O as OAuthSession, a as OAuthProxy } from './OAuthProvider-
|
|
16
|
-
export { j as AuthProviderConfig, b as AzureProvider, k as AzureProviderConfig, l as AzureSession, m as GenericOAuthProviderConfig, G as GitHubProvider, n as GitHubSession, c as GoogleProvider, o as GoogleSession, d as OAuthProvider, g as getAuthSession, r as requireAll, e as requireAny, f as requireAuth, h as requireRole, i as requireScopes } from './OAuthProvider-
|
|
15
|
+
import { A as AuthProvider, O as OAuthSession, a as OAuthProxy } from './OAuthProvider-B_OJFNC0.js';
|
|
16
|
+
export { j as AuthProviderConfig, b as AzureProvider, k as AzureProviderConfig, l as AzureSession, m as GenericOAuthProviderConfig, G as GitHubProvider, n as GitHubSession, c as GoogleProvider, o as GoogleSession, d as OAuthProvider, g as getAuthSession, r as requireAll, e as requireAny, f as requireAuth, h as requireRole, i as requireScopes } from './OAuthProvider-B_OJFNC0.js';
|
|
17
17
|
import 'node:http';
|
|
18
18
|
|
|
19
19
|
declare class DiscoveryDocumentCache {
|
package/dist/FastMCP.js
CHANGED
|
@@ -388,11 +388,14 @@ interface TokenStorage {
|
|
|
388
388
|
* Atomically retrieve a value and delete it, returning `null` if the key was
|
|
389
389
|
* absent. At most one caller may observe a given value.
|
|
390
390
|
*
|
|
391
|
-
* Optional, but **required for correctness
|
|
392
|
-
*
|
|
393
|
-
*
|
|
394
|
-
*
|
|
395
|
-
*
|
|
391
|
+
* Optional, but **required for correctness whenever concurrent requests can
|
|
392
|
+
* reach the same record** — which includes a single process, since the check
|
|
393
|
+
* and the delete straddle an await. The OAuth proxy consumes authorization
|
|
394
|
+
* codes, transactions and refresh-token mappings through it, and single-use
|
|
395
|
+
* enforcement depends on the atomicity. Without it the proxy falls back to a
|
|
396
|
+
* non-atomic get + delete, where two concurrent requests can both redeem the
|
|
397
|
+
* same authorization code, or both redeem the same refresh token and walk
|
|
398
|
+
* away with two independent token chains.
|
|
396
399
|
*
|
|
397
400
|
* Most backends expose a suitable primitive: Redis `GETDEL`, DynamoDB
|
|
398
401
|
* `DeleteItem` with `ReturnValues: "ALL_OLD"`, or SQL
|
|
@@ -604,10 +607,27 @@ declare class OAuthProxy {
|
|
|
604
607
|
* Refresh upstream tokens with provider
|
|
605
608
|
*/
|
|
606
609
|
private refreshUpstreamTokens;
|
|
610
|
+
/**
|
|
611
|
+
* Put a claimed refresh-token mapping back after a rotation failed, keeping
|
|
612
|
+
* whatever lifetime it had left.
|
|
613
|
+
*
|
|
614
|
+
* A mapping that is already expired, or that carries no usable expiry, is
|
|
615
|
+
* dropped instead. Inventing a TTL here would extend the lifetime of a
|
|
616
|
+
* credential in a security path, and every mapping this proxy writes records
|
|
617
|
+
* `expiresAt`.
|
|
618
|
+
*/
|
|
619
|
+
private restoreMapping;
|
|
607
620
|
/**
|
|
608
621
|
* Start periodic cleanup of expired transactions and codes
|
|
609
622
|
*/
|
|
610
623
|
private startCleanup;
|
|
624
|
+
/**
|
|
625
|
+
* Atomically claim a token mapping, mirroring `OAuthProxyStateStore`: at most
|
|
626
|
+
* one caller — across all processes sharing the storage — can receive a given
|
|
627
|
+
* mapping, which is what makes single use enforceable. Falls back to a
|
|
628
|
+
* non-atomic get + delete for storages that do not implement `take`.
|
|
629
|
+
*/
|
|
630
|
+
private takeMapping;
|
|
611
631
|
/**
|
|
612
632
|
* Validate a redirect URI against the configured allow-list.
|
|
613
633
|
*
|
|
@@ -388,11 +388,14 @@ interface TokenStorage {
|
|
|
388
388
|
* Atomically retrieve a value and delete it, returning `null` if the key was
|
|
389
389
|
* absent. At most one caller may observe a given value.
|
|
390
390
|
*
|
|
391
|
-
* Optional, but **required for correctness
|
|
392
|
-
*
|
|
393
|
-
*
|
|
394
|
-
*
|
|
395
|
-
*
|
|
391
|
+
* Optional, but **required for correctness whenever concurrent requests can
|
|
392
|
+
* reach the same record** — which includes a single process, since the check
|
|
393
|
+
* and the delete straddle an await. The OAuth proxy consumes authorization
|
|
394
|
+
* codes, transactions and refresh-token mappings through it, and single-use
|
|
395
|
+
* enforcement depends on the atomicity. Without it the proxy falls back to a
|
|
396
|
+
* non-atomic get + delete, where two concurrent requests can both redeem the
|
|
397
|
+
* same authorization code, or both redeem the same refresh token and walk
|
|
398
|
+
* away with two independent token chains.
|
|
396
399
|
*
|
|
397
400
|
* Most backends expose a suitable primitive: Redis `GETDEL`, DynamoDB
|
|
398
401
|
* `DeleteItem` with `ReturnValues: "ALL_OLD"`, or SQL
|
|
@@ -604,10 +607,27 @@ declare class OAuthProxy {
|
|
|
604
607
|
* Refresh upstream tokens with provider
|
|
605
608
|
*/
|
|
606
609
|
private refreshUpstreamTokens;
|
|
610
|
+
/**
|
|
611
|
+
* Put a claimed refresh-token mapping back after a rotation failed, keeping
|
|
612
|
+
* whatever lifetime it had left.
|
|
613
|
+
*
|
|
614
|
+
* A mapping that is already expired, or that carries no usable expiry, is
|
|
615
|
+
* dropped instead. Inventing a TTL here would extend the lifetime of a
|
|
616
|
+
* credential in a security path, and every mapping this proxy writes records
|
|
617
|
+
* `expiresAt`.
|
|
618
|
+
*/
|
|
619
|
+
private restoreMapping;
|
|
607
620
|
/**
|
|
608
621
|
* Start periodic cleanup of expired transactions and codes
|
|
609
622
|
*/
|
|
610
623
|
private startCleanup;
|
|
624
|
+
/**
|
|
625
|
+
* Atomically claim a token mapping, mirroring `OAuthProxyStateStore`: at most
|
|
626
|
+
* one caller — across all processes sharing the storage — can receive a given
|
|
627
|
+
* mapping, which is what makes single use enforceable. Falls back to a
|
|
628
|
+
* non-atomic get + delete for storages that do not implement `take`.
|
|
629
|
+
*/
|
|
630
|
+
private takeMapping;
|
|
611
631
|
/**
|
|
612
632
|
* Validate a redirect URI against the configured allow-list.
|
|
613
633
|
*
|
package/dist/auth/index.cjs
CHANGED
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
|
|
25
25
|
|
|
26
26
|
|
|
27
|
-
var
|
|
27
|
+
var _chunk6DTYLKSCcjs = require('../chunk-6DTYLKSC.cjs');
|
|
28
28
|
|
|
29
29
|
|
|
30
30
|
|
|
@@ -51,5 +51,5 @@ var _chunkENMHHQJFcjs = require('../chunk-ENMHHQJF.cjs');
|
|
|
51
51
|
|
|
52
52
|
|
|
53
53
|
|
|
54
|
-
exports.AuthProvider =
|
|
54
|
+
exports.AuthProvider = _chunk6DTYLKSCcjs.AuthProvider; exports.AzureProvider = _chunk6DTYLKSCcjs.AzureProvider; exports.ConsentManager = _chunk6DTYLKSCcjs.ConsentManager; exports.DEFAULT_ACCESS_TOKEN_TTL = _chunk6DTYLKSCcjs.DEFAULT_ACCESS_TOKEN_TTL; exports.DEFAULT_ACCESS_TOKEN_TTL_NO_REFRESH = _chunk6DTYLKSCcjs.DEFAULT_ACCESS_TOKEN_TTL_NO_REFRESH; exports.DEFAULT_AUTHORIZATION_CODE_TTL = _chunk6DTYLKSCcjs.DEFAULT_AUTHORIZATION_CODE_TTL; exports.DEFAULT_REFRESH_TOKEN_TTL = _chunk6DTYLKSCcjs.DEFAULT_REFRESH_TOKEN_TTL; exports.DEFAULT_TRANSACTION_TTL = _chunk6DTYLKSCcjs.DEFAULT_TRANSACTION_TTL; exports.DiskStore = _chunk6DTYLKSCcjs.DiskStore; exports.EncryptedTokenStorage = _chunk6DTYLKSCcjs.EncryptedTokenStorage; exports.GitHubProvider = _chunk6DTYLKSCcjs.GitHubProvider; exports.GoogleProvider = _chunk6DTYLKSCcjs.GoogleProvider; exports.JWKSVerifier = _chunk6DTYLKSCcjs.JWKSVerifier; exports.JWTIssuer = _chunk6DTYLKSCcjs.JWTIssuer; exports.MemoryTokenStorage = _chunk6DTYLKSCcjs.MemoryTokenStorage; exports.OAuthProvider = _chunk6DTYLKSCcjs.OAuthProvider; exports.OAuthProxy = _chunk6DTYLKSCcjs.OAuthProxy; exports.OAuthProxyError = _chunk6DTYLKSCcjs.OAuthProxyError; exports.PKCEUtils = _chunk6DTYLKSCcjs.PKCEUtils; exports.getAuthSession = _chunk6DTYLKSCcjs.getAuthSession; exports.requireAll = _chunk6DTYLKSCcjs.requireAll; exports.requireAny = _chunk6DTYLKSCcjs.requireAny; exports.requireAuth = _chunk6DTYLKSCcjs.requireAuth; exports.requireRole = _chunk6DTYLKSCcjs.requireRole; exports.requireScopes = _chunk6DTYLKSCcjs.requireScopes;
|
|
55
55
|
//# sourceMappingURL=index.cjs.map
|
package/dist/auth/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { p as OAuthTransaction, C as ConsentData, T as TokenStorage, q as TokenVerifier, s as TokenVerificationResult, P as PKCEPair } from '../OAuthProvider-
|
|
2
|
-
export { A as AuthProvider, j as AuthProviderConfig, y as AuthorizationParams, b as AzureProvider, k as AzureProviderConfig, l as AzureSession, z as ClientCode, B as DCRClientMetadata, E as DCRRequest, F as DCRResponse, D as DEFAULT_ACCESS_TOKEN_TTL, u as DEFAULT_ACCESS_TOKEN_TTL_NO_REFRESH, v as DEFAULT_AUTHORIZATION_CODE_TTL, w as DEFAULT_REFRESH_TOKEN_TTL, x as DEFAULT_TRANSACTION_TTL, m as GenericOAuthProviderConfig, G as GitHubProvider, n as GitHubSession, c as GoogleProvider, o as GoogleSession, H as OAuthError, d as OAuthProvider, I as OAuthProviderConfig, a as OAuthProxy, J as OAuthProxyConfig, t as OAuthProxyError, O as OAuthSession, K as ProxyDCRClient, R as RefreshRequest, L as TokenMapping, M as TokenRequest, N as TokenResponse, U as UpstreamTokenSet, g as getAuthSession, r as requireAll, e as requireAny, f as requireAuth, h as requireRole, i as requireScopes } from '../OAuthProvider-
|
|
1
|
+
import { p as OAuthTransaction, C as ConsentData, T as TokenStorage, q as TokenVerifier, s as TokenVerificationResult, P as PKCEPair } from '../OAuthProvider-B_OJFNC0.cjs';
|
|
2
|
+
export { A as AuthProvider, j as AuthProviderConfig, y as AuthorizationParams, b as AzureProvider, k as AzureProviderConfig, l as AzureSession, z as ClientCode, B as DCRClientMetadata, E as DCRRequest, F as DCRResponse, D as DEFAULT_ACCESS_TOKEN_TTL, u as DEFAULT_ACCESS_TOKEN_TTL_NO_REFRESH, v as DEFAULT_AUTHORIZATION_CODE_TTL, w as DEFAULT_REFRESH_TOKEN_TTL, x as DEFAULT_TRANSACTION_TTL, m as GenericOAuthProviderConfig, G as GitHubProvider, n as GitHubSession, c as GoogleProvider, o as GoogleSession, H as OAuthError, d as OAuthProvider, I as OAuthProviderConfig, a as OAuthProxy, J as OAuthProxyConfig, t as OAuthProxyError, O as OAuthSession, K as ProxyDCRClient, R as RefreshRequest, L as TokenMapping, M as TokenRequest, N as TokenResponse, U as UpstreamTokenSet, g as getAuthSession, r as requireAll, e as requireAny, f as requireAuth, h as requireRole, i as requireScopes } from '../OAuthProvider-B_OJFNC0.cjs';
|
|
3
3
|
import 'node:http';
|
|
4
4
|
|
|
5
5
|
/**
|
package/dist/auth/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { p as OAuthTransaction, C as ConsentData, T as TokenStorage, q as TokenVerifier, s as TokenVerificationResult, P as PKCEPair } from '../OAuthProvider-
|
|
2
|
-
export { A as AuthProvider, j as AuthProviderConfig, y as AuthorizationParams, b as AzureProvider, k as AzureProviderConfig, l as AzureSession, z as ClientCode, B as DCRClientMetadata, E as DCRRequest, F as DCRResponse, D as DEFAULT_ACCESS_TOKEN_TTL, u as DEFAULT_ACCESS_TOKEN_TTL_NO_REFRESH, v as DEFAULT_AUTHORIZATION_CODE_TTL, w as DEFAULT_REFRESH_TOKEN_TTL, x as DEFAULT_TRANSACTION_TTL, m as GenericOAuthProviderConfig, G as GitHubProvider, n as GitHubSession, c as GoogleProvider, o as GoogleSession, H as OAuthError, d as OAuthProvider, I as OAuthProviderConfig, a as OAuthProxy, J as OAuthProxyConfig, t as OAuthProxyError, O as OAuthSession, K as ProxyDCRClient, R as RefreshRequest, L as TokenMapping, M as TokenRequest, N as TokenResponse, U as UpstreamTokenSet, g as getAuthSession, r as requireAll, e as requireAny, f as requireAuth, h as requireRole, i as requireScopes } from '../OAuthProvider-
|
|
1
|
+
import { p as OAuthTransaction, C as ConsentData, T as TokenStorage, q as TokenVerifier, s as TokenVerificationResult, P as PKCEPair } from '../OAuthProvider-B_OJFNC0.js';
|
|
2
|
+
export { A as AuthProvider, j as AuthProviderConfig, y as AuthorizationParams, b as AzureProvider, k as AzureProviderConfig, l as AzureSession, z as ClientCode, B as DCRClientMetadata, E as DCRRequest, F as DCRResponse, D as DEFAULT_ACCESS_TOKEN_TTL, u as DEFAULT_ACCESS_TOKEN_TTL_NO_REFRESH, v as DEFAULT_AUTHORIZATION_CODE_TTL, w as DEFAULT_REFRESH_TOKEN_TTL, x as DEFAULT_TRANSACTION_TTL, m as GenericOAuthProviderConfig, G as GitHubProvider, n as GitHubSession, c as GoogleProvider, o as GoogleSession, H as OAuthError, d as OAuthProvider, I as OAuthProviderConfig, a as OAuthProxy, J as OAuthProxyConfig, t as OAuthProxyError, O as OAuthSession, K as ProxyDCRClient, R as RefreshRequest, L as TokenMapping, M as TokenRequest, N as TokenResponse, U as UpstreamTokenSet, g as getAuthSession, r as requireAll, e as requireAny, f as requireAuth, h as requireRole, i as requireScopes } from '../OAuthProvider-B_OJFNC0.js';
|
|
3
3
|
import 'node:http';
|
|
4
4
|
|
|
5
5
|
/**
|
package/dist/auth/index.js
CHANGED
|
@@ -938,11 +938,11 @@ var PKCEUtils = class _PKCEUtils {
|
|
|
938
938
|
return false;
|
|
939
939
|
}
|
|
940
940
|
if (method === "plain") {
|
|
941
|
-
return verifier
|
|
941
|
+
return equalsConstantTime(verifier, challenge);
|
|
942
942
|
}
|
|
943
943
|
if (method === "S256") {
|
|
944
944
|
const computedChallenge = _PKCEUtils.generateChallenge(verifier, "S256");
|
|
945
|
-
return computedChallenge
|
|
945
|
+
return equalsConstantTime(computedChallenge, challenge);
|
|
946
946
|
}
|
|
947
947
|
return false;
|
|
948
948
|
}
|
|
@@ -955,6 +955,11 @@ var PKCEUtils = class _PKCEUtils {
|
|
|
955
955
|
return buffer.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
|
|
956
956
|
}
|
|
957
957
|
};
|
|
958
|
+
function equalsConstantTime(a, b) {
|
|
959
|
+
const bufA = Buffer.from(a, "utf8");
|
|
960
|
+
const bufB = Buffer.from(b, "utf8");
|
|
961
|
+
return bufA.length === bufB.length && _crypto.timingSafeEqual.call(void 0, bufA, bufB);
|
|
962
|
+
}
|
|
958
963
|
|
|
959
964
|
// src/auth/utils/tokenStore.ts
|
|
960
965
|
|
|
@@ -1802,51 +1807,62 @@ var OAuthProxy = (_class4 = class {
|
|
|
1802
1807
|
if (!jti) {
|
|
1803
1808
|
throw new OAuthProxyError("invalid_grant", "Refresh token missing JTI");
|
|
1804
1809
|
}
|
|
1805
|
-
const mapping = await this.
|
|
1810
|
+
const mapping = await this.takeMapping(jti);
|
|
1806
1811
|
if (!mapping) {
|
|
1807
1812
|
throw new OAuthProxyError(
|
|
1808
1813
|
"invalid_grant",
|
|
1809
1814
|
"Refresh token already used or expired"
|
|
1810
1815
|
);
|
|
1811
1816
|
}
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
if (!upstreamTokens) {
|
|
1816
|
-
throw new OAuthProxyError(
|
|
1817
|
-
"invalid_grant",
|
|
1818
|
-
"Upstream tokens not found or expired"
|
|
1817
|
+
try {
|
|
1818
|
+
const upstreamTokens = await this.tokenStorage.get(
|
|
1819
|
+
`upstream:${mapping.upstreamTokenKey}`
|
|
1819
1820
|
);
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1821
|
+
if (!upstreamTokens) {
|
|
1822
|
+
throw new OAuthProxyError(
|
|
1823
|
+
"invalid_grant",
|
|
1824
|
+
"Upstream tokens not found or expired"
|
|
1825
|
+
);
|
|
1826
|
+
}
|
|
1827
|
+
if (!upstreamTokens.refreshToken) {
|
|
1828
|
+
throw new OAuthProxyError(
|
|
1829
|
+
"invalid_grant",
|
|
1830
|
+
"No upstream refresh token available"
|
|
1831
|
+
);
|
|
1832
|
+
}
|
|
1833
|
+
const refreshedUpstreamTokens = await this.refreshUpstreamTokens(
|
|
1834
|
+
upstreamTokens.refreshToken,
|
|
1835
|
+
request.scope
|
|
1825
1836
|
);
|
|
1837
|
+
if (refreshedUpstreamTokens.scope.length === 0) {
|
|
1838
|
+
refreshedUpstreamTokens.scope = upstreamTokens.scope;
|
|
1839
|
+
}
|
|
1840
|
+
const refreshTokenTtl = _nullishCoalesce(_nullishCoalesce(refreshedUpstreamTokens.refreshExpiresIn, () => ( this.config.refreshTokenTtl)), () => ( DEFAULT_REFRESH_TOKEN_TTL));
|
|
1841
|
+
const accessTokenTtl = this.calculateAccessTokenTtl(
|
|
1842
|
+
refreshedUpstreamTokens
|
|
1843
|
+
);
|
|
1844
|
+
const upstreamStorageTtl = Math.max(accessTokenTtl, refreshTokenTtl, 1);
|
|
1845
|
+
await this.tokenStorage.save(
|
|
1846
|
+
`upstream:${mapping.upstreamTokenKey}`,
|
|
1847
|
+
refreshedUpstreamTokens,
|
|
1848
|
+
upstreamStorageTtl
|
|
1849
|
+
);
|
|
1850
|
+
return await this.issueSwappedTokensForRefresh(
|
|
1851
|
+
mapping.clientId,
|
|
1852
|
+
refreshedUpstreamTokens,
|
|
1853
|
+
mapping.upstreamTokenKey
|
|
1854
|
+
);
|
|
1855
|
+
} catch (error) {
|
|
1856
|
+
try {
|
|
1857
|
+
await this.restoreMapping(jti, mapping);
|
|
1858
|
+
} catch (restoreError) {
|
|
1859
|
+
console.error(
|
|
1860
|
+
`Failed to restore refresh token mapping ${jti}:`,
|
|
1861
|
+
restoreError
|
|
1862
|
+
);
|
|
1863
|
+
}
|
|
1864
|
+
throw error;
|
|
1826
1865
|
}
|
|
1827
|
-
const refreshedUpstreamTokens = await this.refreshUpstreamTokens(
|
|
1828
|
-
upstreamTokens.refreshToken,
|
|
1829
|
-
request.scope
|
|
1830
|
-
);
|
|
1831
|
-
if (refreshedUpstreamTokens.scope.length === 0) {
|
|
1832
|
-
refreshedUpstreamTokens.scope = upstreamTokens.scope;
|
|
1833
|
-
}
|
|
1834
|
-
const refreshTokenTtl = _nullishCoalesce(_nullishCoalesce(refreshedUpstreamTokens.refreshExpiresIn, () => ( this.config.refreshTokenTtl)), () => ( DEFAULT_REFRESH_TOKEN_TTL));
|
|
1835
|
-
const accessTokenTtl = this.calculateAccessTokenTtl(
|
|
1836
|
-
refreshedUpstreamTokens
|
|
1837
|
-
);
|
|
1838
|
-
const upstreamStorageTtl = Math.max(accessTokenTtl, refreshTokenTtl, 1);
|
|
1839
|
-
await this.tokenStorage.save(
|
|
1840
|
-
`upstream:${mapping.upstreamTokenKey}`,
|
|
1841
|
-
refreshedUpstreamTokens,
|
|
1842
|
-
upstreamStorageTtl
|
|
1843
|
-
);
|
|
1844
|
-
return await this.issueSwappedTokensForRefresh(
|
|
1845
|
-
mapping.clientId,
|
|
1846
|
-
refreshedUpstreamTokens,
|
|
1847
|
-
mapping.upstreamTokenKey,
|
|
1848
|
-
jti
|
|
1849
|
-
);
|
|
1850
1866
|
}
|
|
1851
1867
|
/**
|
|
1852
1868
|
* Issue swapped tokens (JWT pattern)
|
|
@@ -1927,11 +1943,10 @@ var OAuthProxy = (_class4 = class {
|
|
|
1927
1943
|
/**
|
|
1928
1944
|
* Issue swapped tokens for refresh flow
|
|
1929
1945
|
*/
|
|
1930
|
-
async issueSwappedTokensForRefresh(clientId, upstreamTokens, upstreamTokenKey
|
|
1946
|
+
async issueSwappedTokensForRefresh(clientId, upstreamTokens, upstreamTokenKey) {
|
|
1931
1947
|
if (!this.jwtIssuer) {
|
|
1932
1948
|
throw new Error("JWT issuer not initialized");
|
|
1933
1949
|
}
|
|
1934
|
-
await this.tokenStorage.delete(`mapping:${oldJti}`);
|
|
1935
1950
|
const customClaims = await this.extractUpstreamClaims(upstreamTokens);
|
|
1936
1951
|
const accessTokenTtl = this.calculateAccessTokenTtl(upstreamTokens);
|
|
1937
1952
|
const refreshTokenTtl = upstreamTokens.refreshToken ? _nullishCoalesce(_nullishCoalesce(upstreamTokens.refreshExpiresIn, () => ( this.config.refreshTokenTtl)), () => ( DEFAULT_REFRESH_TOKEN_TTL)) : 0;
|
|
@@ -2108,6 +2123,29 @@ var OAuthProxy = (_class4 = class {
|
|
|
2108
2123
|
tokenType: tokens.token_type || "Bearer"
|
|
2109
2124
|
};
|
|
2110
2125
|
}
|
|
2126
|
+
/**
|
|
2127
|
+
* Put a claimed refresh-token mapping back after a rotation failed, keeping
|
|
2128
|
+
* whatever lifetime it had left.
|
|
2129
|
+
*
|
|
2130
|
+
* A mapping that is already expired, or that carries no usable expiry, is
|
|
2131
|
+
* dropped instead. Inventing a TTL here would extend the lifetime of a
|
|
2132
|
+
* credential in a security path, and every mapping this proxy writes records
|
|
2133
|
+
* `expiresAt`.
|
|
2134
|
+
*/
|
|
2135
|
+
async restoreMapping(jti, mapping) {
|
|
2136
|
+
if (!mapping.expiresAt) {
|
|
2137
|
+
return;
|
|
2138
|
+
}
|
|
2139
|
+
const expiresAt = new Date(mapping.expiresAt).getTime();
|
|
2140
|
+
if (Number.isNaN(expiresAt)) {
|
|
2141
|
+
return;
|
|
2142
|
+
}
|
|
2143
|
+
const ttl = Math.ceil((expiresAt - Date.now()) / 1e3);
|
|
2144
|
+
if (ttl <= 0) {
|
|
2145
|
+
return;
|
|
2146
|
+
}
|
|
2147
|
+
await this.tokenStorage.save(`mapping:${jti}`, mapping, ttl);
|
|
2148
|
+
}
|
|
2111
2149
|
/**
|
|
2112
2150
|
* Start periodic cleanup of expired transactions and codes
|
|
2113
2151
|
*/
|
|
@@ -2116,6 +2154,24 @@ var OAuthProxy = (_class4 = class {
|
|
|
2116
2154
|
this.cleanup();
|
|
2117
2155
|
}, 6e4);
|
|
2118
2156
|
}
|
|
2157
|
+
/**
|
|
2158
|
+
* Atomically claim a token mapping, mirroring `OAuthProxyStateStore`: at most
|
|
2159
|
+
* one caller — across all processes sharing the storage — can receive a given
|
|
2160
|
+
* mapping, which is what makes single use enforceable. Falls back to a
|
|
2161
|
+
* non-atomic get + delete for storages that do not implement `take`.
|
|
2162
|
+
*/
|
|
2163
|
+
async takeMapping(jti) {
|
|
2164
|
+
const key = `mapping:${jti}`;
|
|
2165
|
+
if (this.tokenStorage.take) {
|
|
2166
|
+
return await this.tokenStorage.take(key);
|
|
2167
|
+
}
|
|
2168
|
+
const stored = await this.tokenStorage.get(key);
|
|
2169
|
+
if (stored === null) {
|
|
2170
|
+
return null;
|
|
2171
|
+
}
|
|
2172
|
+
await this.tokenStorage.delete(key);
|
|
2173
|
+
return stored;
|
|
2174
|
+
}
|
|
2119
2175
|
/**
|
|
2120
2176
|
* Validate a redirect URI against the configured allow-list.
|
|
2121
2177
|
*
|
|
@@ -2733,4 +2789,4 @@ Original error: ${error.message}`
|
|
|
2733
2789
|
|
|
2734
2790
|
|
|
2735
2791
|
exports.getAuthSession = getAuthSession; exports.requireAll = requireAll; exports.requireAny = requireAny; exports.requireAuth = requireAuth; exports.requireRole = requireRole; exports.requireScopes = requireScopes; exports.DEFAULT_ACCESS_TOKEN_TTL = DEFAULT_ACCESS_TOKEN_TTL; exports.DEFAULT_ACCESS_TOKEN_TTL_NO_REFRESH = DEFAULT_ACCESS_TOKEN_TTL_NO_REFRESH; exports.DEFAULT_REFRESH_TOKEN_TTL = DEFAULT_REFRESH_TOKEN_TTL; exports.DEFAULT_AUTHORIZATION_CODE_TTL = DEFAULT_AUTHORIZATION_CODE_TTL; exports.DEFAULT_TRANSACTION_TTL = DEFAULT_TRANSACTION_TTL; exports.ConsentManager = ConsentManager; exports.JWTIssuer = JWTIssuer; exports.PKCEUtils = PKCEUtils; exports.EncryptedTokenStorage = EncryptedTokenStorage; exports.MemoryTokenStorage = MemoryTokenStorage; exports.OAuthProxy = OAuthProxy; exports.OAuthProxyError = OAuthProxyError; exports.AuthProvider = AuthProvider; exports.AzureProvider = AzureProvider; exports.GitHubProvider = GitHubProvider; exports.GoogleProvider = GoogleProvider; exports.OAuthProvider = OAuthProvider; exports.DiskStore = DiskStore; exports.JWKSVerifier = JWKSVerifier;
|
|
2736
|
-
//# sourceMappingURL=chunk-
|
|
2792
|
+
//# sourceMappingURL=chunk-6DTYLKSC.cjs.map
|