different-ai/openwork · error · EnterpriseMcpOAuthContractError
MCP_OAUTH_AUTHORIZATION_EXPIRED
MCP_OAUTH_AUTHORIZATION_EXPIRED
Error message
The OAuth authorization transaction has expired; start the connection again.
What it means
Thrown from codeVerifier when the loaded transaction's expiresAt is at or before now plus the expiration skew window. The PKCE transaction has a bounded TTL (authorizationTransactionTtlMs); if the user takes too long to complete authorization at the identity provider, the library invalidates the record and requires starting over. This prevents stale PKCE secrets from being exchanged.
Source
Thrown at packages/enterprise-mcp-client/src/oauth-provider.ts:467
)
}
const transaction = await this.persistence.authorizations.load({
context: this.context(),
id: this.flow.authorizationId,
})
if (!transaction) {
throw new EnterpriseMcpOAuthContractError(
"MCP_OAUTH_AUTHORIZATION_MISSING",
"The OAuth authorization transaction is missing or was already consumed.",
)
}
if (transaction.handle.expiresAt <= this.clock.now() + this.expirationSkewMs) {
await this.persistence.authorizations.invalidate({
context: this.context(),
id: this.flow.authorizationId,
reason: "expired",
})
throw new EnterpriseMcpOAuthContractError(
"MCP_OAUTH_AUTHORIZATION_EXPIRED",
"The OAuth authorization transaction has expired; start the connection again.",
)
}
const clientRevision = this.loadedClient?.revision
if (
transaction.handle.clientRegistrationRevision !== undefined
&& transaction.handle.clientRegistrationRevision !== clientRevision
) {
throw new EnterpriseMcpOAuthContractError(
"MCP_OAUTH_AUTHORIZATION_CLIENT_CHANGED",
"The OAuth client registration changed after authorization started.",
)
}
this.authorizationHandle = transaction.handle
return transaction.codeVerifier
}
View on GitHub (pinned to 2b7df46e8a)
Solutions
- Restart the connect flow to mint a fresh transaction.
- Increase authorizationTransactionTtlMs if your IdP login flow legitimately takes longer.
- Detect this error in the callback handler and automatically re-initiate the authorization redirect.
Example fix
// before
new EnterpriseMcpOAuthProvider({ authorizationTransactionTtlMs: 60_000 })
// after — allow slow IdP logins
new EnterpriseMcpOAuthProvider({ authorizationTransactionTtlMs: 10 * 60_000 }) Defensive patterns
Strategy: try-catch
Validate before calling
const tx = await persistence.authorizations.load({ context, id: authorizationId })
const expired = tx !== undefined && tx.handle.expiresAt <= Date.now() Try / catch
try { const verifier = await provider.codeVerifier() }
catch (e) {
if (e instanceof EnterpriseMcpOAuthContractError && e.code === "MCP_OAUTH_AUTHORIZATION_EXPIRED") {
return redirectToAuthorization() // silently restart the connect flow
}
throw e
} Prevention
- Set authorizationTransactionTtlMs comfortably above your IdP's worst-case login time
- Auto-restart the flow on expiry in the callback handler instead of showing an error
- Warn users before the transaction is about to expire during long consent flows
When it happens
Trigger: codeVerifier() after the transaction TTL elapsed — e.g. user left the authorization page open and returned later; transaction.expiresAt <= clock.now() + expirationSkewMs.
Common situations: Long user delays at the IdP login/consent screens; very short authorizationTransactionTtlMs configuration; the callback arriving hours later (user bookmarked the redirect URL).
Related errors
- MCP_OAUTH_AUTHORIZATION_MISSING
- `${t("providers.no_oauth_prefix")} ${resolved}. ${t("provide
- `${t("providers.not_oauth_flow_prefix")} ${resolved}.`
- t("providers.oauth_method_required")
- OpenWork-managed MCP OAuth is currently available for local
AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01).
Data as JSON: /api/errors/d5389285b35c7e7a.
Report an issue: GitHub.