Firebase
Firebase Authentication signs a user in with an Apple identity token plus the raw nonce that produced it. expo-apple-sign-in does not import a Firebase SDK. It gives you toFirebaseAppleCredential, which maps an Apple credential to a plain object, and signInWithFirebase, which runs the Apple sign-in and hands that object to a function you write. This page covers the console settings and two ways to write that function, one for the Firebase JS SDK and one for React Native Firebase.
Configure the Firebase console
Open Security, then Authentication, then Sign-in method, and enable Apple.
- Apps that run only on Apple platforms can leave the Services ID, Team ID, private key, and key ID empty.
- Android and web need the Services ID you pass as
clientIdtoAppleAuth.configure. Under OAuth code flow configuration, also enter the Team ID, the private key, and the key ID. The Apple Developer page explains where these values come from, and the private key never belongs in your app or your repository. - Android also needs the SHA-1 fingerprint of your app registered in the Firebase project.
How the adapter fits
toFirebaseAppleCredential(credential) returns { providerId: 'apple.com', token, rawNonce }, where token is the identity token and rawNonce is the raw nonce from the credential. signInWithFirebase(signInWithCredential, options?) calls AppleAuth.signIn(options), throws an AppleAuthError with code ERR_MISSING_IDENTITY_TOKEN if Apple returns no token, and then calls the function you pass with that object. It resolves with { credential, data }, where data is whatever your function returned.
Firebase compares the hash of rawNonce with the nonce claim in the token, so rawNonce must be the raw value. Do not hash it. Because the adapter calls AppleAuth.signIn itself, trigger it from onPress of AppleButton. When onPress is set, the button does not start a second sign-in.
Firebase JS SDK
With the firebase package, create an OAuthProvider('apple.com') and build the credential from the token and raw nonce.
npx expo install firebaseyarn expo install firebasepnpm expo install firebasebunx expo install firebaseThe sample assumes lib/firebase.ts initializes the app. Configure Auth persistence for React Native as the Firebase documentation describes, which the adapter does not depend on.
import { initializeApp } from 'firebase/app'
export const app = initializeApp({
apiKey: process.env.EXPO_PUBLIC_FIREBASE_API_KEY,
appId: process.env.EXPO_PUBLIC_FIREBASE_APP_ID,
projectId: process.env.EXPO_PUBLIC_FIREBASE_PROJECT_ID,
})import { getAuth, OAuthProvider, signInWithCredential } from 'firebase/auth'
import { AppleButton, isCancelledError, signInWithFirebase } from 'expo-apple-sign-in'
import type { TFirebaseAppleCredential } from 'expo-apple-sign-in'
import { useState, type ReactElement } from 'react'
import { Text, View } from 'react-native'
import { app } from '../lib/firebase'
const signInWithApple = (apple: TFirebaseAppleCredential): Promise<unknown> => {
const provider = new OAuthProvider(apple.providerId)
const credential = provider.credential({ idToken: apple.token, rawNonce: apple.rawNonce })
return signInWithCredential(getAuth(app), credential)
}
export function AppleSignIn(): ReactElement {
const [message, setMessage] = useState<string | null>(null)
const handlePress = async (): Promise<void> => {
setMessage(null)
try {
await signInWithFirebase(signInWithApple)
} catch (error) {
if (!isCancelledError(error)) {
setMessage(error instanceof Error ? error.message : 'Sign in with Apple failed.')
}
}
}
return (
<View>
<AppleButton onPress={handlePress} />
{message ? <Text>{message}</Text> : null}
</View>
)
}React Native Firebase
With @react-native-firebase/auth, the credential comes from AppleAuthProvider.credential(identityToken, nonce). Install and configure the app and auth packages as the React Native Firebase documentation describes, then pass the mapped fields to that call.
import { AppleAuthProvider, getAuth, signInWithCredential } from '@react-native-firebase/auth'
import { AppleButton, isCancelledError, signInWithFirebase } from 'expo-apple-sign-in'
import type { TFirebaseAppleCredential } from 'expo-apple-sign-in'
import { useState, type ReactElement } from 'react'
import { Text, View } from 'react-native'
const signInWithApple = (apple: TFirebaseAppleCredential): Promise<unknown> => {
const credential = AppleAuthProvider.credential(apple.token, apple.rawNonce)
return signInWithCredential(getAuth(), credential)
}
export function AppleSignIn(): ReactElement {
const [message, setMessage] = useState<string | null>(null)
const handlePress = async (): Promise<void> => {
setMessage(null)
try {
await signInWithFirebase(signInWithApple)
} catch (error) {
if (!isCancelledError(error)) {
setMessage(error instanceof Error ? error.message : 'Sign in with Apple failed.')
}
}
}
return (
<View>
<AppleButton onPress={handlePress} />
{message ? <Text>{message}</Text> : null}
</View>
)
}Use the pieces separately
If you need the Apple credential before you decide to sign in with Firebase, call AppleAuth.signIn() yourself and map it with toFirebaseAppleCredential. The result has the same shape that signInWithFirebase passes to your function.
import { AppleAuth, toFirebaseAppleCredential } from 'expo-apple-sign-in'
import type { TFirebaseAppleCredential } from 'expo-apple-sign-in'
export async function getFirebaseAppleCredential(): Promise<TFirebaseAppleCredential> {
const credential = await AppleAuth.signIn()
return toFirebaseAppleCredential(credential)
}Apple sends the user's name only on the first authorization. Apple never puts it inside the identity token, so save credential.user.givenName and credential.user.familyName in your own profile right after the first sign-in. The Usage page lists every credential field.