Skip to content

@gj-kit/expo-auth core concepts

Token refresh for Expo, React Native and web — a missed transient branch won’t compile.

Hand-rolled refresh code classifies a 5xx, a timeout or a CORS failure as a definitive rejection and signs the user out, because the refresh result is consumed by a raw switch that TypeScript never checks for exhaustiveness — and the branch that goes missing is always the transient one. Meanwhile a Platform.OS fork drags expo-secure-store into the web bundle, two tabs race the same single-use refresh token, a boolean re-entry flag lets a 401 retry fall back into the refresh path, and an option-less re-login after signOut silently promotes a session-scoped login to durable storage on a shared machine.

Multiple requests can discover an expired token together. Injected storage and locking let the host choose the platform mechanism while one session coordinates refresh.

Closed refresh outcomes distinguish retryable service failures from invalid credentials, so a 5xx cannot silently clear a valid session.

  • Missing transient case won’t compile — matchRefreshOutcome takes all five endings as handler keys — omit one and the call fails to compile with “Property ‘transient’ is missing”.
  • A 5xx leaves stored tokens alone — On a transient outcome the core writes nothing to storage, and runAuthorized rethrows your original error instead of routing the user to sign-in.
  • Retry twice is unrepresentable — runAuthorized requires shouldRetryAfterRefresh with no default, and the one retry it performs runs outside the refresh path — the public API has no re-entry switch.
  • signIn cannot forget persistence — persistence is a required option on signIn’s second argument, so “session login → signOut → option-less re-login” cannot silently promote tokens to durable storage.
  • No SecureStore in the web bundle — One ./storage subpath forks through exports conditions, so your app writes zero Platform.OS branches and the browser graph contains no expo-secure-store.

Treat tokens as secrets: use the supplied error contracts and never log token strings or raw authorization responses.

Continue with the two verified recipes.