I'm building an Expo app (salon management — booking, scheduling, staff) that uses Clerk for auth and Convex for the backend. 5 salons in pipeline, 3 paying. The app has been in active development for months with this stack.
getToken({ template: "convex" }) started throwing clerk_offline on React Native. getToken() without a template returns a valid session JWT. Same device, same network, same session.
I spent a full debug session isolating this. The network is fine — I tested from inside the RN runtime:
fetch(".well-known/openid-configuration") → 200
fetch("convex.cloud/version") → 200
fetch("google.com") → 200
getToken() → valid JWT
getToken({ template: "convex" }) → clerk_offline
The JWT template "convex" exists in the dashboard, configured correctly (verified issuer, JWKS, aud: "convex"). It worked before.
This blocks the entire app. Convex's ConvexProviderWithClerk hardcodes getToken({ template: "convex" }) internally. When that call fails, the Convex WebSocket connects but never authenticates — every authenticated query returns "Unauthenticated" and every screen shows a timeout. The app is unusable.
I'm working around it now by dropping ConvexProviderWithClerk entirely and using ConvexProviderWithAuth with a custom hook that calls getToken() (no template). Convex still validates the JWT signature and issuer, just skips the aud check. It works but it's not ideal for production.
The clerk_offline code seems like a false positive. Whatever internal HTTP client getToken({ template }) uses to mint the template-specific JWT is failing, even though the global fetch() in RN reaches the same Clerk domain without issues. The session token path (which I assume reads from the local cache) works. The template token path (which needs a network call to Clerk's API) doesn't.
Versions:
@clerk/expo: 3.1.2
expo: ~55.0.6
react-native: 0.83.2
react: 19.2.0
- iOS 26.2 simulator + iPhone 16 Pro (same behavior on both)
I'm building an Expo app (salon management — booking, scheduling, staff) that uses Clerk for auth and Convex for the backend. 5 salons in pipeline, 3 paying. The app has been in active development for months with this stack.
getToken({ template: "convex" })started throwingclerk_offlineon React Native.getToken()without a template returns a valid session JWT. Same device, same network, same session.I spent a full debug session isolating this. The network is fine — I tested from inside the RN runtime:
The JWT template "convex" exists in the dashboard, configured correctly (verified issuer, JWKS,
aud: "convex"). It worked before.This blocks the entire app. Convex's
ConvexProviderWithClerkhardcodesgetToken({ template: "convex" })internally. When that call fails, the Convex WebSocket connects but never authenticates — every authenticated query returns "Unauthenticated" and every screen shows a timeout. The app is unusable.I'm working around it now by dropping
ConvexProviderWithClerkentirely and usingConvexProviderWithAuthwith a custom hook that callsgetToken()(no template). Convex still validates the JWT signature and issuer, just skips theaudcheck. It works but it's not ideal for production.The
clerk_offlinecode seems like a false positive. Whatever internal HTTP clientgetToken({ template })uses to mint the template-specific JWT is failing, even though the globalfetch()in RN reaches the same Clerk domain without issues. The session token path (which I assume reads from the local cache) works. The template token path (which needs a network call to Clerk's API) doesn't.Versions:
@clerk/expo: 3.1.2expo: ~55.0.6react-native: 0.83.2react: 19.2.0