expo: [expo-apple-authentication] Sign In With Apple won't work on Expo Go and Firebase due to wrong audience (aud) in identityToken JWT as `"aud": "host.exp.Exponent"` returned by Apple after signInAsync()

Summary

Tools like Firebase that manage authentication for you only allow for one Service ID in the project (as shown below) CleanShot 2022-02-02 at 00 51 36@2x

However, the Service ID when testing on an React Native Expo Managed project is host.exp.Exponent as Sign in with Apple is registered via Expo. But, it should be com.myapp.name instead. However, due to Firebase’s limitation, I have to choose to make my app work only in testing or production, or create different apps for testing and production, which is absurd. If I don’t do that I’ll get the error like the one below: CleanShot 2022-02-02 at 00 54 47@2x

Not sure whether to post this here or somewhere else but the Firebase web UI is not open-sourced so they don’t have a Github.

Managed or bare workflow? If you have ios/ or android/ directories in your project, the answer is bare!

managed

What platform(s) does this occur on?

iOS

SDK Version (managed workflow only)

44

Environment

>> expo diagnostics

Expo CLI 5.0.3 environment info:
    System:
      OS: macOS 12.1
      Shell: 5.8 - /bin/zsh
    Binaries:
      Node: 14.18.1 - ~/.nvm/versions/node/v14.18.1/bin/node
      Yarn: 1.22.17 - ~/.nvm/versions/node/v14.18.1/bin/yarn
      npm: 6.14.15 - ~/.nvm/versions/node/v14.18.1/bin/npm
    Managers:
      CocoaPods: 1.11.2 - /usr/local/bin/pod
    SDKs:
      iOS SDK:
        Platforms: DriverKit 21.2, iOS 15.2, macOS 12.1, tvOS 15.2, watchOS 8.3
    IDEs:
      Xcode: 13.2.1/13C100 - /usr/bin/xcodebuild
    npmPackages:
      expo: ~44.0.0 => 44.0.5 
      react: 17.0.1 => 17.0.1 
      react-dom: 17.0.1 => 17.0.1 
      react-native: 0.64.3 => 0.64.3 
      react-native-web: 0.17.1 => 0.17.1 
    npmGlobalPackages:
      eas-cli: 0.38.3
      expo-cli: 5.0.3
    Expo Workflow: managed

Reproducible demo

  const signInWithApple = async () => {
    const nonce = Math.random().toString(36).substring(2, 10);

    try {
      const hashedNonce = await Crypto.digestStringAsync(Crypto.CryptoDigestAlgorithm.SHA256, nonce);
      const appleCredential = await AppleAuthentication.signInAsync({
        requestedScopes: [
          AppleAuthentication.AppleAuthenticationScope.FULL_NAME,
          AppleAuthentication.AppleAuthenticationScope.EMAIL
        ],
        nonce: hashedNonce
      });
      const { identityToken } = appleCredential;
      const provider = new OAuthProvider('apple.com');
      const credential = provider.credential({
        idToken: identityToken!,
        rawNonce: nonce
      });
      signInWithCredential(firebaseAuth, credential);
    } catch (error: any) { 
      Alert.alert(error.name, error.message)
    }
};

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Reactions: 1
  • Comments: 25 (1 by maintainers)

Most upvoted comments

One workaround in a development environment is to do this:

The only thing that helped was setting optional Services ID to host.exp.Exponent in Firebase Console -> Authentication -> Sign-in method -> Apple.

From: https://martinliptak.medium.com/thanks-for-the-article-ec172f979048

@charlestbell It’s done under Firebase’s “project settings”. I only use Expo Go during development and for that purpose adding the additional “app” with Expo Go’s bundle ID worked for me.

Screenshot 2022-08-07 at 13 41 52

Another option is to simply add another iOS app to the Firebase project with Bundle ID host.exp.Exponent. That way Firebase will accept the bundle ID as a valid audience. I don’t know if this solution has any downsides.

I’ve also been able to make it work with Supabase only by adding host.exp.Exponent to the allowed client ID’s. I imagine for dev and prod environments, I’ll just have two separate Supabase projects to handle that, even tho it would be annoying to have all configurations duplicated…

I did neither of them. I just sucked it up and didn’t do anything.

On Sun, Apr 24, 2022 at 3:59 PM, Pedro Netto < @.*** > wrote:

