useSignInWithApple()
Before you start
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 between sign-up and sign-in.
Returns
The useSignInWithApple() hook returns the startAppleAuthenticationFlow() method, which you can use to initiate the native Apple authentication flow.
startAppleAuthenticationFlow()
startAppleAuthenticationFlow() has the following function signature:
function startAppleAuthenticationFlow(
startAppleAuthenticationFlowParams?: StartAppleAuthenticationFlowParams,
): Promise<StartAppleAuthenticationFlowReturnType>Parameters
startAppleAuthenticationFlow() accepts the following parameters (StartAppleAuthenticationFlowParams):
- Name
unsafeMetadata?- Type
- SignUpUnsafeMetadata
- Description
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.
Returns
startAppleAuthenticationFlow() returns the following:
- Name
createdSessionId- Type
string | null- Description
The ID of the session that was created, if authentication is successful.
- Name
setActive?- Type
(params: SetActiveParams) => Promise<void>- Description
A method used to set the active session and/or organization. Accepts a SetActiveParams object.
Examples
Reusable component
The following example demonstrates how to use the useSignInWithApple() hook to manage the Apple authentication flow. Because the useSignInWithApple() hook automatically manages the between sign-up and sign-in, you can use this component for both your sign-up and sign-in pages.
import { useSignInWithApple } from '@clerk/clerk-expo'
import { useRouter } from 'expo-router'
import { Alert, Platform, StyleSheet, Text, TouchableOpacity, View } from 'react-native'
// Example props that you could pass to your button
interface AppleSignInButtonProps {
// Callback function that is called when the sign-in is complete
onSignInComplete?: () => void
// Whether to show a divider between the button and the text
showDivider?: boolean
}
export function AppleSignInButton({
onSignInComplete,
showDivider = true,
}: AppleSignInButtonProps) {
const { startAppleAuthenticationFlow } = useSignInWithApple()
const router = useRouter()
// Only render on iOS
if (Platform.OS !== 'ios') {
return null
}
const handleAppleSignIn = async () => {
try {
const { createdSessionId, setActive } = await startAppleAuthenticationFlow()
if (createdSessionId && setActive) {
// Set the created session as the active session
await setActive({ 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 flow
if (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 (
<>
<TouchableOpacity style={styles.appleButton} onPress={handleAppleSignIn}>
<Text style={styles.appleButtonText}>Sign in with Apple</Text>
</TouchableOpacity>
{showDivider && (
<View style={styles.divider}>
<View style={styles.dividerLine} />
<Text style={styles.dividerText}>OR</Text>
<View style={styles.dividerLine} />
</View>
)}
</>
)
}
const styles = 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',
},
})With custom metadata
The following example demonstrates how to pass custom metadata that will be saved to the user's unsafe metadata during sign-up.
import { useRouter } from 'expo-router'
import { useSignInWithApple } from '@clerk/clerk-expo'
import { Alert, Platform, TouchableOpacity, Text } from 'react-native'
export default function SignInPage() {
const { startAppleAuthenticationFlow } = useSignInWithApple()
const router = useRouter()
// Only render on iOS
if (Platform.OS !== 'ios') {
return null
}
const onAppleSignInPress = async () => {
try {
const { createdSessionId, setActive } = await startAppleAuthenticationFlow({
// Add information about the user to their unsafe metadata
unsafeMetadata: {
referralSource: 'ios-app',
signupDate: new Date().toISOString(),
},
})
if (createdSessionId && setActive) {
// Set the created session as the active session
await setActive({ session: createdSessionId })
// Once the session is set as active,
// redirect the user to the home page
router.replace('/')
}
} catch (err: any) {
// User canceled the authentication flow
if (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 (
<TouchableOpacity onPress={onAppleSignInPress}>
<Text>Sign in with Apple</Text>
</TouchableOpacity>
)
}Error handling
The useSignInWithApple() hook may throw errors in the following scenarios:
- User cancellation: The user cancels the authentication flow, resulting in an error with code
ERR_REQUEST_CANCELED. - Platform error: The hook is called on a non-iOS platform.
- Missing package: The
expo-apple-authenticationpackage is not installed. - Authentication failure: Apple authentication fails or the returned ID token is invalid.
Feedback
Last updated on