Skip to content

Instantly share code, notes, and snippets.

@callmephilip
Last active March 28, 2020 19:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save callmephilip/428f11a1bb28cace7fa8ba4b066c06de to your computer and use it in GitHub Desktop.
Save callmephilip/428f11a1bb28cace7fa8ba4b066c06de to your computer and use it in GitHub Desktop.
Passport.js + Meteor accounts
// http://blog.thebakery.io/meteor-accounts-auth-with-passportjs/
import bcrypt from 'bcrypt';
import crypto from 'crypto';
import express from 'express';
import mongoose from 'mongoose';
import passport from 'passport';
import { Strategy as LocalStrategy } from 'passport-local';
import { BasicStrategy } from 'passport-http';
const User = mongoose.model('users', new mongoose.Schema({
_id: String,
}, {
collection: 'users',
}));
function comparePasswords(password, hash, callback) {
bcrypt.compare(crypto.createHash('sha256').update(password).digest('hex'), hash, callback);
}
function deserializeUserPassport(id, done) {
User.findOne({ _id: id }, (err, userModel) => {
if (err) {
done(err);
} else {
if (!userModel) {
done();
return;
}
done(null, userModel.toJSON());
}
});
}
function getUserPassport(username, password, done) {
User.findOne({
'emails.address': username,
}, (findError, userModel) => {
if (findError) {
return done(findError);
}
if (!userModel) {
return done(null, false, { message: 'Incorrect username.' });
}
const user = userModel.toJSON();
comparePasswords(password, user.services.password.bcrypt, (hashError, goodPassword) => {
if (hashError) {
return done(hashError);
}
if (!goodPassword) {
return done(null, false, { message: 'Incorrect password.' });
}
return done(null, user);
});
});
}
passport.serializeUser((user, done) => done(null, user._id));
passport.deserializeUser(deserializeUserPassport);
// Passport auth strategy for basic username + password setup
// if you only want to use this server as an API endpoint, you can just remove this
// and keep BasicStrategy below
passport.use(new LocalStrategy(getUserPassport));
// Passport auth strategy for Basic Auth
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization
passport.use(new BasicStrategy(getUserPassport));
const app = express();
app.use(require('cookie-parser')());
app.use(require('body-parser').urlencoded({ extended: true }));
app.use(require('express-session')({ secret: 'keyboard cat', resave: true, saveUninitialized: true }));
app.use(passport.initialize());
app.use(passport.session());
const port = process.env.PORT || 3007;
app.get('/', (req, res) => {
// When logged in user object is attached to the request
if (!req.user) {
res.redirect('/login');
return;
}
res.send(`Hello ${req.user.emails[0].address}`);
});
app.get('/login', (req, res) => {
res.send(`<form action="/login" method="post">
<div>
<label>Username:</label>
<input type="text" name="username"/>
</div>
<div>
<label>Password:</label>
<input type="password" name="password"/>
</div>
<div>
<input type="submit" value="Log In"/>
</div>
</form>`);
});
app.post('/login', passport.authenticate('local', {
successRedirect: '/',
failureRedirect: '/error',
}));
// /api endpoint gets authentication via Basic Auth
// you auth by sending a base64 encoded username:password string via Authorization header
// see https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization
app.use('/api', passport.authenticate('basic', { session: false }));
app.post('/api/ping', (req, res) => {
res.send(`pong ${req.user.emails[0].address}`);
});
// eslint-disable-next-line
app.listen(port, async () => {
// eslint-disable-next-line
console.log(`API server running on ${port}!`);
await mongoose.connect(process.env.DATABASE_URL, { useNewUrlParser: true, useUnifiedTopology: true });
// eslint-disable-next-line
console.log('Connected to the database');
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment