Why Firebase (onAuthStateChanged) does not see a Google signup user (with signInWithCredential)? - javascript

So I followed this tutorial on how to sign in a user with rnfirebase and google signup. And it works fine. Here is the code:
const googleSignUp = async () => {
// Get the users ID token
const { idToken } = await GoogleSignin.signIn();
// Create a Google credential with the token
const googleCredential = auth.GoogleAuthProvider.credential(idToken);
// Sign-in the user with the credential
const user = auth().signInWithCredential(googleCredential);
return { idToken, user };
};
(Let me note here, that the app has already a sign in with email and password way, with Firebase).
Then I realized that the user cannot change his name, email or delete his account.
Looking deeper, I found out that the onAuthStateChanged(firebase.auth, async (user) => ... returns null for the user.
I've seen in some older answers that if you use Google sign up, you need to sign up the user with signInWithCredential, which I use, so this in not the issue.
Could it be a problem that for email/password sign in, I use code from Firebase web and not from rnfirebase? Although I already had a combination of those, using the push notifications from rnfirebase.
Can someone explain why I get this behavior, and how to fix it?
Thanks!

If I understand correctly, you use both the react-native-firebase library (which wraps the native iOS and Android SDKs) and the JavaScript Web SDK for Firebase in your app.
If that is the case, both indeed have a separate sign-in state, and signing into one won't fire onAuthStateChanged listeners on the other.
You'll have to pick one SDK to authenticate with Firebase, and then use that for both providers.

Related

How to call Google Drive API from Cloud Function for Firebase on behalf of a user?

I want to interact with the Google's Drive API from a Cloud Function for Firebase. For authentication / authorization, I am currently relying on getClient, which I believe uses the Service Account exposed in the Cloud Function environment:
import { google } from 'googleapis';
// Within the Cloud Function body:
const auth = await google.auth.getClient({
scopes: [
'https://www.googleapis.com/auth/drive.file',
],
});
const driveAPI = google.drive({ version: 'v3', auth });
// read files, create file etc. using `driveAPI`...
The above approach works, as long as target directories / files list the email address of the service account as an editor.
However, I'd like to interact with the Drive API on behalf of another user (which I control), so that this user becomes (for example) the owner of files being created. How can I achieve this?
To set the user you want to deligate as in your code just add a subject to the client, with user being the email of the user on your workspace domain.
const client = await auth.getClient();
client.subject = user;
I was able to achieve calling the Drive API on behalf of another user thanks to the suggestions made by #DalmTo.
The first step is to configure domain-wide delegation of authority in Google Workspace for the default AppEngine Service Account.
Next, the code in my question can be extended to receive a subject with the email of the user to impersonate via the clientOptions:
import { google } from 'googleapis';
// Within the Cloud Function body:
const auth = await google.auth.getClient({
scopes: [
'https://www.googleapis.com/auth/drive.file',
],
clientOptions: {
subject: 'email#to.impersonate',
},
keyFile: './serviceAccountKey.json',
});
const driveAPI = google.drive({ version: 'v3', auth });
// read files, create file etc. using `driveAPI`...
Now, the truly odd thing is that this only works when also passing the service account key via the keyFile option in addition. I.e., relying on the key being automatically populated (as it is in Cloud Functions for Firebase) does NOT work when also trying to impersonate a request. There are ongoing discussions of this bug on GitHub, specifically see this comment.
To make domain-wide delegation work without having to provide the keyFile option (which will likely require you to manage the sensitive key file in some way), another option is to sign a JWT and use it to obtain an Oauth token. The approach is outlined by Google, and I found this SO answer providing a code-example very helpful.

Invisible recaptcha in Expo SDK 37

const phoneProvider = new firebase.auth.PhoneAuthProvider();
const verificationId = await phoneProvider.verifyPhoneNumber(
phoneNumber,
recaptchaVerifier.current
);
setVerificationId(verificationId);
Can we use without recaptchaVerifier.current
No, recaptcha will always be required if you want to use the Firebase Phone Auth.
As it says in the documentation :
Firebase phone authentication is not possible out of the box using the Firebase JS SDK. This because an Application Verifier object (reCAPTCHA) is needed as an additional security measure to verify that the user is real and not a bot.
https://docs.expo.io/versions/latest/sdk/firebase-recaptcha/

Only let pre-verified users log into Firebase

Right now, I only want users who have already registered and been verified with our software to login, and I have saved the list of emails of users (stripped of special characters) inside Firebase. Currently, when the user logs in, I use the following function to check if their email is in this list:
function isEmailValid(userEmail, trueCallback, falseCallback) {
var emailHash = userEmail.replace(/[^a-zA-Z0-9]/g, "");
firebase
.database()
.ref("validEmails/" + emailHash)
.on("value", snapshot => {
if (snapshot.val()) {
trueCallback(snapshot.val());
} else {
falseCallback();
}
});
}
Although this method works, it is quite unwieldy, as the user is still able to log in initially before the function callback is called, and their email is still shown in the "Authentication" tab in Firebase.
Is there a better way to only allowed pre-verified users to log into Firebase?
I'm pretty sure this has been covered before: there currently is no way to prevent users from signing in with Firebase Authentication. But if you want to prevent them from accessing backend resources, you can check whether their email address is verified either in the server-side security rules (for Realtime Database, Storage, or Firestore), or in your own server-side code.
At I/O a demo was given of upcoming functionality in Cloud Function that would allow you to prevent signing in users without a verified email address. But I don't know when this functionality will available in a public API.
Also see:
Firebase Prevent Creating Account Before Email Verification
How to prevent user authentication in Firebase/Vue.js BEFORE email is verified
How do I lock down Firebase Database to any user from a specific (email) domain?

Google Smartlock/Googleyolo did not return saved password

According to the documentation (https://developers.google.com/identity/one-tap/web/retrieve-credentials), we can get our saved password, just like when we use Credential Management API on Chrome.
I'm already currently logged in to Google in my browser.
I have tried to use the googleyolo api, using .retrieve() function as documented:
const retrievePromise = googleyolo.retrieve({
supportedAuthMethods: [
"https://accounts.google.com",
"googleyolo://id-and-password"
],
supportedIdTokenProviders: [
{
uri: "https://accounts.google.com",
clientId: "*********-**********.apps.googleusercontent.com"
}
]
}).then(res => console.log(res));
and it only return the idToken, no password returned.
But weirdly, when I tried using Credential Management API on Chrome my saved credentials popped up.
The question is,
1. What went wrong?
2. Where did googleyolo get its list of credentials? Because I checked at my https://passwords.google.com, and my credentials exists
3. What should I do/troubleshoot to get my password credentials?
Sorry for the confusion, passwords are only available in browsers that support the Credential Management API (which the library uses to retrieve the passwords). Will update the documentation to clarify that.
Not sure where you get the "googleyolo://id-and-password" from in the supportedAuthMethods argument. In your link, it specifically says only Google is supported.
googleyolo gets a list of users from your current browser. You will get more users if you have multiple users logged into a Google account.
When I implemented Google signon, I simply use the idtoken to confirm the identify of the user. No password is return from calling googleyolo.
Once you confirmed the user's identify, you can use the method provided to signin.
useGoogleIdTokenForAuth(credential.idToken);

javascript firebase.auth().signInWifEmailAndPassword not be able to get login in firebase

I am working with javascript Firebase in my app.
I'm able to use createUserWithEmailAndPassword successfully in the app. Also, the new user's registration shows inside the Firebase Console.
My question is, how can I check if a user exists or is logged into the browser?
This code will watch to see if there is a logged in user. It is based on the official docs from Firebase. Let me know if you need to know about the flow and authentication tokens etc.
firebase.auth().onAuthStateChanged(function(user) {
if (user) {
console.log('There is a user')
} else {
console.log('Nobody is home: Need to login or sign up!');
}
});

Categories

Resources