Making Apple Authentication work with Firebase Auth in React Native (Expo)

Making Apple Authentication work with Firebase Auth in React Native (Expo)

For Filterlist, my iOS app to discover Instagram filters, I recently implemented Facebook authentication. Apple requires you to also implement Apple Authentication when you use other 3rd party auth providers. I wasted/invested some hours to get it working, and here's what helped.

To be honest, I still haven't managed to get Apple Authentication working inside the Expo client. I always get the following error:

The audience in ID Token [host.exp.Exponent] does not match the expected audience com.vandevliet.XXX.

If anyone has a solution for this error, please let me know, as it would be great to get Apple Authentication working on the simulator or in the Expo client on my physical device.

However, after a ton of building releasing on Testflight, I finally managed to get Apple Auth working with Firebase on React Native.

Just follow the full guide you find in the Expo docs to install everything. It goes smoother than expected. But then when I build my app the first time to distribute it to my testers, they couldn't use Sign in With Apple to authenticate.

The error I always got in Sentry was:

The nonce in ID Token "MY CUSTOM STRING" does not match the SHA256 hash of the raw nonce "MY CUSTOM STRING" in the request.

The trick to solve this error is to sha256 encode the custom string when you pass it as a nonce to the signInAsync method.

This is what the full Apple Authentication Button looks like.


    <AppleAuthentication.AppleAuthenticationButton
      buttonType={AppleAuthentication.AppleAuthenticationButtonType.SIGN_IN}
      buttonStyle={AppleAuthentication.AppleAuthenticationButtonStyle.BLACK}
      onPress={async () => {
        try {
          const credential = await AppleAuthentication.signInAsync({
            requestedScopes: [
              AppleAuthentication.AppleAuthenticationScope.FULL_NAME,
              AppleAuthentication.AppleAuthenticationScope.EMAIL,
            ],
            nonce: sha256("CUSTOM STRING"),
          })

          const authCredential = new firebase.auth.OAuthProvider(
            "apple.com"
          ).credential({
            idToken: credential.identityToken,
            rawNonce: "CUSTOM STRING", // notice this isn't encoded
          })

          try {
            await firebase.auth().signInWithCredential(authCredential)
          } catch (e) {
            Sentry.captureException(e)
          }
          // signed in
        } catch (e) {
          Sentry.captureException(e)
          if (e.code === "ERR_CANCELED") {
            // handle that the user canceled the sign-in flow
          } else {
            // handle other errors
          }
        }
      }}
    />
    ```

The trick is to 256 encode it when you pass it in the signInAsync method, but pass it raw (the keyname "rawNonce" might suggest it) to the OauthProvider credential. To sha-256 the string, I used this package.

And now my Firebase dashboard looks like this 😍