Firebase functions Authentication trigger for sending email - firebase

I am using firebase and want that whenever a new user is created the user gets an email for his/her new sign in. Just as on https://raw.githubusercontent.com/firebase/functions-samples/master/quickstarts/email-users/functions/index.js Whenever a new user sign ups something like this is logged in console with error.
Can someone tell where's my mistake?

Have you configured the gmail.email and gmail.password environment variables as described in the example you linked? You would do this by running the following command in your terminal:
firebase functions:config:set gmail.email=your#email.com gmail.password=yourpassword

This is what you want.
firebase.auth().onAuthStateChanged(function(user) {
user.sendEmailVerification();
});
If you want to check if email have verified try this code is recommended
firebase.auth().onAuthStateChanged(function(user) {
if (user.emailVerified) {
console.log('Email is verified');
}
else {
console.log('Email is not verified');
}
});

Allow less secure apps in your Google account from which you want to send mails. Suppose you are using your own personal email for sending emails through nodemailer. Just go to the link https://myaccount.google.com/lesssecureapps, and allow less secure apps. That's all you are ready to go. :) ;)

Related

How can I use the firebase-admin 'generateEmailVerificationLink' function in firebase cloud-functions beforeCreate()?

I'm trying to build an app that authenticate through firebase. During the whole process I found that firebase release in any case a token even if email is not verified.
Because I want firebase give me a token only when email is verified I decided to use firebase-cloud-functions to check through the beforeCreate() function if a user's email was enabled and if not, send an email for verification generating an email link using 'firebase-admin' admin.auth().generateEmailVerificationLink.
According cloud-functions documentation here: https://firebase.google.com/docs/auth/extend-with-blocking-functions#common-scenarios it is possible to configure firebase-admin in cloud function in this way:
exports.beforeCreate = functions.auth.user().beforeCreate((user, context) => {
const locale = context.locale;
if (user.email && !user.emailVerified) {
// Send custom email verification on sign-up.
return admin.auth().generateEmailVerificationLink(user.email).then((link) => {
return sendCustomVerificationEmail(user.email, link, locale);
});
}
});
Apparently this doesn't work!!! In my case when I create a user I receive following error code:
FirebaseAuthError: There is no user record corresponding to the provided identifier.
Doing some other research it seems that to generate the email verification link FirebaseAuth should have already create or authenticate the user.
How is this thing not working since it's in the documentation? Do you have an idea about how this really work? Any example or detail would be great!!!
Thank to all.

How to verify custom auth claim upon login?

Similar to Uber, I have two applications, one for clients and one for drivers. Is it possible to know which role type the user has upon login? For instance, if I have a client account and I try to log in on the driver's application I should get the error: "client accounts cannot be used to log into the driver application".
Let's say I stored the user's account type (driver or client) in a custom auth claim, would it be possible to access that while firebase auth is verifying the email and password, or does the user have to log in successfully before I can verify the value of the custom auth claim?
Essentially, if the user tries logging into the wrong application, I want it to come back as an error without actually logging them in. So far I've only been able to check for this after the user logs in using getIDTokenResult.
Any help is appreciated! :)
Essentially, if the user tries logging into the wrong application, I want it to come back as an error without actually logging them in.
You seem to be mixing authentication (the user enters credentials that prove who they are) with authorization (the user is allowed to do certain things based on who the are). Firebase Authentication solely is concerned with the former: allowing the user to sign in once they enter the correct credentials for their account. Once the user is signed in, your application code can then determine whether they're allowed to perform certain actions.
For your specific use-case for example, the idiomatic approach is to:
Sign the user in to Firebase Authentication.
Check whether their token contains the necessary claim for the app they're trying to use.
If so, allow them to continue to the main screen of your app.
If not, inform them of that fact and don't allow them to continue.
As you can see here, it is your application logic that handles all authorization logic, while Firebase takes care of the authentication.
The user must be logged in before checking the claims and anyways you cannot prevent anyone from logging in if it's a same firebase project. You should check the claim after login and if the user has logged into wrong application, just force them to logout. Security Rules can be used to prevent unauthorized access.
firebase.auth().signInWithEmailAndPassword().then(async ({user}) => {
const claims = await user.getIdTokenResult()
// check for claim
// if not valid then logout or redirect to relevant pages
await firebase.auth(can ).signOut()
})
You can show your error alerts after signing out.
If you really want to check the claim before logging the user in then you would have to use cloud functions which checks claims for the entered email but this method may not be useful in other sign in providers such as Google or Facebook.
Although I won't recommend using Cloud functions just to check the claims before users logs in as it just can be bypassed on the frontend and as mentioned above, forcing the user to logout should be enough. But here's a cloud function you can use to check the claims.
exports.checkClaim = functions.https.onCall((data, context) => {
const {email} = data;
return admin
.auth()
.getUser(uid)
.then((userRecord) => {
const {customClaims: {driver, client}} = userRecord;
if (driver) return {role: "driver"}
if (client) return {role: "client"}
return {error: "No role found"}
})
.catch((error) => {
console.log('Error fetching user data:', error);
});
});
Then call the function before you run the signInWithEmailAndPassword method.
const checkUserRole = firebase.functions().httpsCallable('checkClaim');
checkUserRole({ email: "user#domain.tld" })
.then((result) => {
const {role, error} = result;
if (error) {
alert("Something went wrong. No roles found")
} else {
console.log(`Your role is: ${role}`)
}
});
Again as mentioned above this sounds a bit overkill but if it's necessary or you prefer to do it that way then you use this function.

How to check email and username

Trying to create a REST authentication system using Google Cloud Functions and Firebase. The Firebase docs here say:
To achieve this, you must create a server endpoint that accepts sign-in credentials—such as a username and password—and, if the credentials are valid, returns a custom JWT.
I see that I have to do something like:
let uid = 'some-uid';
admin.auth().createCustomToken(uid)
.then(function(customToken) {
// Send token back to client
})
.catch(function(error) {
console.log('Error creating custom token:', error);
});
but wondering the best way to verify email/password validity from the login form and get the uid (all in Cloud Functions) to then send into createCustomToken()?
See comments-- I realized I was overcomplicating matters and have opted for another approach entirely. Thanks all!

Sending a Welcome email using Google Cloud Functions when the app uses Phone verification for authentication

I am trying to send a Welcome email using Google Cloud Functions, similar to what is done here:
https://github.com/firebase/functions-samples/tree/master/quickstarts/email-users
The problem is that my app uses Phone verification for authentication, we do however upload the users email and save it under the users UID in the Firebase Real time database.
Could we pull the email using the cloud function using the UID and then insert that into the javascript code? or is there another way of doing this?
Best,
Feras A.
You should be able to read from the realtime database with the Firebase Admin SDK:
return admin.database().ref(/* path to user's email */).once("value").then(function(snapshot) {
if (snapshot.val() === null) {
console.log("Error getting user email: user does not exist");
return;
}
const email = snapshot.child("email").val();
// Send email here
});
More information and examples can be found on the Firebase Admin Auth Guide (See the example under Authenticate with admin privileges).

Meteor account enrollment

I'm looking for a way to customize logins to allow for an administrator to provide a user with an account and a one-time-use temporary password (via email), that enables the user to log into a site (the user can't create an account on their own).
The first time the user logs in, they are instructed to change the temporary password given by the administrator.
I have accounts-ui and accounts-password working, but the user can create a new account at will.
If it matters, I plan to use Autoform and Iron Router for this.
I search the Meteor docs for "enroll", but the information is sparse IMO. Is there a fully working example somewhere to help me get started?
To disable the usual way of creating an account, use Accounts.config:
forbidClientAccountCreation Boolean
Calls to createUser from the client will be rejected. In addition, if you are using accounts-ui, the "Create account" link will not be
available.
Then, instead of having a temporary password, I think you should create the account without password and then use Accounts.sendEnrollmentEmail to send the user an email to choose one.
To create an account without a password on the server and still let
the user pick their own password, call createUser with the email
option and then call Accounts.sendEnrollmentEmail. This will send the
user an email with a link to set their initial password.
So, something like that:
Accounts.config({forbidClientAccountCreation: true});
Meteor.methods({
adminCreateAccount: function (accountAttributes) {
if(Meteor.user() && Meteor.user().role == "admin") {
var accountId = Accounts.createUser({
'username': accountAttributes.username,
'email': accountAttributes.emailAddress
});
Accounts.sendEnrollmentEmail(accountId);
}
}
});
What you can do is
let the admin create user (Accounts.createUser)
add a marker ( eg user.profile.changedInitialPwd) which will be set when the user
changed his pwd)
use some verification logic to make sure, the user has changed his password before he is allowed to sign in
E.g.
Accounts.validateLoginAttempt(function(attempt){
if (attempt.user && !attempt.user.profile.changedInitialPwd ) {
console.log('Initial password not changed');
return false; // the login is aborted
}
return true;
});

Resources