Troubleshooting
Most sign-in problems come from one of three places: the native build, the Apple Developer configuration, or the way a value moves from the app to the backend. Each entry below names the symptom, the cause that the library's source or error messages point to, and the fix. If your symptom is an error code, start with the table in Errors.
The native module is not found in Expo Go
Symptom: AppleAuth.isAvailable() returns false, or AppleAuth.signIn() rejects with ERR_NOT_AVAILABLE and a message that says the ExpoAppleSignIn native module is not linked.
Cause: The library ships a custom native module, and Expo Go does not include it. A development build made before you added the plugin lacks it too. A Metro reload cannot load a native module.
Fix: Add "expo-apple-sign-in" to plugins and build a development build.
npx expo prebuild --clean
npx expo run:ios
npx expo run:androidWeb in a browser does not need a native module.
The Sign in with Apple entitlement is missing
Symptom: Sign in fails on iOS after you added the plugin, or the Sign in with Apple capability is absent from the generated Xcode project.
Cause: The config plugin writes the entitlement com.apple.developer.applesignin with the value Default. A native project generated before you added the plugin does not contain it.
Fix: Regenerate the native projects so that the plugin runs again, then rebuild.
npx expo prebuild --clean
npx expo run:iosAlso enable the capability on the App ID, as described in Apple Developer.
Prebuild warns about expo-apple-authentication
Symptom: npx expo prebuild prints this warning:
» ios: ios.usesAppleSignIn: Install expo-apple-authentication to enable this feature https://docs.expo.dev/versions/latest/sdk/apple-authentication/#eas-buildCause: The Expo config sets ios.usesAppleSignIn. @expo/prebuild-config reads that key only in the fallback plugin it registers for expo-apple-authentication. When that package is not installed, the fallback prints this warning and changes nothing else. expo-apple-sign-in does not read the key, and its own config plugin writes the entitlement.
Fix: Delete ios.usesAppleSignIn from app.json or app.config.ts, keep "expo-apple-sign-in" in plugins, and run prebuild again.
ERR_NOT_CONFIGURED on Android or web
Cause: Android and web sign in through a Services ID. clientId or redirectUri is missing from AppleAuth.configure or from the options of useAppleAuth. iOS does not need either value.
Fix: Configure both values before the first sign-in.
import { AppleAuth } from 'expo-apple-sign-in'
AppleAuth.configure({
clientId: 'com.example.app.web',
redirectUri: 'https://app.example.com/auth/apple',
})clientId is the Services ID. redirectUri is an HTTPS URL registered for it. On Android and web, AppleAuth.isConfigured() returns true once both are set. On iOS it always returns true. See Android and Web.
Apple shows invalid_client or a redirect mismatch
Symptom: The Apple page in the Android WebView or the web popup reports invalid_client, or an error about the redirect URL, instead of the sign-in form.
Cause: On Android the library sends clientId as client_id and redirectUri as redirect_uri to https://appleid.apple.com/auth/authorize, unchanged. Apple compares them with the Services ID and the Return URLs registered in the Developer portal. On web the library passes redirectUri to Apple JS, or the current page URL without its hash when redirectUri has the same origin and path as the page. A clientId that is not a registered Services ID, or a redirect URL that is not registered as a Return URL on that Services ID, fails this comparison.
Fix: Open the Services ID in the Apple Developer portal, open its Sign in with Apple configuration, and register the exact domain and Return URL that you pass as redirectUri. The values must match character by character, including the scheme and the path. Then compare the clientId in your code with the Services ID. See Apple Developer.
Web redirect URI points at another origin
Symptom: On web, sign-in fails before Apple opens with ERR_NOT_CONFIGURED and a message that the web redirectUri origin must match the page, or the popup lands on a different host than your app.
Cause: In popup mode, Apple posts the result to the redirect URL, and that page must hand the result back to the page that opened the popup. The library checks that the origin of redirectUri equals the origin of the current page. An address on the main site, such as example.com, does not match an app served from a subdomain, such as web.example.com.
Fix:
- Register
https://web.example.com/auth/apple, the address on the host that serves your web app, as a Return URL on the Services ID. - Pass that URL to
AppleAuth.configureon web. Do not reuse the redirect that Android uses if it lives on another host. - Reload the web app.
Because the value differs by platform, choose it per platform when you configure:
import { AppleAuth } from 'expo-apple-sign-in'
import { Platform } from 'react-native'
AppleAuth.configure({
clientId: 'com.example.app.web',
redirectUri:
Platform.OS === 'web' ? 'https://web.example.com/auth/apple' : 'https://example.com/auth/apple',
})Name or email is null after the first sign-in
Cause: Apple sends the name and the email only the first time a person authorizes your app. Later sign-ins return null for every name field: givenName, familyName, middleName, namePrefix, nameSuffix, and nickname. The name is never inside the identity token. The library fills user.id and user.email from the token when it can, so the email usually remains.
Fix: Store the name in the first response, as shown in Usage. To test the first-time flow again, open Settings on the device, tap your name, tap Sign in with Apple, select your app, then tap Delete. On Android or web, open account.apple.com, select Sign-In & Security, then Sign in with Apple, and remove the app there. The next sign-in counts as a first authorization.
Supabase rejects the nonce
Cause: The library already hashes the nonce with SHA-256 before Apple sees it, and it returns the raw value on credential.nonce. Supabase hashes the raw value again and compares it with the nonce claim in the token. If you hash credential.nonce yourself and pass the digest, the comparison fails.
Fix: Pass credential.nonce unchanged.
import { createClient } from '@supabase/supabase-js'
import { AppleAuth } from 'expo-apple-sign-in'
const supabase = createClient('https://example.supabase.co', 'public-anon-key')
export async function signInToSupabase(): Promise<void> {
const credential = await AppleAuth.signIn()
const { error } = await supabase.auth.signInWithIdToken({
provider: 'apple',
token: credential.identityToken,
nonce: credential.nonce,
})
if (error) {
throw error
}
}signInWithSupabase does exactly this. See Supabase, including the Client IDs field in the Supabase dashboard.
The iOS Simulator cannot sign in
Symptom: The Apple sheet fails to complete on the iOS Simulator, usually as ERR_REQUEST_FAILED.
Cause: The system can report failed, notHandled, or notInteractive for a sign-in that cannot proceed, and the library maps all three to ERR_REQUEST_FAILED. A simulator without an Apple Account signed in cannot complete the flow.
Fix: Sign in with an Apple Account in the Settings app of the simulator, or test on a physical device.
A second sign-in rejects with ERR_REQUEST_FAILED
Symptom: On iOS or Android, AppleAuth.signIn() rejects with ERR_REQUEST_FAILED and a message that contains A Sign in with Apple request is already in progress.
Cause: The native module runs one sign-in at a time. A call made while the Apple sheet or the Android sign-in screen is still open rejects at once, and the first request continues.
Fix: Start a new sign-in only after the previous one settles. AppleButton ignores presses while its own sign-in runs, but it does not track a custom onPress handler, so set disabled while your handler runs. With useAppleAuth, disable your control while isLoading is true.
ERR_NOT_AVAILABLE on web
Cause: The page has no browser document, or the Apple JS SDK did not load or did not initialize. A content blocker or a Content Security Policy that blocks appleid.apple.com prevents the script from loading.
Fix: Allow scripts from appleid.apple.com and check the network tab for the SDK request. After a failed load the library removes the script tag, so the next call to AppleAuth.signIn() requests Apple JS again.
The browser blocks the Apple popup
Symptom: On web, AppleAuth.signIn() rejects with ERR_REQUEST_FAILED and the message The browser blocked the Apple sign-in popup. Call signIn from a click handler.
Cause: Browsers open a popup only in response to a user gesture such as a click. When signIn runs from an effect or a timer, the browser blocks the window and Apple JS rejects with popup_blocked_by_browser.
Fix: Call AppleAuth.signIn(), or the signIn function from useAppleAuth, inside the press or click handler. Without an onPress prop, AppleButton calls AppleAuth.signIn() from its own press handler.