This guide walks through configuring Apple Sign In for Sobers on iOS.
Apple Sign In uses a native authentication flow on iOS. The app obtains an identity token directly from Apple's native APIs and exchanges it with Supabase using signInWithIdToken().
Platform Support:
- iOS: Native Sign in with Apple via
expo-apple-authentication✅ - Android: Not supported (Apple only supports Apple platforms and web)
- Web: Not implemented (would require OAuth secret key rotation every 6 months)
Architecture Decision:
We chose iOS-only support for simplicity:
- No OAuth secret key rotation maintenance (keys expire every 6 months)
- Simpler implementation using the official Expo package
- App Store compliance achieved (required when offering other social logins)
- Apple Developer Program membership ($99/year)
- Access to Apple Developer Console
- Access to Supabase Dashboard
- Expo project with EAS Build configured
- Go to Apple Developer Console → Certificates, Identifiers & Profiles
- Select Identifiers → Click + to create new
- Select App IDs → Continue
- Select App → Continue
- Configure:
- Description:
Sobers - Bundle ID:
com.volvox.sobrietywaypoint(Explicit)
- Description:
- Scroll to Capabilities and enable Sign in with Apple
- Click Continue → Register
For native iOS sign-in, you only need your Bundle ID: com.volvox.sobrietywaypoint
Why so simple? Native iOS sign-in uses Apple's built-in authentication APIs. Unlike web OAuth flows, you don't need:
- A Services ID (web OAuth only)
- A private key (web OAuth only)
- Secret key rotation (web OAuth only—keys expire every 6 months)
-
Go to your Supabase Dashboard
-
Select your project → Authentication → Providers → Apple
-
Toggle Enable Sign in with Apple
-
Configure the fields:
Field Value Notes Client IDs com.volvox.sobrietywaypointYour iOS bundle ID Secret Key (for OAuth) (leave empty) Not needed for native iOS flow Allow users without an email Off Rarely needed; Apple always provides a real or relay email -
Click Save
Note: The "Allow users without an email" toggle is for rare edge cases where email is genuinely absent. Apple always provides either the user's real email or a valid private relay address (e.g.,
abc123@privaterelay.appleid.com). Private relay addresses are real, routable emails that work normally—see Private Email Relay for details.
The following configuration is already in place:
// app.config.ts
export default ({ config }: ConfigContext): ExpoConfig => ({
...config,
ios: {
bundleIdentifier: 'com.volvox.sobrietywaypoint',
usesAppleSignIn: true, // Enable Apple Sign In capability
// ... other iOS config
},
plugins: [
'expo-router',
'expo-apple-authentication', // Native Sign in with Apple support
// ... other plugins
],
});The package is already installed:
# expo-apple-authentication is included in the project
pnpm list expo-apple-authenticationThe AppleSignInButton component (components/auth/AppleSignInButton.tsx) is self-contained:
- Returns
nullon non-iOS platforms (no conditional rendering needed in parent) - Handles the entire authentication flow internally
- Exchanges Apple identity token with Supabase via
signInWithIdToken - Profile creation is handled by AuthContext's existing
onAuthStateChangelistener - Theme-aware button styling (black in light mode, white in dark mode)
import { AppleSignInButton } from '@/components/auth/AppleSignInButton';
// In login/signup screens:
<AppleSignInButton
onError={(error) => {
Alert.alert('Error', error.message);
}}
/>;- User taps the Apple Sign In button
expo-apple-authenticationshows native Face ID/Touch ID/Password prompt- Apple returns identity token after successful authentication
- Component exchanges token with Supabase via
signInWithIdToken - Supabase validates token server-side and creates/retrieves user
- AuthContext's
onAuthStateChangelistener detects new session createOAuthProfileIfNeededcreates profile if needed- User is redirected to onboarding (new user) or main app (returning user)
The button follows Apple Human Interface Guidelines:
- Uses Apple's native
AppleAuthenticationButtoncomponent - Adapts to current theme: BLACK style in light mode, WHITE style in dark mode
- 12px corner radius to match other buttons in the app
- 50pt height (meets Apple's minimum 44pt tap target)
Apple only provides the user's name on the first sign-in. The existing createOAuthProfileIfNeeded function in AuthContext handles this:
// From AuthContext.tsx - already implemented
const createOAuthProfileIfNeeded = async (user: User): Promise<void> => {
// ... checks for existing profile ...
// Extract name from user metadata (available on first sign-in)
const fullName = user.user_metadata?.full_name;
const nameParts = fullName?.split(' ').filter(Boolean);
const firstName = nameParts?.[0] || null; // May be null - collected during onboarding
// Create profile with available data
await supabase.from('profiles').insert({
id: user.id,
email: user.email || '',
first_name: firstName,
// ...
});
};If the name isn't available (subsequent sign-ins or user declined to share), the user is directed to onboarding where they enter their name.
Apple allows users to hide their real email address. When they do, you'll receive an email like:
abc123def456@privaterelay.appleid.com
This is a real, working email address that forwards to the user's actual email. The app handles these normally—no special handling needed.
Apple Sign In requires a development build - it won't work in Expo Go.
# Create a development build for iOS
eas build --platform ios --profile development
# Or build locally (requires Xcode)
npx expo run:ios- Install the development build on a real iOS device (Apple Sign In requires a real device and does not work reliably in the Simulator)
- Tap "Sign in with Apple" button
- Verify Face ID/Touch ID/Password prompt appears
- Authenticate with your Apple ID
- Confirm user is created in Supabase Auth dashboard
- Verify profile is created in
profilestable - Test returning user flow (sign out, sign back in)
To get the name prompt again for testing:
- Go to Settings → Apple ID → Password & Security → Apps Using Apple ID
- Find and remove "Sobers"
- Sign in again to get the first-time experience
- Verify your bundle ID matches in Apple Developer Console and Supabase
- Ensure Apple provider is enabled in Supabase
- Apple Sign In does not work reliably in the Simulator—always test on a real device
- Ensure
usesAppleSignIn: trueis in app.config.ts - Verify
expo-apple-authenticationplugin is included
- Apple only provides the name on the first sign-in
- This is expected behavior for returning users
- The onboarding flow collects the name if not available
- User chose to hide their email—use the relay address Apple provides
- The relay address works like a normal email
- The component returns
nullon non-iOS platforms (Android, web) - Verify you're testing on iOS
- Apple's identity tokens are short-lived and validated server-side by Supabase
- No private keys are stored client-side
- The native flow is more secure than OAuth redirect (no key rotation needed)
If your app uses any third-party social login (Google, Facebook, etc.), Apple requires you to also offer Sign in with Apple. From Apple's App Store Review Guidelines:
Apps that use a third-party or social login service to set up or authenticate the user's primary account with the app must also offer Sign in with Apple as an equivalent option.
This implementation satisfies that requirement.
components/auth/AppleSignInButton.tsx- Self-contained Apple Sign In buttoncontexts/AuthContext.tsx- Auth context (handles profile creation via onAuthStateChange)app/login.tsx- Login screen with Apple buttonapp/signup.tsx- Signup screen with Apple buttonapp.config.ts- Expo configuration with Apple Sign In capability