diff --git a/.changeset/protect-expo-native-client-sync.md b/.changeset/protect-expo-native-client-sync.md new file mode 100644 index 00000000000..56cab5fb812 --- /dev/null +++ b/.changeset/protect-expo-native-client-sync.md @@ -0,0 +1,5 @@ +--- +'@clerk/expo': patch +--- + +Prevent native client updates from replacing a signed-in Expo client with a stale or sessionless client. Native-to-JS synchronization now validates client changes before applying them, restores the previous token when validation fails, and applies the same protection during 401 recovery. diff --git a/integration/templates/expo-native/App.tsx b/integration/templates/expo-native/App.tsx index 2031e9b4512..cef3f2faf71 100644 --- a/integration/templates/expo-native/App.tsx +++ b/integration/templates/expo-native/App.tsx @@ -1,10 +1,13 @@ import { ClerkProvider, useAuth, useUser } from '@clerk/expo'; -import { useSignInWithGoogle } from '@clerk/expo/google'; import { AuthView, UserButton } from '@clerk/expo/native'; import { tokenCache } from '@clerk/expo/token-cache'; import { useState } from 'react'; import { Button, Modal, StyleSheet, Text, View } from 'react-native'; +import { E2EControls } from './components/E2EControls'; +import { GoogleSignInButton } from './components/GoogleSignInButton'; +import { JsSignInForm } from './components/JsSignInForm'; + const publishableKey = process.env.EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY; if (!publishableKey) { @@ -14,9 +17,8 @@ if (!publishableKey) { function NativeBuildFixture() { const { isLoaded, isSignedIn, signOut } = useAuth({ treatPendingAsSignedOut: false }); const { user } = useUser(); - const { startGoogleAuthenticationFlow } = useSignInWithGoogle(); const [isAuthOpen, setIsAuthOpen] = useState(false); - const [googleResult, setGoogleResult] = useState(null); + const [e2eStatus, setE2eStatus] = useState(null); return ( @@ -32,19 +34,10 @@ function NativeBuildFixture() { title='Open native AuthView' onPress={() => setIsAuthOpen(true)} /> - {!isSignedIn && ( -