What I want to do.
I'm currently creating a restaurant booking web app with Nuxt, Laravel API and Firebase Authentication.
What I want to do is,
Create a new user account in Firebase Authentication.
{
"email": "User's email address from input",
"password": "User's password from input"
}
At the same time, insert a new user account to my local database with user uid as password.
{
"name": "User's name from input",
"email": "User's email address from input",
"password": "User's uid from store/auth.js"
}
Issue
The registration success to the Firebase Auth and also to the local database as well if it's without uid. But when I try to add uid, I get this error in Laravel logs.
1364 Field 'General error: password' doesn't have a default value
I thought this error occurred because of asynchronous processing, so I added Async to the code, but the result does not change.
Code
// register.vue
<script>
import firebase from '~/plugins/firebase'
export default {
layout: 'auth',
data () {
return {
user: {
name: null,
email: null,
password: null,
}
}
},
methods: {
async register() {
this.$store.dispatch('auth/register',
{
name: this.user.name,
email: this.user.email,
password: this.user.password
}
)
.then(() => {
this.$store.dispatch('auth/onAuth')
})
.then(() => {
this.$axios.post('http://localhost:8000/api/v1/users',
{
name: this.user.name,
email: this.user.email,
password: this.$store.state.auth.userUid
}
)
})
.then(() => {
this.$router.push('/thanks')
})
},
}
}
</script>
// store/auth.js
import firebase from '~/plugins/firebase.js'
export const state = () => ({
userUid: '',
userEmail: '',
loggedIn: false,
})
export const actions = {
async register({ commit }, payload) {
firebase
.auth()
.createUserWithEmailAndPassword(payload.email, payload.password)
.then((result) => {
const user = result.user
commit('loginStatusChange', true)
console.log('Regist a user was successful')
commit('setUserUid', user.uid)
commit('setUserEmail', user.email)
})
},
onAuth({ commit }) {
firebase.auth().onAuthStateChanged(user => {
user = user ? user : {}
commit('setUserUid', user.uid)
commit('setUserEmail', user.email)
commit('loginStatusChange', user.uid ? true : false)
})
}
}
export const mutations = {
loginStatusChange(state, status) {
state.loggedIn = status
},
setUserUid(state, userUid) {
state.userUid = userUid
},
setUserEmail(state, userEmail) {
state.userEmail = userEmail
}
}
export const getters = {
getUserUid(state) {
return state.userUid
},
getUserEmail(state) {
return state.userEmail
}
}
Environment
The issue is that your actions aren't composable so your Axios post request to Laravel doesn't wait for the previous two actions to complete, therefore this.$store.state.auth.userUid
is empty at that stage.
Have your async actions return a promise that actually waits for things to complete.
export const actions = {
async register({ commit }, { email, password }) {
const { user } = await firebase // 👈 note the "await" here
.auth()
.createUserWithEmailAndPassword(email, password)
commit('loginStatusChange', true)
console.log('Register a user was successful')
commit('setUserUid', user.uid)
commit('setUserEmail', user.email)
return user // 👈 return the user so consumers can use it
}
}
Registering a firebase auth state change listener isn't something you should configure as a Vuex action. I would instead register this as a plugin
// store/index.js
import firebase from "~/plugins/firebase"
const authStateChangePlugin = store => {
firebase.auth().onAuthStateChanged(user => {
user = user ? user : {}
store.commit("auth/setUserUid", user.uid)
store.commit("auth/setUserEmail", user.email)
store.commit("auth/loginStatusChange", user.uid ? true : false)
})
}
export const plugins = [ authStateChangePlugin ]
Wait for your action to dispatch before posting to Laravel
methods: {
async register () {
// 👇 note the use of "await"
const user = await this.$store.dispatch("auth/register", {
...this.user
})
await this.$axios.post("http://localhost:8000/api/v1/users", {
...this.user,
password: user.uid // no need to reference the store here
})
this.$router.push('/thanks')
}
}