Vue 3 Firebase Auth
Created:
Work in progress.
Install Vue Router & Firebase
npm install [email protected]
npm install [email protected]
Initialize Vue Router and register routes
/* ~src/router/router.js */
import { createRouter, createWebHistory } from 'vue-router';
import Index from '../views/Index.vue';
import About from '../views/About.vue';
import Dashboard from '../views/Dashboard.vue';
const routes = [
{ path: '/', component: Index },
{ path: '/about', component: About },
{
path: '/dashboard',
component: Dashboard,
meta: { requiresAuth: true },
},
];
const router = createRouter({
history: createWebHistory(),
routes,
scrollBehavior(to, from, savedPosition) {
if (savedPosition) {
return savedPosition;
}
return { top: 0, left: 0 };
},
});
export default router;
Initialize Firebase
/* ~/src/initFirebase.js */
import { initializeApp } from 'firebase/app';
import { getAuth } from 'firebase/auth';
/* replace config */
const firebaseConfig = {
apiKey: 'AIzaSyDOCAbC123dEf456GhI789jKl01-MnO',
authDomain: 'myapp-project-123.firebaseapp.com',
databaseURL: 'https://myapp-project-123.firebaseio.com',
projectId: 'myapp-project-123',
storageBucket: 'myapp-project-123.appspot.com',
messagingSenderId: '65211879809',
appId: '1:65211879909:web:3ae38ef1cdcb2e01fe5f0c',
measurementId: 'G-8GSGZQ44ST',
};
const firebaseApp = initializeApp(firebaseConfig);
const Auth = getAuth(firebaseApp);
export { Auth };
Manage auth
/* ~/src/auth/auth.js */
import { Auth } from '../initFirebase.js';
import { getIdTokenResult } from 'firebase/auth';
import api from '../api/api.js';
/**
* @param {import('firebase/auth').User} firebaseUser
*/
export async function getUserData(firebaseUser) {
// console.log({ firebaseUser })
const { photoURL, displayName } = firebaseUser;
const idTokenResult = await getIdTokenResult(firebaseUser);
let { userID } = idTokenResult?.claims; // undefined if new user
if (!userID) {
userID = await createNewUser(firebaseUser);
} else {
// Fetch additional data from the server, smt like
// const { body: userRecord } = await api.users.find(userID)
// then theck if displayName and/or photoURL have changed
// and proceed accordingly
}
const user = {
displayName,
photoURL,
userID,
};
return user;
}
async function createNewUser({ photoURL, displayName }) {
// Call the back-end to insert a new user record in DB
// and assign a custom claim “userID” to the newly created user
let userID;
try {
const { status, body } = await api.users.create({ photoURL, displayName });
// console.log({ status, body })
userID = body.userID;
} catch (error) {
console.error(error);
}
return userID;
}
Sign In
/* ~/src/auth/signIn.js */
import { Auth } from '../initFirebase.js';
import {
GoogleAuthProvider,
signInWithRedirect,
signInWithPopup,
useDeviceLanguage,
} from 'firebase/auth';
export async function signIn() {
const re = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i;
const isMobile = re.test(navigator.userAgent);
useDeviceLanguage(Auth);
const provider = new GoogleAuthProvider();
provider.addScope('https://www.googleapis.com/auth/plus.login');
try {
if (isMobile) {
await signInWithRedirect(Auth, provider);
} else {
await signInWithPopup(Auth, provider);
}
} catch (error) {
alert(error.message);
}
}
Update main.js
/* ~/src/main.js */
import { createApp, readonly, ref } from 'vue';
import App from './App.vue';
import router from './router/router.js';
import { onAuthStateChanged } from 'firebase/auth';
import { Auth } from './initFirebase';
import { getUserData } from './auth/auth';
router.beforeEach((to, from, next) => {
const { currentUser } = Auth;
const requiresAuth = to.matched.some((record) => record.meta.requiresAuth);
if (requiresAuth && !currentUser) {
next({ path: '/' });
} else {
next();
}
});
let app;
const user = ref({});
onAuthStateChanged(Auth, async (firebaseUser) => {
if (!firebaseUser) {
user.value = {};
} else {
user.value = await getUserData(firebaseUser);
}
if (!app) {
app = createApp(App);
app.provide('user', readonly(user)); // now user is globally available
app.use(router);
app.mount('#app');
}
});