v0.6.0
Minor Changes
-
#199
bf7d91eThanks @mattzcarey! - ConvertOAuthErrorthrown fromtokenExchangeCallbackinto structured
/tokenresponses and convert token storage KV rate limits into retryable OAuth errors.Previously, an error thrown from
tokenExchangeCallbackduring the
authorization_codeorrefresh_tokengrant flows would bubble up as an
unhandled exception and be served as500 Internal Server Error. This forced
clients to keep retrying with the same dead refresh token, producing
"refresh-token retry storms" against upstream providers.The provider now catches
OAuthErrorthrown from the callback (or any code
it calls — errors propagate naturally up through deep call stacks) and
returns a standard{ error, error_description }response with the supplied
status code and headers. KV429 Too Many Requestswrite failures while issuing
tokens are also returned astemporarily_unavailablewithRetry-After: 30,
so transient storage pressure does not leak Worker500responses from the
token endpoint.import { OAuthError } from '@cloudflare/workers-oauth-provider'; tokenExchangeCallback: async (options) => { if (options.grantType === 'refresh_token') { // `refreshUpstream` may throw `OAuthError` from any depth. return { newProps: await refreshUpstream(options.props) }; } }; async function refreshUpstream(props) { const res = await fetch(/* upstream token endpoint */); if (res.status === 401) { throw new OAuthError('invalid_grant', { description: 'upstream refresh token is invalid', }); } if (res.status === 429) { throw new OAuthError('temporarily_unavailable', { description: 'upstream rate limited', statusCode: 429, headers: { 'Retry-After': res.headers.get('retry-after') ?? '60' }, }); } return await res.json(); }
OAuthError(code, options)takes:code(positional, required) — the OAuth error code returned in the
errorfield. For standard codes, this package exports the
OAuthTokenErrorCodetype.options.description— human-readable text returned inerror_description.options.statusCode— HTTP status code (default400).options.headers— additional response headers. SetRetry-Afterhere
for transient failures so well-behaved clients back off; per RFC 7231
§7.1.3 the value may be either seconds or an HTTP-date. No implicit
default — if you don't set it, noRetry-Afteris sent.
Throwing this package's
OAuthErrorclass is the supported form. Anything
else — plainError, plain objects with acodefield, app-local OAuth
error classes, etc. — continues to surface as500 Internal Server Error
so unexpected failures stay visible. The provider does not
catch-everything-and-return-400.The exported
OAuthErrorclass supersedes the previously-internal one: the
constructor signature is now(code, options)rather than(code, message).
Internal call sites are updated;descriptionnow lives alongside
statusCodeandheadersin the options object.New exports:
OAuthError(class),OAuthErrorOptions(interface),
OAuthTokenErrorCode(type union of registered codes).