Checklist
Description
getAccessTokenSilently is typed as returning Promise<string> (src/auth0-context.tsx#L67), but at runtime it can resolve to undefined. TypeScript users therefore get no prompt to handle the undefined case, and the typical failure is a silent Authorization: Bearer undefined header sent to an API.
The undefined originates in auth0-spa-js's getTokenSilently, which auth0-react wraps and returns verbatim (the wrapper does token = await client.getTokenSilently(opts); … return token; with no guard). There are two runtime paths that produce undefined:
-
cacheMode: 'cache-only' with a cache miss — src/Auth0Client.ts#L998:
if (cacheMode === 'cache-only') {
return; // bare return → undefined
}
-
Session ceiling reached — src/Auth0Client.ts#L979:
if (await this._isSessionCeilingReached()) {
return undefined;
}
Notably this fires on a plain getAccessTokenSilently() call with default options (when the cached ID token carries a session_expiry claim that has passed). It also clears the local session as a side effect and then resolves undefined rather than throwing — so callers get neither a token nor an exception.
The SDK's internals already acknowledge this: the private _getTokenSilently is typed Promise<undefined | GetTokenSilentlyVerboseResponse> and the public wrapper reads result?.access_token with optional chaining (src/Auth0Client.ts#L969) — the undefined is known, it's just erased at the public type boundary (src/Auth0Client.ts#L910, mirrored in auth0-react's Auth0ContextInterface).
Expected: the public return type should tell the truth — Promise<string | undefined> (or, if preferred, a narrowed overload so only cacheMode: 'cache-only' widens to string | undefined, with the session-ceiling path either included or changed to throw). Whatever shape is chosen in auth0-spa-js, auth0-react's re-declared getAccessTokenSilently type needs the same fix.
auth0-react version
2.22.1 (with @auth0/auth0-spa-js 2.24.1)
React version
19.2
Which browsers have you tested in?
Chrome
Checklist
Description
getAccessTokenSilentlyis typed as returningPromise<string>(src/auth0-context.tsx#L67), but at runtime it can resolve toundefined. TypeScript users therefore get no prompt to handle theundefinedcase, and the typical failure is a silentAuthorization: Bearer undefinedheader sent to an API.The
undefinedoriginates inauth0-spa-js'sgetTokenSilently, whichauth0-reactwraps and returns verbatim (the wrapper doestoken = await client.getTokenSilently(opts); … return token;with no guard). There are two runtime paths that produceundefined:cacheMode: 'cache-only'with a cache miss —src/Auth0Client.ts#L998:Session ceiling reached —
src/Auth0Client.ts#L979:Notably this fires on a plain
getAccessTokenSilently()call with default options (when the cached ID token carries asession_expiryclaim that has passed). It also clears the local session as a side effect and then resolvesundefinedrather than throwing — so callers get neither a token nor an exception.The SDK's internals already acknowledge this: the private
_getTokenSilentlyis typedPromise<undefined | GetTokenSilentlyVerboseResponse>and the public wrapper readsresult?.access_tokenwith optional chaining (src/Auth0Client.ts#L969) — theundefinedis known, it's just erased at the public type boundary (src/Auth0Client.ts#L910, mirrored in auth0-react'sAuth0ContextInterface).Expected: the public return type should tell the truth —
Promise<string | undefined>(or, if preferred, a narrowed overload so onlycacheMode: 'cache-only'widens tostring | undefined, with the session-ceiling path either included or changed to throw). Whatever shape is chosen inauth0-spa-js,auth0-react's re-declaredgetAccessTokenSilentlytype needs the same fix.auth0-react version
2.22.1 (with @auth0/auth0-spa-js 2.24.1)
React version
19.2
Which browsers have you tested in?
Chrome