Search code examples
react-native-firebaseapple-sign-in

Firebase REST API signInWithIdp and Apple SignIn Provider - MISSING_OR_INVALID_NONCE


I'm implementing Apple Sign In in a React Native App.

The sample I'm using works well within the Mobile App: Apple Sign In - React Native Firebase

Just in case the link above changes, here is the code:

import auth from '@react-native-firebase/auth';
import { appleAuth } from '@invertase/react-native-apple-authentication';

async function onAppleButtonPress() {
  // Start the sign-in request
  const appleAuthRequestResponse = await appleAuth.performRequest({
    requestedOperation: appleAuth.Operation.LOGIN,
    requestedScopes: [appleAuth.Scope.EMAIL, appleAuth.Scope.FULL_NAME],
  });

  // Ensure Apple returned a user identityToken
  if (!appleAuthRequestResponse.identityToken) {
    throw 'Apple Sign-In failed - no identify token returned';
  }

  // Create a Firebase credential from the response
  const { identityToken, nonce } = appleAuthRequestResponse;
  const appleCredential = auth.AppleAuthProvider.credential(identityToken, nonce);

  // Sign the user in with the credential
  return auth().signInWithCredential(appleCredential);
}

In my backend Apps are only authorized to make calls if they use Firebase Access Tokens.

To get this to work, I am using the Google/Firebase REST API signInWithIdp. This works perfectly well for Twitter/Facebook/Google, but it doesn't for Apple.

What I/m doing is to use the Apple identityToken obtained here:

const { identityToken, nonce } = appleAuthRequestResponse;

And I make this call:

POST https://identitytoolkit.googleapis.com/v1/accounts:signInWithIdp?key={key}

BODY:
{
"postBody":"id_token={identityToken}&providerId=apple.com",
"requestUri":"http://localhost",
"returnSecureToken": true
}

but I get:

{
    "error": {
        "code": 400,
        "message": "MISSING_OR_INVALID_NONCE : Duplicate credential received. Please try again with a new credential.",
        "errors": [
            {
                "message": "MISSING_OR_INVALID_NONCE : Duplicate credential received. Please try again with a new credential.",
                "domain": "global",
                "reason": "invalid"
            }
        ]
    }
}

Due to the lack of documentation I'm blocked on this one. :(

Any suggestions on how to eliminate this error are very welcome. :)


Solution

  • Here is the documentation to support 'Sign in with OAuth credential'. The examples it gives looks like this:

    id_token=[GOOGLE_ID_TOKEN]&providerId=[google.com]

    You can actually add a nonce parameter as well (which isn't documented!), for example:

    id_token=ID_TOKEN&providerId=apple.com&nonce=NONCE

    To figure this out, I had to use the SDK (I used iOS) and make the request. I used mitmproxy to read the network, and this is what it showed when putting in dummy data:

    Request