├── .gitignore ├── README.md ├── firebase.json ├── index.html ├── package.json ├── public └── favicon.ico ├── src ├── App.vue ├── assets │ └── logo.png ├── components │ └── Navbar.vue ├── main.js ├── router │ └── index.js ├── stores │ ├── index.js │ └── modules │ │ ├── auth.js │ │ └── user.js └── views │ ├── Home.vue │ ├── Profile.vue │ └── auth │ ├── Login.vue │ ├── PasswordReset.vue │ ├── Register.vue │ └── Verify.vue └── vite.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | .firebase 5 | .firebaserc 6 | 7 | # local env files 8 | .env.local 9 | .env.*.local 10 | 11 | # Log files 12 | npm-debug.log* 13 | yarn-debug.log* 14 | yarn-error.log* 15 | pnpm-debug.log* 16 | 17 | # Editor directories and files 18 | .idea 19 | .vscode 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? 25 | 26 | /src/firebase-config.js -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # vue3_firebase_auth 3 | 4 | This is a template for creating vue3 login/register via firebase-auth and using firestore to store some custom data. 5 | Additional this page can be hosted via firebase hosting. 6 | The app uses the newest firebase sdk version and the Vue 3 [SFC ` 13 | 14 | 15 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue3-firebase-auth", 3 | "version": "0.0.0", 4 | "scripts": { 5 | "dev": "vite", 6 | "build": "vite build", 7 | "preview": "vite preview", 8 | "deploy": "vite build && firebase deploy" 9 | }, 10 | "dependencies": { 11 | "@sweetalert2/theme-bootstrap-4": "^5.0.8", 12 | "bootstrap": "^5.1.3", 13 | "bootstrap-icons": "^1.7.2", 14 | "sweetalert2": "^11.3.10", 15 | "vue": "^3.2.25", 16 | "vue-router": "^4.0.12", 17 | "vue-sweetalert2": "^5.0.2", 18 | "vuex": "^4.0.2" 19 | }, 20 | "devDependencies": { 21 | "@vitejs/plugin-vue": "^2.0.0", 22 | "firebase": "^9.6.4", 23 | "sass": "^1.49.0", 24 | "sass-loader": "^12.4.0", 25 | "vite": "^2.7.2" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mindsaver/vue3_firebase_auth/7255bb27cff2414feae1de6422406b7bc4a6804b/public/favicon.ico -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 28 | -------------------------------------------------------------------------------- /src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Mindsaver/vue3_firebase_auth/7255bb27cff2414feae1de6422406b7bc4a6804b/src/assets/logo.png -------------------------------------------------------------------------------- /src/components/Navbar.vue: -------------------------------------------------------------------------------- 1 | 52 | 53 | 73 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue' 2 | import App from './App.vue' 3 | import router from './router' 4 | import "bootstrap/dist/css/bootstrap.min.css" 5 | import "bootstrap-icons/font/bootstrap-icons.css" 6 | import "bootstrap" 7 | import store from './stores' 8 | import VueSweetalert2 from 'vue-sweetalert2'; 9 | 10 | //import 'sweetalert2/dist/sweetalert2.min.css'; 11 | import '@sweetalert2/theme-bootstrap-4/bootstrap-4.scss'; 12 | // firebase 13 | import { initializeApp } from 'firebase/app' 14 | import { initializeFirestore } from 'firebase/firestore' 15 | import { getStorage } from 'firebase/storage' 16 | import { getAuth } from 'firebase/auth' 17 | import { firebaseConfig } from './firebase-config' 18 | 19 | console.log("main: initializeApp"); 20 | const firebase = initializeApp(firebaseConfig) 21 | const firestoreSettings = { 22 | timestampsInSnapshots: true 23 | } 24 | getAuth().onAuthStateChanged((user) => { 25 | console.log("onAuthStateChanged") 26 | if (user) { 27 | console.log(user) 28 | 29 | store.commit("user/setUser",user) 30 | } else { 31 | store.commit("user/setUser",null) 32 | } 33 | }); 34 | 35 | //getStorage(firebase) 36 | //initializeFirestore(firebase, firestoreSettings) 37 | 38 | const app = createApp(App); 39 | app.use(store) 40 | app.use(router); 41 | app.use(VueSweetalert2) 42 | app.mount("#app"); 43 | 44 | -------------------------------------------------------------------------------- /src/router/index.js: -------------------------------------------------------------------------------- 1 | import { createRouter, createWebHistory } from "vue-router"; 2 | import { getAuth, onAuthStateChanged } from "firebase/auth"; 3 | 4 | const router = createRouter({ 5 | history: createWebHistory(), 6 | routes: [ 7 | { 8 | path: "/", 9 | name: "home", 10 | // route level code-splitting 11 | // this generates a separate chunk (about.[hash].js) for this route 12 | // which is lazy-loaded when the route is visited. 13 | component: () => 14 | import(/* webpackChunkName: "home" */ "../views/Home.vue"), 15 | }, 16 | { 17 | path: "/login", 18 | name: "login", 19 | component: () => 20 | import(/* webpackChunkName: "login" */ "../views/auth/Login.vue"), 21 | meta: { 22 | requiresNoAuth: true, 23 | }, 24 | }, 25 | { 26 | path: "/register", 27 | name: "register", 28 | component: () => 29 | import(/* webpackChunkName: "register" */ "../views/auth/Register.vue"), 30 | meta: { 31 | requiresNoAuth: true, 32 | }, 33 | }, 34 | { 35 | path: "/passwordreset", 36 | name: "passwordreset", 37 | component: () => 38 | import( 39 | /* webpackChunkName: "passwordreset" */ "../views/auth/PasswordReset.vue" 40 | ), 41 | meta: { 42 | requiresNoAuth: true, 43 | }, 44 | }, 45 | { 46 | path: "/verify", 47 | name: "verify", 48 | component: () => 49 | import(/* webpackChunkName: "verify" */ "../views/auth/Verify.vue"), 50 | meta: { 51 | requiresVerify: true, 52 | }, 53 | }, 54 | { 55 | path: "/profile", 56 | name: "profile", 57 | component: () => 58 | import(/* webpackChunkName: "profile" */ "../views/Profile.vue"), 59 | meta: { 60 | requiresAuth: true, 61 | }, 62 | }, 63 | ], 64 | }); 65 | 66 | const getCurrentUser = () => 67 | new Promise((resolve, reject) => { 68 | const removeListener = onAuthStateChanged( 69 | getAuth(), 70 | (user) => { 71 | removeListener(); 72 | resolve(user); 73 | }, 74 | reject 75 | ); 76 | }); 77 | 78 | router.beforeEach(async (to, from, next) => { 79 | let user = await getCurrentUser(); 80 | if (to.matched.some((record) => record.meta.requiresAuth)) { 81 | if (user && !user.emailVerified) { 82 | next("/verify"); 83 | } else if (user) { 84 | next(); 85 | } else { 86 | next("/"); 87 | } 88 | } else if (to.matched.some((record) => record.meta.requiresNoAuth)) { 89 | if (!user) { 90 | next(); 91 | } else { 92 | next("/"); 93 | } 94 | } else if (to.matched.some((record) => record.meta.requiresVerify)) { 95 | if (user && !user.emailVerified) { 96 | next(); 97 | } else { 98 | next("/"); 99 | } 100 | } else { 101 | console.log("else"); 102 | if (user && !user.emailVerified) { 103 | next("/verify"); 104 | } else { 105 | next(); 106 | } 107 | } 108 | }); 109 | 110 | export default router; 111 | -------------------------------------------------------------------------------- /src/stores/index.js: -------------------------------------------------------------------------------- 1 | import { createStore, createLogger } from 'vuex' 2 | import user from './modules/user' 3 | 4 | const debug = process.env.NODE_ENV !== 'production' 5 | 6 | export default createStore({ 7 | modules: { 8 | user 9 | }, 10 | strict: debug, 11 | plugins: debug ? [createLogger()] : [] 12 | }) -------------------------------------------------------------------------------- /src/stores/modules/auth.js: -------------------------------------------------------------------------------- 1 | //store.js 2 | import { 3 | getAuth, 4 | signInWithEmailAndPassword, 5 | createUserWithEmailAndPassword, 6 | sendEmailVerification, 7 | signOut, 8 | GoogleAuthProvider, 9 | signInWithPopup, 10 | updateProfile 11 | } from 'firebase/auth' 12 | 13 | 14 | 15 | const state = () => ({ 16 | isLoading:false, 17 | errMsg:"" 18 | }) 19 | 20 | 21 | const getters = { 22 | 23 | 24 | isLoading: (state) => { 25 | return state.isLoading; 26 | }, 27 | errMsg: (state) => { 28 | return state.errMsg; 29 | } 30 | } 31 | 32 | const actions = { 33 | async register({ commit, state },email, password) { 34 | const auth = getAuth() 35 | commit('setIsLoading', true) 36 | await createUserWithEmailAndPassword(auth, email, password) 37 | .then((user) => { 38 | if (user) { 39 | this.user = auth.currentUser 40 | updateProfile(auth.currentUser, { 41 | displayName: '', 42 | photoURL: '' 43 | }) 44 | sendEmailVerification(auth.currentUser) 45 | commit('setIsLoading', false) 46 | } 47 | }) 48 | .catch((error) => { 49 | console.log(error); 50 | commit('setIsLoading', false) 51 | }) 52 | }, 53 | 54 | async verify ({ commit, state }) { 55 | const auth = getAuth() 56 | console.log("-----------") 57 | console.log(this.errMsg) 58 | commit('setIsLoading', true) 59 | 60 | await sendEmailVerification(auth.currentUser) 61 | .then((user) => { 62 | console.log("test1") 63 | console.log(user); 64 | commit('setIsLoading', false) 65 | }) 66 | .catch((error) => { 67 | console.log(error) 68 | switch (error.code) { 69 | case 'auth/too-many-requests': 70 | commit('setErrMsg', 'You made to many requests please wait some time...') 71 | break 72 | default: 73 | commit('setErrMsg', 'Resending verification failed...') 74 | break 75 | } 76 | commit('setIsLoading', false) 77 | 78 | // console.log(this.errMsg) 79 | }) 80 | } 81 | } 82 | const mutations = { 83 | setIsLoading (state, status) { 84 | state.isLoading = status 85 | }, 86 | setErrMsg (state, msg) { 87 | state.errMsg = msg 88 | } 89 | } 90 | 91 | export default { 92 | namespaced: true, 93 | state, 94 | getters, 95 | actions, 96 | mutations 97 | } 98 | -------------------------------------------------------------------------------- /src/stores/modules/user.js: -------------------------------------------------------------------------------- 1 | //store.js 2 | 3 | const state = () => ({ 4 | user: [], 5 | username:"" 6 | }); 7 | 8 | const getters = { 9 | user: (state) => { 10 | return state.user; 11 | }, 12 | loggedIn: (state) => { 13 | if (state.user) return true; 14 | return false; 15 | }, 16 | username: (state) => { 17 | return state.username 18 | }, 19 | email: (state) => { 20 | return state.user?.email 21 | }, 22 | isPasswordUsed: (state) => { 23 | return state.user?.providerData.find((x)=>{return x.providerId == "password"}) != null 24 | } 25 | 26 | }; 27 | 28 | const actions = {}; 29 | const mutations = { 30 | setUser(state, user) { 31 | state.user = user; 32 | if(user != null) 33 | state.username = user.displayName 34 | }, 35 | }; 36 | 37 | export default { 38 | namespaced: true, 39 | state, 40 | getters, 41 | actions, 42 | mutations, 43 | }; 44 | -------------------------------------------------------------------------------- /src/views/Home.vue: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/views/Profile.vue: -------------------------------------------------------------------------------- 1 | 90 | 173 | -------------------------------------------------------------------------------- /src/views/auth/Login.vue: -------------------------------------------------------------------------------- 1 | 56 | 57 | 114 | -------------------------------------------------------------------------------- /src/views/auth/PasswordReset.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | -------------------------------------------------------------------------------- /src/views/auth/Register.vue: -------------------------------------------------------------------------------- 1 | 26 | 27 | -------------------------------------------------------------------------------- /src/views/auth/Verify.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | -------------------------------------------------------------------------------- /vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import vue from '@vitejs/plugin-vue' 3 | const path = require('path') 4 | 5 | // https://vitejs.dev/config/ 6 | export default defineConfig({ 7 | resolve:{ 8 | alias:{ 9 | '@' : path.resolve(__dirname, './src') 10 | }, 11 | }, 12 | plugins: [vue()] 13 | }) --------------------------------------------------------------------------------