The useSignInWithApple() hook provides native Sign in with Apple functionality for iOS devices. It handles the ID token exchange with Clerk's backend and automatically manages the transfer flow between sign-up and sign-in.
Metadata that can be read and set from the frontend and the backend. Once the authentication process is complete, the value of this field will be automatically copied to the created user's unsafe metadata (User.unsafeMetadata). One common use case is to collect custom information about the user during the authentication process and store it in this property. Read more about unsafe metadata.
The SignInJavaScript Icon object that was created, which holds the state of the current sign-in and provides helper methods to navigate and complete the sign-in process.
The SignUpJavaScript Icon object that was created, which holds the state of the current sign-up and provides helper methods to navigate and complete the sign-up process.
The following example demonstrates how to use the useSignInWithApple()Expo Icon hook to manage the Apple authentication flow. Because the useSignInWithApple() hook automatically manages the transfer flow between sign-up and sign-in, you can use this component for both your sign-up and sign-in pages.
components/AppleSignInButton.tsx
import { useSignInWithApple } from'@clerk/expo/apple'import { useRouter } from'expo-router'import { Alert, Platform, StyleSheet, Text, TouchableOpacity, View } from'react-native'// Example props that you could pass to your buttoninterfaceAppleSignInButtonProps {// Callback function that is called when the sign-in is completeonSignInComplete?: () =>void// Whether to show a divider between the button and the text showDivider?:boolean}exportfunctionAppleSignInButton({ onSignInComplete, showDivider =true,}:AppleSignInButtonProps) {const { startAppleAuthenticationFlow } =useSignInWithApple()constrouter=useRouter()// Only render on iOSif (Platform.OS!=='ios') {returnnull }consthandleAppleSignIn=async () => {try {const { createdSessionId,setActive } =awaitstartAppleAuthenticationFlow()if (createdSessionId && setActive) {// Set the created session as the active sessionawaitsetActive({ session: createdSessionId })// Once the session is set as active,// if a callback function is provided, call it.// Otherwise, redirect to the home page. onSignInComplete ?onSignInComplete() :router.replace('/') } } catch (err:any) {// User canceled the sign-in flowif (err.code ==='ERR_REQUEST_CANCELED') returnAlert.alert('Error',err.message ||'An error occurred during Apple Sign-In')console.error('Apple Sign-In error:',JSON.stringify(err,null,2)) } }return ( <> <TouchableOpacitystyle={styles.appleButton} onPress={handleAppleSignIn}> <Textstyle={styles.appleButtonText}>Sign in with Apple</Text> </TouchableOpacity> {showDivider && ( <Viewstyle={styles.divider}> <Viewstyle={styles.dividerLine} /> <Textstyle={styles.dividerText}>OR</Text> <Viewstyle={styles.dividerLine} /> </View> )} </> )}conststyles=StyleSheet.create({ appleButton: { backgroundColor:'#000', padding:15, borderRadius:8, alignItems:'center', marginBottom:10, }, appleButtonText: { color:'#fff', fontSize:16, fontWeight:'600', }, divider: { flexDirection:'row', alignItems:'center', marginVertical:20, }, dividerLine: { flex:1, height:1, backgroundColor:'#ccc', }, dividerText: { marginHorizontal:10, color:'#666', },})
The following example demonstrates how to pass custom metadata that will be saved to the user's unsafe metadata during sign-up.
app/(auth)/sign-in.tsx
import { useRouter } from'expo-router'import { useSignInWithApple } from'@clerk/expo/apple'import { Alert, Platform, TouchableOpacity, Text } from'react-native'exportdefaultfunctionSignInPage() {const { startAppleAuthenticationFlow } =useSignInWithApple()constrouter=useRouter()// Only render on iOSif (Platform.OS!=='ios') {returnnull }constonAppleSignInPress=async () => {try {const { createdSessionId,setActive } =awaitstartAppleAuthenticationFlow({// Add information about the user to their unsafe metadata unsafeMetadata: { referralSource:'ios-app', signupDate:newDate().toISOString(), }, })if (createdSessionId && setActive) {// Set the created session as the active sessionawaitsetActive({ session: createdSessionId })// Once the session is set as active,// redirect the user to the home pagerouter.replace('/') } } catch (err:any) {// User canceled the authentication flowif (err.code ==='ERR_REQUEST_CANCELED') {return }Alert.alert('Error',err.message ||'An error occurred during Apple Sign-In')console.error('Apple Sign-In error:',JSON.stringify(err,null,2)) } }return ( <TouchableOpacityonPress={onAppleSignInPress}> <Text>Sign in with Apple</Text> </TouchableOpacity> )}