Skip to main content
Docs

Sign in with Apple

This guide will teach you how to add native Sign in with Apple to your Clerk Expo application.

Note

Apple Sign-In works on both iOS Simulators and physical devices. However, physical devices provide full functionality including biometric authentication (Face ID/Touch ID), while simulators have limited support. Always test on a physical device before releasing to production.

Add your Native Application

Add your iOS application to the Native Applications page in the Clerk Dashboard. You will need your iOS app's App ID Prefix (Team ID) and Bundle ID.

Enable Apple as a social connection

  1. In the Clerk Dashboard, navigate to the SSO Connections page.
  2. Select Add connection and select For all users.
  3. In the Choose provider dropdown, select Apple.
  4. Ensure that Enable for sign-up and sign-in is toggled on.

Note

Apple provides a privacy feature called Hide My Email, allowing users to sign in to your app with Apple without disclosing their actual email addresses. Instead, your instance receives an app-specific email address that forwards any emails to the user's real address. To be able to send emails properly to users with hidden addresses, you must configure an additional setting in the Apple Developer portal. See Configure Email Source for Apple Private Relay for more information.

Install dependencies

The Expo Apple Authentication library provides access to Apple's native Sign in with Apple functionality from your Expo app.

Run the following command to install the library:

terminal
npx expo install expo-apple-authentication
terminal
pnpm dlx expo install expo-apple-authentication
terminal
yarn dlx expo install expo-apple-authentication
terminal
bun x expo install expo-apple-authentication

Add expo-apple-authentication to your app config

Add the expo-apple-authentication plugin to your app.json or app.config.js.

app.json
{
  "expo": {
    "plugins": ["expo-apple-authentication"]
  }
}
app.config.js
export default {
  expo: {
    plugins: ['expo-apple-authentication'],
  },
}

Build your authentication flow

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.

components/AppleSignInButton.tsx
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',
  },
})

Create a native build

Create a native build with EAS Build or a local prebuild, since Apple Authentication is not supported in Expo Go.

terminal
# Using EAS Build
eas build --platform ios

# Or using local prebuild
npx expo prebuild && npx expo run:ios --device

Feedback

What did you think of this content?

Last updated on