0
votes

I want user to be automatically authenticated (temporarily) on Firebase just by sending Email then be redirected to a welcome page asking to complete the auth process by following a link received by email.

The first part is ok, I can authenticate by just inserting email and generating a random password like the following (Vuex store action):

this.$store.dispatch('userSignUp', { email: this.email, password: this.generatePassword })

which is called by component method button v-on:click="userSignUp

Vuex action is like :

  userSignUp ({commit}, payload) {
    commit('setLoading', true)
    firebase.auth().createUserWithEmailAndPassword(payload.email, payload.password)
    .then(firebaseUser => {
      commit('setUser', firebaseUser)
      commit('setLoading', false)
      commit('setError', null)
      router.push('/welcome')
    })
    .catch(error => {
      commit('setError', error.message)
      commit('setLoading', false)
    })
  }

So far so good, the user put the email, an helper function this.generatePassword generate a random password and the user is logged in and created on firebase.

Now this user is logged in, is on a welcome page, but it doesn't know his own random password (because I don't want to).

I want this to be one shot login and if the user want to come back, has to follow the link sent by email by Firebase.

There is a firebase function [sendPasswordResetEmail][1], which seems right for the case but I connot find the way to make it working.

I did Vuex action like before :

export const actions = {
  sendPasswordReset ({commit}, payload) {
    commit('setLoading', true)
    firebase.auth().sendPasswordResetEmail(payload.email)
    .then(firebaseUser => {
      commit('setUser', firebaseUser)
      commit('setLoading', false)
      commit('setError', null)
      router.push('/welcome')
    })
    .catch(error => {
      commit('setError', error.message)
      commit('setLoading', false)
      router.push('/error')
    })
  },
...

which is called by component method button v-on:click="userSignUp

methods: {
  userSignUp () {
    this.$store.dispatch('userSignUp', { email: this.email, password: this.generatePassword })
    this.$store.dispatch('sendPasswordReset', { email: this.email })
  }
},

I only get response code

{
 "error": {
  "errors": [
   {
    "domain": "global",
    "reason": "invalid",
    "message": "EMAIL_NOT_FOUND"
   }
  ],
  "code": 400,
  "message": "EMAIL_NOT_FOUND"
 }
}

while the Request Payload seems ok anyway :

{requestType: "PASSWORD_RESET", email: "[email protected]"}
email
:
"[email protected]"
requestType
:
"PASSWORD_RESET"

Any idea ?

1

1 Answers

2
votes

The provider you're using is called the password provider. As its name implies it is heavily dependent on the user having (and knowing) a password. Since you are looking for passwordless authentication, I'd recommend against using the email+password provider as the basis.

Instead consider implementing a custom authentication provider. While this involves a few more components, it is not as difficult as you may think. You'll need to run trusted code, which you can do either on a server you already have, or on Cloud Functions. In either of those cases, you'll use one of the Admin SDKs to implement the sensitive parts of the authentication flow.

A quick list of steps that I think you'll need:

  1. Create an endpoint (e.g. a HTTP triggered Cloud Function) for the user to request an authentication email.
  2. Implement the code for this endpoint to:
    1. Generate a random one-time code in there, which you're going to send to the user. Firebase Authentication calls this the out-of-band (or OOB) code, since it's sent to the user on a different medium than your app.
    2. Store this code and the user's email address somewhere where only your server-side code can read it, e.g. in the Firebase Database or Cloud Firestore.
    3. Send an email to the user, with the code or a link to a page that includes the code and their email address.
  3. Create an endpoint (e.g. again a HTTP function, or web page) where the user enters (e.g. by clicking on a link in the email) the OOB code and their email address.
  4. Compare the code the user entered, to the one you stored before.
  5. If the codes match, generate a custom token for the user and send it to them.
  6. The user/app now signs into Firebase with the custom token.