├── views ├── index.pug ├── error.pug └── layout.pug ├── public ├── images │ ├── login.png │ └── success-message.png └── stylesheets │ └── style.css ├── routes ├── index.js └── auth.js ├── package.json ├── README.md ├── .gitignore ├── app.js └── bin └── www /views/index.pug: -------------------------------------------------------------------------------- 1 | extends layout 2 | 3 | block content 4 | h1= title 5 | p Welcome to #{title} 6 | -------------------------------------------------------------------------------- /public/images/login.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmchaves/node-passport-jwt-example-app/HEAD/public/images/login.png -------------------------------------------------------------------------------- /views/error.pug: -------------------------------------------------------------------------------- 1 | extends layout 2 | 3 | block content 4 | h1= message 5 | h2= error.status 6 | pre #{error.stack} 7 | -------------------------------------------------------------------------------- /public/images/success-message.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmchaves/node-passport-jwt-example-app/HEAD/public/images/success-message.png -------------------------------------------------------------------------------- /public/stylesheets/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding: 50px; 3 | font: 14px "Lucida Grande", Helvetica, Arial, sans-serif; 4 | } 5 | 6 | a { 7 | color: #00B7FF; 8 | } 9 | -------------------------------------------------------------------------------- /views/layout.pug: -------------------------------------------------------------------------------- 1 | doctype html 2 | html 3 | head 4 | title= title 5 | link(rel='stylesheet', href='/stylesheets/style.css') 6 | body 7 | block content 8 | -------------------------------------------------------------------------------- /routes/index.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var router = express.Router(); 3 | 4 | 5 | /* GET home page. */ 6 | router.get("/", function(req, res) { 7 | res.json({message: "Index is running!"}); 8 | }); 9 | 10 | module.exports = router; 11 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "myapp", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "start": "node ./bin/www" 7 | }, 8 | "dependencies": { 9 | "body-parser": "^1.18.2", 10 | "cookie-parser": "~1.4.3", 11 | "debug": "~2.6.9", 12 | "express": "^4.16.3", 13 | "hoek": "^5.0.3", 14 | "jsonwebtoken": "^8.2.1", 15 | "lodash": "^4.17.10", 16 | "morgan": "~1.9.0", 17 | "passport": "^0.4.0", 18 | "passport-jwt": "^3.0.1", 19 | "pug": "2.0.0-beta11", 20 | "serve-favicon": "~2.4.5" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## node-passport-jwt-example-app 2 | 3 | #### 1) Go to the project folder 4 | #### 2) npm install 5 | #### 3) npm start 6 | 7 | #### Make a post request to login, use `localhost:3000/auth/login/` 8 | #### Credentials: 9 | ##### name: `javier` 10 | ##### password: `password123` 11 | - You can use Postman 12 | 13 | 14 | #### Test the authentication, use `localhost:3000/auth/secret/` 15 | #### Header: 16 | ##### key: `Authorization` 17 | ##### value: `Bearer ` + token 18 | 19 | Example: 20 | Login: 21 | ![alt text](https://raw.githubusercontent.com/jmchaves/node-passport-jwt-example-app/master/public/images/login.png) 22 | 23 | Get secret message: 24 | ![alt text](https://raw.githubusercontent.com/jmchaves/node-passport-jwt-example-app/master/public/images/success-message.png) 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (http://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # Typescript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | var express = require('express'); 2 | var path = require('path'); 3 | var favicon = require('serve-favicon'); 4 | var logger = require('morgan'); 5 | var cookieParser = require('cookie-parser'); 6 | var bodyParser = require('body-parser'); 7 | 8 | var index = require('./routes/index'); 9 | var auth = require('./routes/auth'); 10 | 11 | var app = express(); 12 | 13 | // view engine setup 14 | app.set('views', path.join(__dirname, 'views')); 15 | app.set('view engine', 'pug'); 16 | 17 | // uncomment after placing your favicon in /public 18 | //app.use(favicon(path.join(__dirname, 'public', 'favicon.ico'))); 19 | app.use(logger('dev')); 20 | app.use(bodyParser.json()); 21 | app.use(bodyParser.urlencoded({ extended: false })); 22 | app.use(cookieParser()); 23 | app.use(express.static(path.join(__dirname, 'public'))); 24 | 25 | app.use('/', index); 26 | app.use('/auth', auth); 27 | 28 | // catch 404 and forward to error handler 29 | app.use(function(req, res, next) { 30 | var err = new Error('Not Found'); 31 | err.status = 404; 32 | next(err); 33 | }); 34 | 35 | // error handler 36 | app.use(function(err, req, res, next) { 37 | // set locals, only providing error in development 38 | res.locals.message = err.message; 39 | res.locals.error = req.app.get('env') === 'development' ? err : {}; 40 | 41 | // render the error page 42 | res.status(err.status || 500); 43 | res.render('error'); 44 | }); 45 | 46 | module.exports = app; 47 | -------------------------------------------------------------------------------- /bin/www: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | /** 4 | * Module dependencies. 5 | */ 6 | 7 | var app = require('../app'); 8 | var debug = require('debug')('myapp:server'); 9 | var http = require('http'); 10 | 11 | /** 12 | * Get port from environment and store in Express. 13 | */ 14 | 15 | var port = normalizePort(process.env.PORT || '3000'); 16 | app.set('port', port); 17 | 18 | /** 19 | * Create HTTP server. 20 | */ 21 | 22 | var server = http.createServer(app); 23 | 24 | /** 25 | * Listen on provided port, on all network interfaces. 26 | */ 27 | 28 | server.listen(port); 29 | server.on('error', onError); 30 | server.on('listening', onListening); 31 | 32 | /** 33 | * Normalize a port into a number, string, or false. 34 | */ 35 | 36 | function normalizePort(val) { 37 | var port = parseInt(val, 10); 38 | 39 | if (isNaN(port)) { 40 | // named pipe 41 | return val; 42 | } 43 | 44 | if (port >= 0) { 45 | // port number 46 | return port; 47 | } 48 | 49 | return false; 50 | } 51 | 52 | /** 53 | * Event listener for HTTP server "error" event. 54 | */ 55 | 56 | function onError(error) { 57 | if (error.syscall !== 'listen') { 58 | throw error; 59 | } 60 | 61 | var bind = typeof port === 'string' 62 | ? 'Pipe ' + port 63 | : 'Port ' + port; 64 | 65 | // handle specific listen errors with friendly messages 66 | switch (error.code) { 67 | case 'EACCES': 68 | console.error(bind + ' requires elevated privileges'); 69 | process.exit(1); 70 | break; 71 | case 'EADDRINUSE': 72 | console.error(bind + ' is already in use'); 73 | process.exit(1); 74 | break; 75 | default: 76 | throw error; 77 | } 78 | } 79 | 80 | /** 81 | * Event listener for HTTP server "listening" event. 82 | */ 83 | 84 | function onListening() { 85 | var addr = server.address(); 86 | var bind = typeof addr === 'string' 87 | ? 'pipe ' + addr 88 | : 'port ' + addr.port; 89 | debug('Listening on ' + bind); 90 | } 91 | -------------------------------------------------------------------------------- /routes/auth.js: -------------------------------------------------------------------------------- 1 | var _ = require("lodash"); 2 | var express = require("express"); 3 | var router = express.Router(); 4 | var bodyParser = require("body-parser"); 5 | var jwt = require('jsonwebtoken'); 6 | 7 | var passport = require("passport"); 8 | var passportJWT = require("passport-jwt"); 9 | 10 | var ExtractJwt = passportJWT.ExtractJwt; 11 | var JwtStrategy = passportJWT.Strategy; 12 | 13 | var users = [ 14 | { 15 | id: 1, 16 | name: 'javier', 17 | password: 'password123' 18 | } 19 | ]; 20 | 21 | var jwtOptions = {} 22 | jwtOptions.jwtFromRequest = ExtractJwt.fromAuthHeaderAsBearerToken(); 23 | jwtOptions.secretOrKey = 'mysecretword'; 24 | 25 | var strategy = new JwtStrategy(jwtOptions, function(jwt_payload, next) { 26 | console.log('payload received', jwt_payload); 27 | // usually this would be a database call: 28 | var user = users[_.findIndex(users, {id: jwt_payload.id})]; 29 | if (user) { 30 | next(null, user); 31 | } else { 32 | next(null, false); 33 | } 34 | }); 35 | 36 | passport.use(strategy); 37 | 38 | var app = express(); 39 | app.use(passport.initialize()); 40 | 41 | // parse application/x-www-form-urlencoded 42 | // for easier testing with Postman or plain HTML forms 43 | app.use(bodyParser.urlencoded({ 44 | extended: true 45 | })); 46 | 47 | // parse application/json 48 | app.use(bodyParser.json()) 49 | 50 | router.get("/", function(req, res) { 51 | res.json({message: "The app is running!"}); 52 | }); 53 | 54 | router.post("/login", function(req, res) { 55 | if(req.body.name && req.body.password){ 56 | var name = req.body.name; 57 | var password = req.body.password; 58 | } 59 | // usually this would be a database call: 60 | var user = users[_.findIndex(users, {name: name})]; 61 | if( ! user ){ 62 | res.status(401).json({message:"no such user found"}); 63 | } 64 | 65 | if(user.password === req.body.password) { 66 | // from now on we'll identify the user by the id and the id is the only personalized value that goes into our token 67 | var payload = {id: user.id}; 68 | var token = jwt.sign(payload, jwtOptions.secretOrKey); 69 | res.json({message: "ok", token: token}); 70 | } else { 71 | res.status(401).json({message:"invalid credentials"}); 72 | } 73 | }); 74 | 75 | router.get("/secret", passport.authenticate('jwt', { session: false }), function(req, res){ 76 | res.json({message: "Success!"}); 77 | }); 78 | 79 | router.get("/secretDebug", 80 | function(req, res, next){ 81 | console.log(req.get('Authorization')); 82 | next(); 83 | }, function(req, res){ 84 | res.json("debugging"); 85 | }); 86 | 87 | module.exports = router; 88 | --------------------------------------------------------------------------------