Preliminary Checks
Reproduction
https://github.com/clerk/clerk-expo-quickstart
Publishable key
pk_test_YmlnLWZpbGx5LTM3LmNsZXJrLmFjY291bnRzLmRldiQ
Description
After migrating from @clerk/clerk-expo v2 to @clerk/expo v3.1.6, Metro JS reload (pressing R) causes session loss despite valid JWT in tokenCache.
This did NOT happen with @clerk/clerk-expo v2.
Steps to reproduce:
- Set up
@clerk/expo v3 with tokenCache from @clerk/expo/token-cache
- Add
@clerk/expo to plugins in app.config.js
- Run
npx expo prebuild --clean, then npx expo run:ios or npx expo run:android
- Sign in successfully
- Press R in Metro terminal (JS reload)
- User is redirected to sign-in screen — session lost
Expected behavior:
Session should be restored from cached JWT, same as v2 and same as app kill + reopen.
Actual behavior:
tokenCache.getToken("__clerk_client_jwt") returns a valid JWT, but useAuth() resolves with isLoaded: true, isSignedIn: false, userId: null.
App kill + reopen works correctly — session persists. The issue is only with JS-only reload where native context survives but JS re-initializes.
Logs after sign-in:
getToken __clerk_client_jwt eyJhbGciOiJSUzI1NiIs...
useAuth: isLoaded=true, isSignedIn=true, userId=user_xxx
Logs after Metro JS reload:
getToken __clerk_client_jwt eyJhbGciOiJSUzI1NiIs... ← same valid JWT
useAuth: isLoaded=true, isSignedIn=false, userId=null ← session lost
Logs after app kill + reopen:
getToken __clerk_client_jwt eyJhbGciOiJSUzI1NiIs...
useAuth: isLoaded=true, isSignedIn=true, userId=user_xxx ← works fine
What I've tried:
- Custom tokenCache with logging — JWT is present and read correctly
- Built-in
@clerk/expo/token-cache — same result
@clerk/expo added to plugins in app.config.js (native module confirmed: "Clerk iOS plugin loaded", "Clerk Android plugin loaded")
publishableKey via process.env.EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY (inlined by Metro)
useAuth({ treatPendingAsSignedOut: false }) — isSignedIn still resolves to false
npx expo prebuild --clean + full native rebuild with --no-build-cache
- Tested on Android physical device and emulator — session lost on JS reload
- Tested on iOS physical device — session survives JS reload correctly
- App kill + reopen works fine on both platforms
Possibly related: #8245, #8236
Environment
System:
OS: macOS 26.0
CPU: (8) arm64 Apple M1 Pro
Memory: 89.36 MB / 16.00 GB
Shell: 5.9 - /bin/zsh
Binaries:
Node: 23.3.0 - /Users/prilepskiy/.asdf/installs/nodejs/23.3.0/bin/node
npm: 10.9.0 - /Users/prilepskiy/.asdf/plugins/nodejs/shims/npm
bun: 1.3.6 - /Users/prilepskiy/.bun/bin/bun
npmPackages:
@clerk/expo: ^3.1.6 => 3.1.6
expo: ~54.0.33 => 54.0.33
react: 19.1.0 => 19.1.0
react-native: 0.81.5 => 0.81.5
Preliminary Checks
I have reviewed the documentation: https://clerk.com/docs
I have searched for existing issues: https://github.com/clerk/javascript/issues
I have not already reached out to Clerk support via email or Discord (if you have, no need to open an issue here)
This issue is not a question, general help request, or anything other than a bug report directly related to Clerk. Please ask questions in our Discord community: https://clerk.com/discord.
Reproduction
https://github.com/clerk/clerk-expo-quickstart
Publishable key
pk_test_YmlnLWZpbGx5LTM3LmNsZXJrLmFjY291bnRzLmRldiQ
Description
After migrating from
@clerk/clerk-expov2 to@clerk/expov3.1.6, Metro JS reload (pressing R) causes session loss despite valid JWT in tokenCache.This did NOT happen with
@clerk/clerk-expov2.Steps to reproduce:
@clerk/expov3 withtokenCachefrom@clerk/expo/token-cache@clerk/expoto plugins in app.config.jsnpx expo prebuild --clean, thennpx expo run:iosornpx expo run:androidExpected behavior:
Session should be restored from cached JWT, same as v2 and same as app kill + reopen.
Actual behavior:
tokenCache.getToken("__clerk_client_jwt")returns a valid JWT, butuseAuth()resolves withisLoaded: true,isSignedIn: false,userId: null.App kill + reopen works correctly — session persists. The issue is only with JS-only reload where native context survives but JS re-initializes.
Logs after sign-in:
Logs after Metro JS reload:
Logs after app kill + reopen:
What I've tried:
@clerk/expo/token-cache— same result@clerk/expoadded to plugins in app.config.js (native module confirmed: "Clerk iOS plugin loaded", "Clerk Android plugin loaded")publishableKeyviaprocess.env.EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY(inlined by Metro)useAuth({ treatPendingAsSignedOut: false })— isSignedIn still resolves to falsenpx expo prebuild --clean+ full native rebuild with --no-build-cachePossibly related: #8245, #8236
Environment
System: OS: macOS 26.0 CPU: (8) arm64 Apple M1 Pro Memory: 89.36 MB / 16.00 GB Shell: 5.9 - /bin/zsh Binaries: Node: 23.3.0 - /Users/prilepskiy/.asdf/installs/nodejs/23.3.0/bin/node npm: 10.9.0 - /Users/prilepskiy/.asdf/plugins/nodejs/shims/npm bun: 1.3.6 - /Users/prilepskiy/.bun/bin/bun npmPackages: @clerk/expo: ^3.1.6 => 3.1.6 expo: ~54.0.33 => 54.0.33 react: 19.1.0 => 19.1.0 react-native: 0.81.5 => 0.81.5