├── .env.example ├── .gitignore ├── README.md ├── package-lock.json ├── package.json ├── postcss.config.js ├── public ├── favicon.svg └── index.html ├── src ├── App.vue ├── assets │ └── css │ │ └── main.css ├── components │ ├── Dashboard.vue │ ├── Error404.vue │ ├── ForgotPassword.vue │ ├── Header.vue │ ├── Home.vue │ ├── SignIn.vue │ └── SignUp.vue ├── main.js ├── router │ └── routes.js └── store │ └── store.js └── tailwind.config.js /.env.example: -------------------------------------------------------------------------------- 1 | VUE_APP_HOST_NAME=http://example.com -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | 6 | # local env files 7 | .env.local 8 | .env.*.local 9 | 10 | # Log files 11 | npm-debug.log* 12 | yarn-debug.log* 13 | yarn-error.log* 14 | pnpm-debug.log* 15 | 16 | # Editor directories and files 17 | .idea 18 | .vscode 19 | *.suo 20 | *.ntvs* 21 | *.njsproj 22 | *.sln 23 | *.sw? 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Vue Auth Demo with Firebase 2 | 3 | > A Vue.js project that provides a simple demo for securing pages with vue-router, Vuex and Firebase to handle authentication and user management. 4 | 5 | **Please note you will need to add your own firebase credentials to the [config](https://github.com/garethredfern/vue-auth-demo/blob/master/src/main.js#L10).** 6 | 7 | For detailed explanation on how things work read the following tutorials: 8 | 9 | - [Authenticate Users Using Firebase & VueJS](https://redfern.dev/articles/authenticate-users-using-firebase-and-vuejs) 10 | - [How to Manage User State With Vuex and Firebase](https://redfern.dev/articles/manage-user-state-vuex-and-firebase) 11 | 12 | To follow along with each of the blog posts the code has seperate branches for each step: 13 | 14 | 1. [Basic Auth](https://github.com/garethredfern/vue-auth-demo/tree/basic-auth) 15 | 16 | ## Build Setup 17 | 18 | ```bash 19 | # install dependencies 20 | npm install 21 | 22 | # serve with hot reload at localhost:8080 23 | npm run dev 24 | 25 | # build for production with minification 26 | npm run build 27 | ``` 28 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-auth-demo", 3 | "author": "Gareth Redfern ", 4 | "version": "0.1.0", 5 | "private": true, 6 | "scripts": { 7 | "serve": "vue-cli-service serve", 8 | "build": "vue-cli-service build", 9 | "lint": "vue-cli-service lint" 10 | }, 11 | "dependencies": { 12 | "@firebase/app": "^0.6.10", 13 | "core-js": "^3.6.5", 14 | "firebase": "^7.19.1", 15 | "vue": "^2.6.11", 16 | "vue-router": "^3.2.0", 17 | "vuex": "^3.4.0" 18 | }, 19 | "devDependencies": { 20 | "@vue/cli-plugin-babel": "~4.5.0", 21 | "@vue/cli-plugin-eslint": "~4.5.0", 22 | "@vue/cli-plugin-router": "~4.5.0", 23 | "@vue/cli-plugin-vuex": "~4.5.0", 24 | "@vue/cli-service": "~4.5.0", 25 | "@vue/eslint-config-prettier": "^6.0.0", 26 | "babel-eslint": "^10.1.0", 27 | "eslint": "^6.7.2", 28 | "eslint-plugin-prettier": "^3.1.3", 29 | "eslint-plugin-vue": "^6.2.2", 30 | "prettier": "^1.19.1", 31 | "tailwindcss": "^1.7.6", 32 | "vue-template-compiler": "^2.6.11" 33 | }, 34 | "prettier": { 35 | "trailingComma": "es5", 36 | "tabWidth": 2, 37 | "semi": true, 38 | "singleQuote": false 39 | }, 40 | "eslintConfig": { 41 | "root": true, 42 | "env": { 43 | "node": true 44 | }, 45 | "extends": [ 46 | "plugin:vue/essential", 47 | "eslint:recommended", 48 | "@vue/prettier" 49 | ], 50 | "parserOptions": { 51 | "parser": "babel-eslint" 52 | }, 53 | "rules": {} 54 | }, 55 | "browserslist": [ 56 | "> 1%", 57 | "last 2 versions", 58 | "not dead" 59 | ] 60 | } 61 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | const tailwindcss = require("tailwindcss"); 2 | const autoprefixer = require("autoprefixer"); 3 | 4 | module.exports = { 5 | plugins: [ 6 | tailwindcss("./tailwind.config.js"), 7 | autoprefixer({ 8 | add: true, 9 | grid: true, 10 | }), 11 | ], 12 | }; 13 | -------------------------------------------------------------------------------- /public/favicon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Vue Auth Demo 8 | 9 | 10 | 16 |
17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 32 | 33 | 45 | -------------------------------------------------------------------------------- /src/assets/css/main.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | 3 | @tailwind components; 4 | 5 | @tailwind utilities; 6 | -------------------------------------------------------------------------------- /src/components/Dashboard.vue: -------------------------------------------------------------------------------- 1 | 34 | 35 | 72 | -------------------------------------------------------------------------------- /src/components/Error404.vue: -------------------------------------------------------------------------------- 1 | 11 | -------------------------------------------------------------------------------- /src/components/ForgotPassword.vue: -------------------------------------------------------------------------------- 1 | 41 | 42 | 75 | -------------------------------------------------------------------------------- /src/components/Header.vue: -------------------------------------------------------------------------------- 1 | 25 | 26 | 47 | -------------------------------------------------------------------------------- /src/components/Home.vue: -------------------------------------------------------------------------------- 1 | 11 | -------------------------------------------------------------------------------- /src/components/SignIn.vue: -------------------------------------------------------------------------------- 1 | 54 | 55 | 82 | -------------------------------------------------------------------------------- /src/components/SignUp.vue: -------------------------------------------------------------------------------- 1 | 47 | 48 | 79 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import App from "./App.vue"; 3 | import firebase from "firebase"; 4 | import VueRouter from "vue-router"; 5 | import { store } from "./store/store"; 6 | import { routes } from "./router/routes"; 7 | import "@/assets/css/main.css"; 8 | 9 | // Firebase config - this is provided when you create your app 10 | // Swap out these settings for your project settings 11 | var firebaseConfig = { 12 | apiKey: "AIzaSyCxfKEMCvc-rtExZTsJQKPr4mbXkmQYkJY", 13 | authDomain: "vue-auth-demo-637b2.firebaseapp.com", 14 | databaseURL: "https://vue-auth-demo-637b2.firebaseio.com", 15 | projectId: "vue-auth-demo-637b2", 16 | storageBucket: "vue-auth-demo-637b2.appspot.com", 17 | messagingSenderId: "624803255895", 18 | appId: "1:624803255895:web:c4f09775fe732e8f3b7512", 19 | }; 20 | 21 | // Initialize Firebase 22 | firebase.initializeApp(firebaseConfig); 23 | 24 | // Set-up and use the Vue Router 25 | // Pass in your routes and then 26 | // Set the mode to use history 27 | // removes # from the URL 28 | Vue.use(VueRouter); 29 | 30 | const router = new VueRouter({ 31 | routes: routes, 32 | mode: "history", 33 | }); 34 | 35 | // Check before each page load whether the page requires authentication/ 36 | // if it does check whether the user is signed into the web app or 37 | // redirect to the sign-in page to enable them to sign-in 38 | router.beforeEach((to, from, next) => { 39 | const user = firebase.auth().currentUser; 40 | const requiresAuth = to.matched.some(record => record.meta.requiresAuth); 41 | 42 | if (requiresAuth && !user) { 43 | next("/sign-in"); 44 | } else if (requiresAuth && user) { 45 | next(); 46 | } else { 47 | next(); 48 | } 49 | }); 50 | 51 | // Wrap the vue instance in a Firebase onAuthStateChanged method 52 | // This stops the execution of the navigation guard 'beforeEach' 53 | // method until the Firebase initialization ends 54 | firebase.auth().onAuthStateChanged(() => { 55 | new Vue({ 56 | el: "#app", 57 | store: store, 58 | router: router, 59 | render: h => h(App), 60 | }); 61 | }); 62 | -------------------------------------------------------------------------------- /src/router/routes.js: -------------------------------------------------------------------------------- 1 | import firebase from "firebase"; 2 | import Home from "@/components/Home"; 3 | import SignIn from "@/components/SignIn"; 4 | import SignUp from "@/components/SignUp"; 5 | import Error404 from "@/components/Error404"; 6 | import Dashboard from "@/components/Dashboard"; 7 | import ForgotPassword from "@/components/ForgotPassword"; 8 | 9 | // This is where you add all your site routes 10 | // Each route is set as an object in the array 11 | // For a the most basic route just set 12 | // the path & component to load 13 | 14 | export const routes = [ 15 | { 16 | path: "", 17 | name: "home", 18 | component: Home, 19 | }, 20 | { 21 | path: "/sign-in", 22 | name: "signIn", 23 | component: SignIn, 24 | beforeEnter(to, from, next) { 25 | const user = firebase.auth().currentUser; 26 | if (user) { 27 | next({ name: "dashboard" }); 28 | } else { 29 | next(); 30 | } 31 | }, 32 | }, 33 | { 34 | path: "/sign-up", 35 | name: "signUp", 36 | component: SignUp, 37 | beforeEnter(to, from, next) { 38 | const user = firebase.auth().currentUser; 39 | if (user) { 40 | next({ name: "dashboard" }); 41 | } else { 42 | next(); 43 | } 44 | }, 45 | }, 46 | { 47 | path: "/forgot-password", 48 | name: "forgotPassword", 49 | component: ForgotPassword, 50 | beforeEnter(to, from, next) { 51 | const user = firebase.auth().currentUser; 52 | if (user) { 53 | next({ name: "dashboard" }); 54 | } else { 55 | next(); 56 | } 57 | }, 58 | }, 59 | { 60 | path: "/dashboard", 61 | name: "dashboard", 62 | component: Dashboard, 63 | meta: { 64 | requiresAuth: true, 65 | }, 66 | }, 67 | { 68 | path: "/404", 69 | name: "404", 70 | component: Error404, 71 | }, 72 | { 73 | path: "*", 74 | redirect: "/404", 75 | }, 76 | ]; 77 | -------------------------------------------------------------------------------- /src/store/store.js: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import Vuex from "vuex"; 3 | import firebase from "firebase"; 4 | 5 | Vue.use(Vuex); 6 | 7 | export const store = new Vuex.Store({ 8 | state: { 9 | user: null, 10 | }, 11 | getters: { 12 | getUser: state => state.user, 13 | }, 14 | mutations: { 15 | SET_USER: state => { 16 | state.user = firebase.auth().currentUser; 17 | }, 18 | }, 19 | actions: { 20 | setUser: context => { 21 | context.commit("SET_USER"); 22 | }, 23 | }, 24 | }); 25 | -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: [], 3 | theme: { 4 | fontFamily: { 5 | sans: ["Open Sans", "sans-serif"], 6 | }, 7 | }, 8 | }; 9 | --------------------------------------------------------------------------------