Home > Software design >  How to allow username/password and email/password login?
How to allow username/password and email/password login?

Time:01-15

I am trying to make my sign-up process more simple for users by not requiring an email. When that user goes to log in again, there are three situations.

  1. They didn't sign up with an email, and I set their email as [email protected] on the backend. They log in with their username/password, and I append @mydomain.com to their username before authenticating.
  2. They did sign up with an email, and they use their email/password to log in.
  3. They did sign up with an email, but they log in with their username and password.

For situation 3, I can't figure out a good way to authenticate that user. My initial idea was to send the username and password to a cloud function with the intent of matching the username to its email and verifying the password, but it doesn't seem like the admin SDK has a way to do this. I could of course send the email back to the client, but that seems unsecure. Am I missing something/any ideas here? Thank you.

edit.

I was finally able to implement what Dharmaraj suggested. See below. Hopefully someone else finds this useful!

// The Cloud Functions for Firebase SDK to
// create Cloud Functions and set up triggers.
const functions = require('firebase-functions');

// The Firebase Admin SDK to access Firestore.
const admin = require('firebase-admin');
admin.initializeApp();

const axios = require('axios');
const apiKey = 'API KEY';
const signInURL = 'https://identitytoolkit.googleapis.com/v1/accounts:signInWithPassword?key='   apiKey;

exports.getEmail = functions.https.onCall(async (data, context) => {
  // Grab the text parameter.
  const username = data.text.toLowerCase();
  const password = data.password;
  const uidData = await admin
    .firestore()
    .collection('usernameToUid')
    .doc(username)
    .get();
  const uid = uidData.get('uid');
  if (uid == null) {
    return {result: 'auth/user-not-found'};
  } else {
    const emailData = await admin
      .firestore()
      .collection('emails')
      .doc(uidData.get('uid'))
      .get();
    const email = emailData.get('email');
    if (email == null) {
      return {result: 'auth/email-not-found'};
    } else {
      //      try {
      //        const response = await axios
      //          .post('https://rapidapi.com/learn/api/rest', {
      //            name: 'John Doe',
      //          });
      //        return {result: JSON.stringify(response.data)};
      //      } catch (error) {
      //        return {result: error.message};
      //      }
      try {
        const response = await axios
          .post(signInURL, {
            email: email,
            password: password,
            returnSecureToken: true,
          });
        return {result: response.data.email};
      } catch (error) {
        return {result: 'auth/incorrect-password'};
      }
    }
  }
});

CodePudding user response:

There isn't any way to verify user's password using Admin SDk but a workaround would be to use Firebase Auth REST API with Cloud Function. Instead of returning email to the client side, after fetching email by username from database, you can impersonate user login.

exports.verifyPassword = functions.https.onCall((data, context) => {
  const { username, password } = data;

  const email = getEmailByUsername(username);

  // TODO: user Firebase Auth REST API
});

You can use fetchSignInMethodsForEmail to check if [email protected] exists. If it does not, then check for custom user email domains using Cloud Functions as mentioned before.

  • Related