Setup Nuxt With Firebase V9 Modular.
Create components/SignIn.vue
.
<template> <div id="firebaseui-auth-container"> <!-- <b-skeleton height="48px" v-if="loading"></b-skeleton>--> <v-if="loading">Loading ...</v-if="loading"> </div></template><script>import { GoogleAuthProvider } from "firebase/auth";// cannot put here, else window is not defined// import firebaseui from "firebaseui";import "firebaseui/dist/firebaseui.css"export default { data() { return { loading: true } }, async mounted() { const auth = await this.$fire.getAuth() // const { GoogleAuthProvider } = await import("firebase/auth"); const firebaseui = await import('firebaseui') // import("firebaseui/dist/firebaseui.css") const ui = firebaseui.auth.AuthUI.getInstance() || new firebaseui.auth.AuthUI(auth) const _this = this const config = { signInOptions: [ // this.$fireModule.auth.GoogleAuthProvider.PROVIDER_ID GoogleAuthProvider.PROVIDER_ID ], signInFlow: 'popup', // signInSuccessUrl: '/', // tosUrl: '/tos', // privacyPolicyUrl: '/privacy', callbacks: { signInSuccessWithAuthResult() { // console.log('signInSuccessWithAuthResult') _this.$emit('success') }, uiShown: () => { // console.log('uiShown') this.loading = false } } } ui.start('#firebaseui-auth-container', config) }} </script>
Usage
<template> <div> <sign-in v-on:success="onSignIn()" /> </div></template><script>export default { props: ['value'], methods: { onSignIn() { // this.$emit('update:value', false) const user = this.$fire.auth.currentUser; }, signOut() { // assume await this.$fire.getAuth() is already called this.$fire.auth.signOut() } /* async signOut() { const auth = await this.$fire.getAuth() auth.signOut() } */ },}</script>
Listen to user sign-in via onAuthStateChanged
, and write to vuex store.
async getAuth() { if (!this.auth) { const { getAuth, onAuthStateChanged } = await import("firebase/auth") const firebaseApp = await this.getApp() this.auth = getAuth(firebaseApp) onAuthStateChanged(this.auth, async (authUser) => { const claims = authUser ? (await authUser.getIdTokenResult(true)).claims : null if (authUser) { // I only run app check when user signin await fire.getAppCheck() } // store await store.dispatch('onAuthStateChangedAction', { authUser, claims }) }) } return this.auth}
Edit store/index.js
export const state = () => ({ user: false,})export const mutations = { ON_AUTH_STATE_CHANGED_MUTATION: async (state, { authUser, claims, user }) => { if (authUser) { const data = { uid: authUser.uid, // email: authUser.email, displayName: authUser.displayName, } if (user) { data.displayName = user.name } if (claims.isAdmin) { data.isAdmin = true } state.user = data } else { state.user = false } if (process.client && window.localStorage) { /** * Auth.onAuthStateChanged is delayed by 0.35s on first load before you can access the user object * Alternatively you can store part of user object in window.localStorage for quicker access, but less safe */ /* try { let data = JSON.stringify(state.user) localStorage.setItem('__user__', data) } catch(err) { console.error('localStorage fail', err) } */ } },}export const actions = { async onAuthStateChangedAction({ commit }, { authUser, claims }) { let user = null if (authUser) { const db = await this.$fire.getFirestore() // fetch user object from database // getItem is my custom helper funtion user = await db.getItem('user', authUser.uid) } commit('ON_AUTH_STATE_CHANGED_MUTATION', { authUser, claims, user }) }}
Access user object from any page or component.
<script>export default { computed: { currentUser() { /* if (process.client && !this.$store.state.user && window.localStorage) { const json = localStorage.getItem('__user__') if (json) { try { return JSON.parse(json) } catch (err) { console.error('localStorage fail', err) } } } */ return this.$store.state.user }, },}</script>