I'm trying to have users of my app sign in by email + link, password-less. The client (written in React Native) asks for the sign-in link using the Javascript SDK like so, based on this answer:
var actionCodeSettings = {
// URL you want to redirect back to. The domain (www.example.com) for this
// URL must be in the authorized domains list in the Firebase Console.
url: `${BASE_URL}/verifyEmail?email=${email}`,
// This must be true.
handleCodeInApp: true,
iOS: {
bundleId: BUNDLE_ID
},
android: {
packageName: BUNDLE_ID,
installApp: true,
minimumVersion: '12'
},
dynamicLinkDomain: 'myapp.page.link'
};
await firebase.auth().sendSignInLinkToEmail(email, actionCodeSettings)
}
Then the user opens the email and follows the sign-in link. Ideally it deep links back to the app, but in case that doesn't happen (e.g. they do it on a different device), I still need it to verify their email address on my server, which is NodeJS. My /verifyEmail handler should do that. According to this answer, the Firebase admin SDK can't verify action codes anymore. It suggests using the Firebase admin REST API, which says to effectively do:
curl 'https://identitytoolkit.googleapis.com/v1/accounts:update?key=AIzaSyCrFbTvuObVGlmGv9MK2sZ9MyS-VCkN--8' \
-H 'Content-Type: application/json' --data-binary '{"oobCode":"9LRoycB4fFrycmyLreYnjcAzxsGnwIpd9ub5tkpX_EQAAAF2-d9GoQ"}'
But I'm getting INVALID_OOB_CODE as a result. To test, I copied the OOB code from the email link, without clicking it, directly into that cURL command.
What am I doing wrong? Looking at the Javascript client SDK's source, it seems that applyActionCode calls the same endpoint I'm calling here in the same way. I'm thinking maybe this method only works for verifying an email/password signup, but if so, how do I sign up someone without a password?
The only workaround I can think of is in /verifyEmail to hash the oobCode, truncate the hash down to a user-friendly verification code, store the verification link on the server side, and ask the user to input that code in the app in order to retrieve the verification link to be used with EmailAuthProvider.credentialWithLink. And reject if too much time passes. That's undesirable.