{ }
Published on

Configure Firebase Auth with Apple Login in an Expo App (2025 Guide)

Authors
  • avatar
    Name
    Ahmed Farid
    Twitter
    @

CAUTION

Apple requires “Sign in with Apple” if you offer other social logins. Follow the checklist to stay compliant and avoid App Store rejections.

This tutorial shows how to power Sign in with Apple using Firebase Auth inside an Expo SDK 50 project. We will:

  1. Register identifiers and keys in Apple Developer portal.
  2. Enable Apple provider in Firebase console.
  3. Implement the login flow with expo-apple-authentication and @react-native-firebase/auth (or web SDK v10).
  4. Handle first-time name / email, account linking, and token refresh.

Table of Contents

1. Prerequisites & Terminology

  • Expo SDK 50 (managed or bare).
  • macOS with Xcode 15.
  • Firebase project already created.
TermMeaning
Service IDApple OAuth client identifier used by Firebase │
Key IDIdentifier for the .p8 private key │
Client SecretJWT signed with the private key—Firebase generates automatically │

2. Create Identifiers & Keys in Apple Developer

  1. Certificates, IDs & Profiles → Identifiers: Create an App ID (e.g. com.yourco.applefirebase). Enable Sign in with Apple capability.
  2. Keys → +: New key → enable Sign in with Apple, link to App ID, download .p8. Note Key ID.
  3. Identifiers → Services IDs: New service ID com.yourco.applefirebase.service. Under Web Auth config add redirect URL: https://YOUR_FIREBASE_PROJECT.firebaseapp.com/__/auth/handler.

3. Enable Apple Provider in Firebase

Firebase Console → Authentication / Sign-in method → Apple → Enable.

Enter:

  • Services ID from step 3.
  • Apple Team ID.
  • Key ID.
  • Upload .p8.
  • Leave redirect default (https://.../__/auth/handler).

Firebase creates the client secret JWT and rotates automatically.

4. Install Dependencies in Expo Project

yarn add expo-apple-authentication @react-native-firebase/app @react-native-firebase/auth
# Or web SDK if you target Expo Web
yarn add firebase@10

Add Apple entitlement via app.json:

{
  "expo": {
    "ios": {
      "bundleIdentifier": "com.yourco.applefirebase",
      "usesAppleSignIn": true,
    },
  },
}

Run npx expo prebuild --platform ios to regenerate native project.

5. Initialise Firebase SDK

// src/lib/firebase.ts
import { initializeApp } from '@react-native-firebase/app'
import auth from '@react-native-firebase/auth'

const firebaseConfig = {
  apiKey: '...',
  authDomain: 'YOUR_PROJECT.firebaseapp.com',
  projectId: 'YOUR_PROJECT',
  appId: '1:123456:web:abcdef',
}

export const app = initializeApp(firebaseConfig)
export { auth }

6. Implement Sign in with Apple Flow

import * as Apple from 'expo-apple-authentication'
import { AppleAuthRequestResponse } from 'expo-apple-authentication'
import { auth } from '@/lib/firebase'
import { OAuthProvider, signInWithCredential } from '@react-native-firebase/auth'

async function appleLogin() {
  const appleResponse: AppleAuthRequestResponse = await Apple.signInAsync({
    requestedScopes: [
      Apple.AppleAuthenticationScope.FULL_NAME,
      Apple.AppleAuthenticationScope.EMAIL,
    ],
  })

  if (!appleResponse.identityToken) throw new Error('Apple Sign-in failed – no identity token')

  // 1. Create Firebase credential
  const provider = new OAuthProvider('apple.com')
  const credential = provider.credential({
    idToken: appleResponse.identityToken,
    rawNonce: appleResponse.nonce, // Expo returns a secure nonce automatically
  })

  // 2. Sign in / link
  const result = await signInWithCredential(auth(), credential)

  // 3. Update display name on first login
  if (appleResponse.fullName?.givenName && result.additionalUserInfo?.isNewUser) {
    await result.user.updateProfile({
      displayName: `${appleResponse.fullName.givenName} ${appleResponse.fullName.familyName}`,
    })
  }
}

Notes:

  • rawNonce is required by Firebase to mitigate replay attacks.
  • Firebase handles token refresh and stores in device secure storage.

7. Handling Account Linking with Email/Password

If user previously created a password account with the same email:

try {
  await signInWithCredential(auth(), credential)
} catch (err: any) {
  if (err.code === 'auth/account-exists-with-different-credential') {
    const methods = await auth().fetchSignInMethodsForEmail(err.email)
    // prompt user to log in with method[0] then linkWithCredential
  }
}

8. Supporting Expo Web (Optional)

On web, use Firebase signInWithPopup(new OAuthProvider('apple.com')). Apple restricts popup to Safari 14+. Consider fallback to Redirect flow.

9. Testing & Deployment

  1. Simulator with signed-in Apple ID supports Sign in with Apple.
  2. Test invalid credential by revoking key in Apple portal → expect Firebase 400.
  3. App Store listing: add Sign in with Apple demo video and privacy text.

10. Troubleshooting

ErrorFix
invalid_client / code 400Services ID mismatch between Firebase & Apple
auth/missing-noncePass rawNonce from Expo response
identityToken nullUser cancelled or iCloud not logged in

11. Security & Compliance Checklist

usesAppleSignIn: true in app.json.
✅ Provide Continue with Apple button equal prominence.
✅ Implement account deletion as per §5.1.1 App Store Review.
✅ Hide email if Apple returns email === null.

12. Further Reading & Resources

  • Firebase docs: Apple provider.
  • Expo expo-apple-authentication docs.
  • Apple WWDC 2024: What’s new in Sign in with Apple.

13. Conclusion

You now have secure Sign in with Apple integrated with Firebase Auth in your Expo app—compliant, token-safe, and production-ready. Ship it 🚀