Skip to content

Instantly share code, notes, and snippets.

@luishrd
Last active April 19, 2018 23:24
Show Gist options
  • Save luishrd/5f1d32223518c530752bb937dc077b4f to your computer and use it in GitHub Desktop.
Save luishrd/5f1d32223518c530752bb937dc077b4f to your computer and use it in GitHub Desktop.
{
"username": "peregrin",
"password": "took"
}
const express = require('express');
const morgan = require('morgan');
const helmet = require('helmet');
const cors = require('cors');
module.exports = function(server) {
server.use(helmet());
server.use(morgan('dev'));
server.use(express.json());
server.use(cors());
};
{
"name": "jwtting",
"version": "1.0.0",
"description": "",
"main": "server.js",
"scripts": {
"start": "nodemon server.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"nodemon": "^1.17.3"
},
"dependencies": {
"bcrypt": "^2.0.0",
"cors": "^2.8.4",
"express": "^4.16.3",
"helmet": "^3.12.0",
"jsonwebtoken": "^8.2.1",
"mongoose": "^5.0.15",
"morgan": "^1.9.0",
"passport": "^0.4.0",
"passport-jwt": "^4.0.0",
"passport-local": "^1.0.0"
}
}
const jwt = require('jsonwebtoken');
const passport = require('passport');
const LocalStrategy = require('passport-local');
const User = require('../users/User');
const secret = 'no size limit on tokens';
const { ExtractJwt } = require('passport-jwt');
const JwtStrategy = require('passport-jwt').Strategy;
// { usernameField: email }
const localStrategy = new LocalStrategy(function(username, password, done) {
User.findOne({ username }, function(err, user) {
if (err) {
done(err);
}
if (!user) {
done(null, false);
}
user.verifyPassword(password, function(err, isValid) {
if (err) {
return done(err);
}
if (isValid) {
const { _id, username, race } = user;
return done(null, { _id, username, race }); // placed on req.user
}
return done(null, false);
});
});
});
const jwtOptions = {
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
secretOrKey: secret,
};
const jwtStrategy = new JwtStrategy(jwtOptions, function(payload, done) {
User.findById(payload.sub)
.select('-password')
.then(user => {
if (user) {
done(null, user);
} else {
done(null, false);
}
})
.catch(err => {
return done(err, false);
});
});
passport.use(localStrategy);
passport.use(jwtStrategy); // new line
const authenticate = passport.authenticate('local', { session: false });
const protected = passport.authenticate('jwt', { session: false }); // new line
module.exports = function(server) {
server.get('/api/hobbits', protected, (req, res) => {
User.find({ race: 'hobbit' })
.select('-password')
.then(hobbits => {
res.json(hobbits);
})
.catch(err => {
res.status(500).json(err);
});
});
server.post('/api/login', authenticate, (req, res) => {
res.json({ token: makeToken(req.user), user: req.user });
});
// sanity check route
server.get('/', function(req, res) {
res.send({ api: 'up and running' });
});
server.post('/api/register', function(req, res) {
const credentials = req.body;
// add a pre('save') hook to the User schema
// that will hash the password before
// persisting the user to the database
const user = new User(credentials);
user.save().then(inserted => {
const token = makeToken(inserted);
res.status(201).json({ token });
});
});
};
function makeToken(user) {
// sub: subject (id) who the token is about
// iat: issued at time
const timestamp = new Date().getTime();
const payload = {
sub: user._id,
iat: timestamp,
username: user.username,
race: user.race,
};
const options = { expiresIn: '4h' };
return jwt.sign(payload, secret, options);
}
const express = require('express');
const mongoose = require('mongoose');
const server = express();
const setupMiddleware = require('./setup/middleware')(server);
const setupRoutes = require('./setup/routes')(server);
// alternatively we can do this in two steps like so:
// we first import the module
// const setupMiddleware = require('./setup/middleware');
// then execute it passing the server instance
// setupMiddleware(server);
mongoose
.connect('mongodb://localhost/auth')
.then(cnn => {
console.log('\n=== connected to mongo ===\n');
})
.catch(err => {
console.log('\n=== ERROR connecting to mongo ===\n');
});
server.listen(5000, () => console.log('\n=== API on port 5k ===\n'));
const mongoose = require('mongoose');
const bcrypt = require('bcrypt');
const userSchema = new mongoose.Schema({
username: {
type: String,
required: true,
unique: true,
lowercase: true,
// normalize all users to lowercase
// helps later when making queries
},
password: {
type: String,
required: true,
minlength: 4, // make this at least 10 or 12
// in a production application
},
race: {
type: String,
required: true,
},
});
userSchema.pre('save', function(next) {
// const user = this; // scope is the document
// you need to do this if the function passed to
// then is a regular function, not an arrow
// function to make sure the binding of this
// is correct. See code below.
// bcrypt.hash(this.password, 10).then(function(hash) {
bcrypt.hash(this.password, 10).then(hash => {
// different scope if using function(hash)
// same document scope if using arrow function
this.password = hash;
next();
});
});
userSchema.methods.verifyPassword = function(guess, callback) {
bcrypt.compare(guess, this.password, function(err, isValid) {
if (err) {
return callback(err);
}
// here there was no error
callback(null, isValid);
});
};
module.exports = mongoose.model('User', userSchema, 'users');
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment