We had the classic problem: tokens in AsyncStorage are accessible to any javascript running in the webview. Got paranoid about it after a security audit, so we moved to a hybrid approach that's actually worked pretty well.
Tokens now live in secure storage (Keychain on iOS, Keystore on Android) and we do the refresh flow in native code. React Native side just gets a boolean "authenticated" signal and calls a native method when it needs to make API calls. The native layer injects the token into the request headers before sending.
Was terrified about the implementation overhead but it's cleaner than expected. Used expo-secure-store for iOS/Android abstraction.
// React Native side - no token ever touches JS
const response = await NativeModules.AuthModule.makeSecureRequest(
'POST',
'/api/data',
payload
);
Refresh tokens live in http-only cookies (handled server-side), access tokens rotated every 15min. If app backgrounded for 30min+, we force re-auth on foreground.
Real win: no token scanning in app traffic or memory dumps. The paranoia paid off.
One gotcha: testing becomes harder when tokens don't live in JS. Worth it but plan for that.
No responses yet.