Bryan Primus

Expo Sign In with Apple

4 min read | Publication date not available

Authentication Flow Diagaram

User → App Frontend → Provider (Apple/Google) → App Frontend → Backend Authentication Service → Database → App Frontend (Authenticated)

Note: A paid Apple Developer account is required to implement Sign In with Apple.

Installation

We will start with iOS implementation and then continue with android later

Create a new expo app if you haven’t had existing project

Resetting the project is optional, but we’ll do it for simplicity in this guide.

bun create expo

cd app
bun reset-project
git commit -m "feat: reset project template"

This implementation doesn’t work with expo go, therefore we need to install development builds. First install expo-dev-client

bunx expo add expo-dev-client

Since we are opting in to native development builds and we want to use continuous native integration, we will add ios and android folders to .gitignore

echo "ios/" >> .gitignore
echo "android/" >> .gitignore

Run prebuild to generate native folder and its code

bunx expo prebuild -p ios

Configure bundleIdentifier for iOS

I usually use a format based on domain name.

  • Say the domain ends with .com for example book.com I will use com.book.mobile

  • And if the domain ends with .app for example book.app I will use com.app.book

This will matter when registering the app to the store, and we need to make sure that it is unique or hasn’t been registered before

Next We will be using package from expo called expo-apple-authentication

Install the package

bunx expo add expo-apple-authentication

Configure the package

On app.json add usesAppleSignIn to true and add the plugin.

{
  "expo": {
    "ios": {
      "usesAppleSignIn": true
    },
    "plugins": ["expo-apple-authentication"]
  }
}

After adding all those configuration, run prebuild again

bunx expo prebuild -p ios

At this point we should commit our changes

git commit -m "feat: setup development builds and authentication packages"

Run the app

Now we need to make sure everything configured correctly by running the app and make sure there is no error.

When first time running the app, it will ask for paid apple developer team for signing the app. Make sure to choose the correct one if you have more than one.

Testing on both iOS Simulator and real physical device is encouraged

Run on iOS Simulator

bunx expo run:ios

Run on physical device

Try run this command

bunx expo run:ios --device

This will throw error if you haven’t setup your iPhone and Signing on XCode. Therefore open XCode for this project first.

cd ios/
open [project-name].xcodeproj

Let the indexing of the project done, make sure you select your iPhone device, Go to Signing & Capabilities, make sure automatic signing already configured with the correct account and try running the command again

bunx expo run:ios --device

If this is your first time using your iPhone device, it will register it automatically

Check all listed device here. https://developer.apple.com/account/resources/devices/list

Running above step correctly will also register a new identifier here https://developer.apple.com/account/resources/identifiers/list

Check in the list, there should be a new identified called XC [your.bundle.identifier], with Sign In With Apple capability.

It will also add your “appleTeamId”: “[YOUR_APPLE_TEAM_ID]” to app.json

If you have never configure certificates, it will also create one here https://developer.apple.com/account/resources/certificates/list, note that it will create certificate based on env, development or production

Usage

Code from expo doc

Apply this code to your root app

import * as AppleAuthentication from 'expo-apple-authentication';
import { View, StyleSheet } from 'react-native';

export default function App() {
  return (
    <View style={styles.container}>
      <AppleAuthentication.AppleAuthenticationButton
        buttonType={AppleAuthentication.AppleAuthenticationButtonType.SIGN_IN}
        buttonStyle={AppleAuthentication.AppleAuthenticationButtonStyle.BLACK}
        cornerRadius={5}
        style={styles.button}
        onPress={async () => {
          try {
            const credential = await AppleAuthentication.signInAsync({
              requestedScopes: [
                AppleAuthentication.AppleAuthenticationScope.FULL_NAME,
                AppleAuthentication.AppleAuthenticationScope.EMAIL,
              ],
            });
            console.log(credential);
            // signed in

            // FROM THIS PART 
            // WE NEED TO USE `credential` returned AND INTEGRATE IT TO OUR BACKEND OF CHOICE
            // AND THEN MANAGE THE SESSION USING OUR BACKEND
          } catch (e: any) {
            if (e.code === 'ERR_REQUEST_CANCELED') {
              // handle that the user canceled the sign-in flow
            } else {
              // handle other errors
            }
          }
        }}
      />
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    alignItems: 'center',
    justifyContent: 'center',
  },
  button: {
    width: 200,
    height: 44,
  },
});

If everything working as expected, you should see Sign in with Apple button and if you click it, it will open a native modal to sign in using your apple id.

Try signing in and check your console log to check the credential

For more configuration details, check https://docs.expo.dev/versions/latest/sdk/apple-authentication

TODO

  • Example backend implementation using InstantDb
  • Example backend implementation using Convex
  • Android client setup

Daily News

I like to read only 3 news every day