Thanks for letting me know @ ansh ( https://github.com/ansh ) 🤝 Which route did you go? Could you maybe provide any details on how you made it happen? Thanks!

— Reply to this email directly, view it on GitHub ( https://github.com/expo/expo/issues/16162#issuecomment-1107917241 ) , or unsubscribe ( https://github.com/notifications/unsubscribe-auth/AB6T25KPUEVNQZTXMCAZYI3VGWY2DANCNFSM5NLNYGOQ ). You are receiving this because you were mentioned. Message ID: <expo/expo/issues/16162/1107917241 @ github. com>

Right now, expo-apple-authentication’s signInAsync() function returns an object that contains the identityToken which is what we really need to authenticate using Firebase. This identityToken is just a simple JWT with the payload data for the "aud": "host.exp.Exponent". This is the problem. There is no way to change the data sent to signInAsync() or any option to customize what aud (audience) is received by Apple. So when Apple gets our sign in request, they just return the same aud (audience) back to us in the identityToken. However, one fix from Expo’s side could be is to help us define the aud or Service ID in app.json and that way signInAsync() can use that instead of using “host.exp.Exponent”. This is a good fix since using “host.exp.Exponent” does not seem like a good idea anyway since user data will be going through Expo’s Service ID and Expo’s account on Apple Developer.

That’s what I did. Didn’t realize that’s what you are asking for. But essentially you will have to change that each time you want to run dev mode or prod. On Mon, Apr 25 2022 at 05:29, Pedro Netto < @.*** > wrote: One workaround in development environment is to do this: > > > The only thing that helped was setting optional Services ID to > host.exp.Exponent in Firebase Console -> Authentication -> Sign-in method > -> Apple. > > From: https://martinliptak.medium.com/thanks-for-the-article-ec172f979048 — Reply to this email directly, view it on GitHub ( #16162 (comment) ) , or unsubscribe ( https://github.com/notifications/unsubscribe-auth/AB6T25KFID6VAQOXYBLP73TVGZXY5ANCNFSM5NLNYGOQ ). You are receiving this because you were mentioned. Message ID: <expo/expo/issues/16162/1108388415 @ github. com>

Worked for me too. Also you shouldn’t have to change it if you use a different firebase project for prod vs test.

Regarding dev and prod with Supabase, for local development apparently you need to put host.expo.Exponent for allowed client ID’s, but when on TestFlight you need to put your App bundle ID ( for example com.app.myapp ), you can comma separate them.

Like below 👇 image

I’ve also been able to make it work with Supabase only by adding host.exp.Exponent to the allowed client ID’s. I imagine for dev and prod environments, I’ll just have two separate Supabase projects to handle that, even tho it would be annoying to have all configurations duplicated…

Thank you! I was missing this part by adding host.exp.Exponent to the allowed client ID's.

Hello, My apple sign in work fine on Expo Go and Simulator but when i want to connect with TestFlight, nothing happens. So Apple send me a review that : " We discovered one or more bugs in your app. Specifically, the app stays on the login screen when attempting to log in using Sign in with Apple. ". I don’t know why this happen. My code : const loginWithApple = () => { const nonce = Math.random().toString(36).substring(2, 10);

    return Crypto.digestStringAsync(Crypto.CryptoDigestAlgorithm.SHA256, nonce)
        .then((hashedNonce) =>
            AppleAuthentication.signInAsync({
                requestedScopes: [
                    AppleAuthentication.AppleAuthenticationScope.FULL_NAME,
                    AppleAuthentication.AppleAuthenticationScope.EMAIL
                ],
                nonce: hashedNonce
            })
        )
        .then(async (appleCredential) => {
            const { identityToken } = appleCredential;
            const provider = new firebase.auth.OAuthProvider('apple.com');
            const credential = await provider.credential({
                idToken: identityToken,
                rawNonce: nonce
            });
            await firebase.auth().signInWithCredential(credential).then((res) => {
                const profileInfo = res.user.providerData[0];
                const uid = res.user.uid;
                let action = addUserOnFirestore(
                    uid,
                    profileInfo.email,
                    profileInfo.displayName?.split(" ")[0],
                    profileInfo.displayName?.split(" ")[2],
                    profileInfo.photoURL,
                    res,
                    props.navigation
                );

                setIsLoading(true);
                try {
                    dispatch(action);
                } catch (err) {
                    setError(err.message);
                }
                setIsLoading(false);
            });
            // Successful sign in is handled by firebase.auth().onAuthStateChanged
        })
        .catch((error) => {
            console.log('Error : ', error);
        });
}

Did I missing something ? Thanks to all in advance.

That’s what I did. Didn’t realize that’s what you are asking for. But essentially you will have to change that each time you want to run dev mode or prod.

On Mon, Apr 25 2022 at 05:29, Pedro Netto < @.*** > wrote:

One workaround in development environment is to do this:

The only thing that helped was setting optional Services ID to host.exp.Exponent in Firebase Console -> Authentication -> Sign-in method -> Apple.

From: https://martinliptak.medium.com/thanks-for-the-article-ec172f979048

— Reply to this email directly, view it on GitHub ( https://github.com/expo/expo/issues/16162#issuecomment-1108388415 ) , or unsubscribe ( https://github.com/notifications/unsubscribe-auth/AB6T25KFID6VAQOXYBLP73TVGZXY5ANCNFSM5NLNYGOQ ). You are receiving this because you were mentioned. Message ID: <expo/expo/issues/16162/1108388415 @ github. com>