Skip to content

Quick start ​

Three steps take an installed expo-apple-sign-in to a working sign-in on iOS, Android and web: the config plugin, one AppleAuth.configure call, and an App.tsx that renders AppleButton and keeps the credential it returns. It assumes you have finished Installation and, for Android and web, created a Services ID and Return URL as described in Apple Developer.

1. Add the config plugin ​

List the plugin in app.json and rebuild the development client. The plugin enables the Sign in with Apple entitlement for iOS.

app.json
json
{
  "expo": {
    "plugins": ["expo-apple-sign-in"]
  }
}
bash
npx expo prebuild
npx expo run:ios

2. Configure Android and web ​

Android and web sign in through Apple's web flow, which identifies your app by a Services ID and sends the result to a registered HTTPS Return URL. Pass both to AppleAuth.configure once, before the first sign-in. On iOS the library uses the App ID and ignores these two values, so the same call is safe on every platform.

ts
import { AppleAuth } from 'expo-apple-sign-in'

AppleAuth.configure({
  clientId: 'com.example.app.web',
  redirectUri: 'https://app.example.com/auth/callback',
})

If either value is missing on Android or web, sign-in fails with ERR_NOT_CONFIGURED. On web, redirectUri must also have the same origin as the page; Web explains why.

3. Render the button ​

AppleButton runs AppleAuth.signIn() when pressed and reports the outcome through onSuccess, onCancel and onError. This App.tsx stores a short status line for each outcome:

App.tsx
tsx
import { useState, type ReactElement } from 'react'
import { StyleSheet, Text, View } from 'react-native'
import { AppleAuth, AppleButton, type AppleAuthError, type AppleCredential } from 'expo-apple-sign-in'

AppleAuth.configure({
  clientId: 'com.example.app.web',
  redirectUri: 'https://app.example.com/auth/callback',
})

export default function App(): ReactElement {
  const [status, setStatus] = useState('Signed out')

  const handleSuccess = (credential: AppleCredential): void => {
    setStatus(`Signed in as ${credential.user.email ?? credential.user.id ?? 'an Apple user'}`)
  }

  const handleError = (error: AppleAuthError): void => {
    setStatus(`Sign-in failed: ${error.code}`)
  }

  return (
    <View style={styles.container}>
      <AppleButton onSuccess={handleSuccess} onCancel={() => setStatus('Canceled')} onError={handleError} />
      <Text>{status}</Text>
    </View>
  )
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
    gap: 16,
    padding: 24,
  },
})

A dismissed sheet or popup calls onCancel instead of onError, so cancellation never shows up as a failure. The button defaults to the black style and the Sign in with Apple label; Apple button covers the other styles, labels and sizes.

What the credential contains ​

onSuccess receives an AppleCredential with the same fields on every platform:

FieldTypeContents
identityTokenstringThe JWT that Apple signed. Send it to your auth provider or your server.
authorizationCodestring or nullA single-use code that a server can exchange with Apple for tokens.
noncestringThe raw nonce. The token's nonce claim holds its SHA-256 hash, so pass this value to Supabase or Firebase as it is.
statestring or nullThe state value Apple sent back.
user.idstring or nullApple's stable identifier for the user, the sub claim of the identity token.
user.emailstring or nullThe user's email, which can be a private relay address.
user.givenName, user.familyNamestring or nullThe user's given name and family name.
user.middleName, user.namePrefix, user.nameSuffix, user.nicknamestring or nullThe other parts of the name. Only iOS fills them, and Android and web return null.
realUserStatus'unknown', 'likelyReal' or 'unsupported'Apple's estimate of whether the user is a real person. Android and web always report 'unknown'.

Apple includes the name and email only the first time a user authorizes your app, so save them on that first sign-in. When Apple leaves out the user id or email, the library reads them from the identity token's claims.

Next steps ​

The credential is only useful once a backend trusts it. To sign the user in to an auth service, follow the page for Supabase, Clerk or Firebase. To verify the token on your own server, read Backend verification. For a custom button with loading and error state, use the useAppleAuth hook.

Released under the MIT License.