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 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
- > [!NOTE]
5
+ > [!IMPORTANT]
6
6
  >
7
- > For a Python implementation, see [FastMCP](https://github.com/jlowin/fastmcp).
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 _chunkENMHHQJFcjs = require('./chunk-ENMHHQJF.cjs');
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 = _chunkENMHHQJFcjs.AuthProvider; exports.AzureProvider = _chunkENMHHQJFcjs.AzureProvider; exports.DiscoveryDocumentCache = _chunkU36NARZGcjs.DiscoveryDocumentCache; exports.FastMCP = _chunkU36NARZGcjs.FastMCP; exports.FastMCPError = _chunkU36NARZGcjs.FastMCPError; exports.FastMCPSession = _chunkU36NARZGcjs.FastMCPSession; exports.GitHubProvider = _chunkENMHHQJFcjs.GitHubProvider; exports.GoogleProvider = _chunkENMHHQJFcjs.GoogleProvider; exports.MEDIA_FETCH_TIMEOUT_MS = _chunkU36NARZGcjs.MEDIA_FETCH_TIMEOUT_MS; exports.OAuthProvider = _chunkENMHHQJFcjs.OAuthProvider; exports.ServerState = _chunkU36NARZGcjs.ServerState; exports.SessionError = _chunkU36NARZGcjs.SessionError; exports.UnexpectedStateError = _chunkU36NARZGcjs.UnexpectedStateError; exports.UserError = _chunkU36NARZGcjs.UserError; exports.audioContent = _chunkU36NARZGcjs.audioContent; exports.getAuthSession = _chunkENMHHQJFcjs.getAuthSession; exports.imageContent = _chunkU36NARZGcjs.imageContent; exports.jsonSchemaAdapter = _chunkU36NARZGcjs.jsonSchemaAdapter; exports.requireAll = _chunkENMHHQJFcjs.requireAll; exports.requireAny = _chunkENMHHQJFcjs.requireAny; exports.requireAuth = _chunkENMHHQJFcjs.requireAuth; exports.requireRole = _chunkENMHHQJFcjs.requireRole; exports.requireScopes = _chunkENMHHQJFcjs.requireScopes;
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
@@ -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-B_E71LUD.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_E71LUD.cjs';
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-B_E71LUD.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_E71LUD.js';
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
@@ -24,7 +24,7 @@ import {
24
24
  requireAuth,
25
25
  requireRole,
26
26
  requireScopes
27
- } from "./chunk-2ZFQSPXZ.js";
27
+ } from "./chunk-VFBUPSNI.js";
28
28
  export {
29
29
  AuthProvider,
30
30
  AzureProvider,
@@ -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 when more than one process shares
392
- * this storage**: the OAuth proxy consumes authorization codes and
393
- * transactions through it, and single-use enforcement depends on the
394
- * atomicity. Without it the proxy falls back to a non-atomic get + delete,
395
- * where two concurrent requests can both redeem the same authorization code.
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 when more than one process shares
392
- * this storage**: the OAuth proxy consumes authorization codes and
393
- * transactions through it, and single-use enforcement depends on the
394
- * atomicity. Without it the proxy falls back to a non-atomic get + delete,
395
- * where two concurrent requests can both redeem the same authorization code.
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
  *
@@ -24,7 +24,7 @@
24
24
 
25
25
 
26
26
 
27
- var _chunkENMHHQJFcjs = require('../chunk-ENMHHQJF.cjs');
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 = _chunkENMHHQJFcjs.AuthProvider; exports.AzureProvider = _chunkENMHHQJFcjs.AzureProvider; exports.ConsentManager = _chunkENMHHQJFcjs.ConsentManager; exports.DEFAULT_ACCESS_TOKEN_TTL = _chunkENMHHQJFcjs.DEFAULT_ACCESS_TOKEN_TTL; exports.DEFAULT_ACCESS_TOKEN_TTL_NO_REFRESH = _chunkENMHHQJFcjs.DEFAULT_ACCESS_TOKEN_TTL_NO_REFRESH; exports.DEFAULT_AUTHORIZATION_CODE_TTL = _chunkENMHHQJFcjs.DEFAULT_AUTHORIZATION_CODE_TTL; exports.DEFAULT_REFRESH_TOKEN_TTL = _chunkENMHHQJFcjs.DEFAULT_REFRESH_TOKEN_TTL; exports.DEFAULT_TRANSACTION_TTL = _chunkENMHHQJFcjs.DEFAULT_TRANSACTION_TTL; exports.DiskStore = _chunkENMHHQJFcjs.DiskStore; exports.EncryptedTokenStorage = _chunkENMHHQJFcjs.EncryptedTokenStorage; exports.GitHubProvider = _chunkENMHHQJFcjs.GitHubProvider; exports.GoogleProvider = _chunkENMHHQJFcjs.GoogleProvider; exports.JWKSVerifier = _chunkENMHHQJFcjs.JWKSVerifier; exports.JWTIssuer = _chunkENMHHQJFcjs.JWTIssuer; exports.MemoryTokenStorage = _chunkENMHHQJFcjs.MemoryTokenStorage; exports.OAuthProvider = _chunkENMHHQJFcjs.OAuthProvider; exports.OAuthProxy = _chunkENMHHQJFcjs.OAuthProxy; exports.OAuthProxyError = _chunkENMHHQJFcjs.OAuthProxyError; exports.PKCEUtils = _chunkENMHHQJFcjs.PKCEUtils; exports.getAuthSession = _chunkENMHHQJFcjs.getAuthSession; exports.requireAll = _chunkENMHHQJFcjs.requireAll; exports.requireAny = _chunkENMHHQJFcjs.requireAny; exports.requireAuth = _chunkENMHHQJFcjs.requireAuth; exports.requireRole = _chunkENMHHQJFcjs.requireRole; exports.requireScopes = _chunkENMHHQJFcjs.requireScopes;
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
@@ -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-B_E71LUD.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_E71LUD.cjs';
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
  /**
@@ -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-B_E71LUD.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_E71LUD.js';
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
  /**
@@ -24,7 +24,7 @@ import {
24
24
  requireAuth,
25
25
  requireRole,
26
26
  requireScopes
27
- } from "../chunk-2ZFQSPXZ.js";
27
+ } from "../chunk-VFBUPSNI.js";
28
28
  export {
29
29
  AuthProvider,
30
30
  AzureProvider,
@@ -938,11 +938,11 @@ var PKCEUtils = class _PKCEUtils {
938
938
  return false;
939
939
  }
940
940
  if (method === "plain") {
941
- return verifier === challenge;
941
+ return equalsConstantTime(verifier, challenge);
942
942
  }
943
943
  if (method === "S256") {
944
944
  const computedChallenge = _PKCEUtils.generateChallenge(verifier, "S256");
945
- return computedChallenge === challenge;
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.tokenStorage.get(`mapping:${jti}`);
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
- const upstreamTokens = await this.tokenStorage.get(
1813
- `upstream:${mapping.upstreamTokenKey}`
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
- if (!upstreamTokens.refreshToken) {
1822
- throw new OAuthProxyError(
1823
- "invalid_grant",
1824
- "No upstream refresh token available"
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, oldJti) {
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-ENMHHQJF.cjs.map
2792
+ //# sourceMappingURL=chunk-6DTYLKSC.cjs.map