├── .gitignore ├── .gitmodules ├── LICENSE ├── index.html ├── package.json ├── readme.md ├── src ├── auth │ └── index.js ├── components │ ├── App.vue │ ├── Home.vue │ ├── Login.vue │ ├── SecretQuote.vue │ └── Signup.vue └── index.js └── webpack.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "server"] 2 | path = server 3 | url = https://github.com/auth0/nodejs-jwt-authentication-sample -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Auth0, Inc. (http://auth0.com) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Hello Vue 6 | 7 | 8 | 9 |
10 | 11 | 12 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-jwt-auth-example", 3 | "version": "1.0.0", 4 | "description": "An of how to do JWT Authentication with Vue.js", 5 | "scripts": { 6 | "dev": "webpack-dev-server --inline --hot" 7 | }, 8 | "author": "ryanchenkie", 9 | "license": "MIT", 10 | "devDependencies": { 11 | "babel-core": "^6.0.0", 12 | "babel-loader": "^6.0.0", 13 | "babel-plugin-transform-runtime": "^6.0.0", 14 | "babel-preset-es2015": "^6.0.0", 15 | "babel-preset-stage-2": "^6.0.0", 16 | "babel-runtime": "^5.8.0", 17 | "css-loader": "^0.21.0", 18 | "style-loader": "^0.13.0", 19 | "vue-hot-reload-api": "^1.2.1", 20 | "vue-html-loader": "^1.0.0", 21 | "vue-loader": "^7.0.1", 22 | "webpack": "^1.12.3", 23 | "webpack-dev-server": "^1.12.1" 24 | }, 25 | "dependencies": { 26 | "bootstrap": "^3.3.5", 27 | "vue-resource": "^0.1.17", 28 | "vue-router": "^0.7.5", 29 | "vue": "^1.0.7" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Vue.js JWT Authentication 2 | 3 | This example shows how to do JWT authentication in Vue.js apps. It uses Auth0's [nodejs-jwt-authentication-sample](https://github.com/auth0/nodejs-jwt-authentication-sample), a NodeJS backend that serves Chuck Norris quotes. 4 | 5 | ## Installation 6 | 7 | Clone the repo and then install the server submodule and dependencies. 8 | 9 | ```bash 10 | git submodule update --init 11 | cd server 12 | npm install 13 | cd .. 14 | npm install 15 | ``` 16 | 17 | Once the application scripts are in place, start the server (which will provide the quotes) using: 18 | 19 | ```bash 20 | node server/server.js 21 | ``` 22 | 23 | Afterwards, open a second Terminal window and run the [webpack development server](http://webpack.github.io/docs/webpack-dev-server.html). It will watch for changes with **hot reloading**: 24 | 25 | ```bash 26 | npm run dev 27 | ``` 28 | 29 | ## Important Snippets 30 | 31 | The entry point for the app is at `src/index.js`. Here we import everything we need and set up routing. 32 | 33 | ```js 34 | // src/index.js 35 | 36 | import Vue from 'vue' 37 | import App from './components/App.vue' 38 | import Home from './components/Home.vue' 39 | import SecretQuote from './components/SecretQuote.vue' 40 | import Signup from './components/Signup.vue' 41 | import Login from './components/Login.vue' 42 | import VueRouter from 'vue-router' 43 | import VueResource from 'vue-resource' 44 | Vue.use(VueResource) 45 | Vue.use(VueRouter) 46 | import auth from './auth' 47 | 48 | Vue.http.headers.common['Authorization'] = 'Bearer ' + localStorage.getItem('id_token'); 49 | 50 | // Check the user's auth status when the app starts 51 | auth.checkAuth() 52 | 53 | export var router = new VueRouter() 54 | 55 | router.map({ 56 | '/home': { 57 | component: Home 58 | }, 59 | 'secretquote': { 60 | component: SecretQuote 61 | }, 62 | '/login': { 63 | component: Login 64 | }, 65 | '/signup': { 66 | component: Signup 67 | } 68 | }) 69 | 70 | router.redirect({ 71 | '*': '/home' 72 | }) 73 | 74 | router.start(App, '#app') 75 | ``` 76 | 77 | The `Login` and `Signup` Vue components are very similar and allow the user to enter their username and password. 78 | 79 | ```html 80 | 81 | 82 | 108 | 109 | 140 | ``` 141 | 142 | These components utilize the `auth` service. 143 | 144 | ```js 145 | // src/auth/index.js 146 | 147 | import {router} from '../index' 148 | 149 | const API_URL = 'http://localhost:3001/' 150 | const LOGIN_URL = API_URL + 'sessions/create/' 151 | const SIGNUP_URL = API_URL + 'users/' 152 | 153 | export default { 154 | 155 | user: { 156 | authenticated: false 157 | }, 158 | 159 | login(context, creds, redirect) { 160 | context.$http.post(LOGIN_URL, creds, (data) => { 161 | localStorage.setItem('id_token', data.id_token) 162 | 163 | this.user.authenticated = true 164 | 165 | if(redirect) { 166 | router.go(redirect) 167 | } 168 | 169 | }).error((err) => { 170 | context.error = err 171 | }) 172 | }, 173 | 174 | signup(context, creds, redirect) { 175 | context.$http.post(SIGNUP_URL, creds, (data) => { 176 | localStorage.setItem('id_token', data.id_token) 177 | 178 | this.user.authenticated = true 179 | 180 | if(redirect) { 181 | router.go(redirect) 182 | } 183 | 184 | }).error((err) => { 185 | context.error = err 186 | }) 187 | }, 188 | 189 | logout() { 190 | localStorage.removeItem('id_token') 191 | this.user.authenticated = false 192 | }, 193 | 194 | checkAuth() { 195 | var jwt = localStorage.getItem('id_token') 196 | if(jwt) { 197 | this.user.authenticated = true 198 | } 199 | else { 200 | this.user.authenticated = false 201 | } 202 | }, 203 | 204 | 205 | getAuthHeader() { 206 | return { 207 | 'Authorization': 'Bearer ' + localStorage.getItem('id_token') 208 | } 209 | } 210 | } 211 | ``` 212 | 213 | Finally, we can get protected Chuck Norris quotes with our `SecretQuote` component. This component is very similar to `Home` in which we are able to retrieve unprotected quotes. The difference is that `SecretQuote` attaches an `Authorization` header on the `GET` requests that are made from it. 214 | 215 | ```html 216 | 217 | 218 | 227 | 228 | 259 | ``` 260 | 261 | ## What is Auth0? 262 | 263 | Auth0 helps you to: 264 | 265 | * Add authentication with [multiple authentication sources](https://docs.auth0.com/identityproviders), either social like **Google, Facebook, Microsoft Account, LinkedIn, GitHub, Twitter, Box, Salesforce, amont others**, or enterprise identity systems like **Windows Azure AD, Google Apps, Active Directory, ADFS or any SAML Identity Provider**. 266 | * Add authentication through more traditional **[username/password databases](https://docs.auth0.com/mysql-connection-tutorial)**. 267 | * Add support for **[linking different user accounts](https://docs.auth0.com/link-accounts)** with the same user. 268 | * Support for generating signed [Json Web Tokens](https://docs.auth0.com/jwt) to call your APIs and **flow the user identity** securely. 269 | * Analytics of how, when and where users are logging in. 270 | * Pull data from other sources and add it to the user profile, through [JavaScript rules](https://docs.auth0.com/rules). 271 | 272 | ## Create a Free Auth0 Account 273 | 274 | 1. Go to [Auth0](https://auth0.com) and click Sign Up. 275 | 2. Use Google, GitHub or Microsoft Account to login. 276 | 277 | ## Issue Reporting 278 | 279 | If you have found a bug or if you have a feature request, please report them at this repository issues section. Please do not report security vulnerabilities on the public GitHub issue tracker. The [Responsible Disclosure Program](https://auth0.com/whitehat) details the procedure for disclosing security issues. 280 | 281 | ## Author 282 | 283 | [Auth0](auth0.com) 284 | 285 | ## License 286 | 287 | This project is licensed under the MIT license. See the [LICENSE](LICENSE) file for more info. 288 | -------------------------------------------------------------------------------- /src/auth/index.js: -------------------------------------------------------------------------------- 1 | import {router} from '../index' 2 | 3 | const API_URL = 'http://localhost:3001/' 4 | const LOGIN_URL = API_URL + 'sessions/create/' 5 | const SIGNUP_URL = API_URL + 'users/' 6 | 7 | export default { 8 | 9 | user: { 10 | authenticated: false 11 | }, 12 | 13 | login(context, creds, redirect) { 14 | context.$http.post(LOGIN_URL, creds, (data) => { 15 | localStorage.setItem('id_token', data.id_token) 16 | 17 | this.user.authenticated = true 18 | 19 | if(redirect) { 20 | router.go(redirect) 21 | } 22 | 23 | }).error((err) => { 24 | context.error = err 25 | }) 26 | }, 27 | 28 | signup(context, creds, redirect) { 29 | context.$http.post(SIGNUP_URL, creds, (data) => { 30 | localStorage.setItem('id_token', data.id_token) 31 | 32 | this.user.authenticated = true 33 | 34 | if(redirect) { 35 | router.go(redirect) 36 | } 37 | 38 | }).error((err) => { 39 | context.error = err 40 | }) 41 | }, 42 | 43 | logout() { 44 | localStorage.removeItem('id_token') 45 | this.user.authenticated = false 46 | }, 47 | 48 | checkAuth() { 49 | var jwt = localStorage.getItem('id_token') 50 | if(jwt) { 51 | this.user.authenticated = true 52 | } 53 | else { 54 | this.user.authenticated = false 55 | } 56 | }, 57 | 58 | 59 | getAuthHeader() { 60 | return { 61 | 'Authorization': 'Bearer ' + localStorage.getItem('id_token') 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/components/App.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 36 | -------------------------------------------------------------------------------- /src/components/Home.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | -------------------------------------------------------------------------------- /src/components/Login.vue: -------------------------------------------------------------------------------- 1 | 27 | 28 | -------------------------------------------------------------------------------- /src/components/SecretQuote.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | -------------------------------------------------------------------------------- /src/components/Signup.vue: -------------------------------------------------------------------------------- 1 | 27 | 28 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './components/App.vue' 3 | import Home from './components/Home.vue' 4 | import SecretQuote from './components/SecretQuote.vue' 5 | import Signup from './components/Signup.vue' 6 | import Login from './components/Login.vue' 7 | import VueRouter from 'vue-router' 8 | import VueResource from 'vue-resource' 9 | Vue.use(VueResource) 10 | Vue.use(VueRouter) 11 | import auth from './auth' 12 | 13 | Vue.http.headers.common['Authorization'] = 'Bearer ' + localStorage.getItem('id_token'); 14 | 15 | // Check the user's auth status when the app starts 16 | auth.checkAuth() 17 | 18 | export var router = new VueRouter() 19 | 20 | router.map({ 21 | '/home': { 22 | component: Home 23 | }, 24 | 'secretquote': { 25 | component: SecretQuote 26 | }, 27 | '/login': { 28 | component: Login 29 | }, 30 | '/signup': { 31 | component: Signup 32 | } 33 | }) 34 | 35 | router.redirect({ 36 | '*': '/home' 37 | }) 38 | 39 | router.start(App, '#app') 40 | 41 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | // the main entry of our app 3 | entry: ['./src/index.js', './src/auth/index.js'], 4 | // output configuration 5 | output: { 6 | path: __dirname + '/build/', 7 | publicPath: 'build/', 8 | filename: 'build.js' 9 | }, 10 | // how modules should be transformed 11 | module: { 12 | loaders: [ 13 | // process *.vue files using vue-loader 14 | { test: /\.vue$/, loader: 'vue' }, 15 | // process *.js files using babel-loader 16 | // the exclude pattern is important so that we don't 17 | // apply babel transform to all the dependencies! 18 | { test: /\.js$/, loader: 'babel', exclude: /node_modules/ } 19 | ] 20 | }, 21 | // configure babel-loader. 22 | // this also applies to the JavaScript inside *.vue files 23 | babel: { 24 | presets: ['es2015'], 25 | plugins: ['transform-runtime'] 26 | } 27 | } 28 | --------------------------------------------------------------------------------