Using passport-local
and passport-github
we show how you could handle logins.
-
-
Save xeoncross/bae6f2c5be40bf0c6993089d4de2175e to your computer and use it in GitHub Desktop.
Demo for Passport.js authentication in a Node.js Express application
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"extends": "airbnb", | |
"parser": "babel-eslint", | |
"rules": { | |
"no-console": 0, | |
"react/jsx-filename-extension": 0, | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const passport = require("passport"); | |
const LocalStrategy = require("passport-local").Strategy; | |
var records = [ | |
{ id: 1, password: "password", email: "admin@example.com" }, | |
{ id: 2, password: "password", email: "user@example.com" } | |
]; | |
var findById = function(id, cb) { | |
process.nextTick(function() { | |
var idx = id - 1; | |
if (records[idx]) { | |
cb(null, records[idx]); | |
} else { | |
cb(new Error("User " + id + " does not exist")); | |
} | |
}); | |
}; | |
var findByEmail = function(email, cb) { | |
process.nextTick(function() { | |
for (var i = 0; i < records.length; i++) { | |
if (records[i].email == email) { | |
return cb(null, records[i]); | |
} else { | |
console.log(records[i].email, "!=", email); | |
} | |
} | |
return cb(null, null); | |
}); | |
}; | |
/** | |
* Sign in using Email and Password. | |
*/ | |
// The local strategy require a `verify` function which receives the credentials | |
// (`username` and `password`) submitted by the user. The function must verify | |
// that the password is correct and then invoke `cb` with a user object, which | |
// will be set at `req.user` in route handlers after authentication. | |
passport.use( | |
new LocalStrategy({ usernameField: "email" }, function(email, password, cb) { | |
findByEmail(email, function(err, user) { | |
if (err) { | |
return cb(err); | |
} | |
if (!user) { | |
console.log("user not found", email, password); | |
return cb(null, false, { error: "Invalid email or password." }); | |
} | |
if (user.password != password) { | |
console.log("password doesn't match"); | |
return cb(null, false, { error: "Invalid email or password." }); | |
} | |
return cb(null, user); | |
}); | |
}) | |
); | |
// Configure Passport authenticated session persistence. | |
// | |
// In order to restore authentication state across HTTP requests, Passport needs | |
// to serialize users into and deserialize users out of the session. The | |
// typical implementation of this is as simple as supplying the user ID when | |
// serializing, and querying the user record by ID from the database when | |
// deserializing. | |
passport.serializeUser(function(user, cb) { | |
console.log("serializeUser", user); | |
cb(null, user.id); | |
}); | |
passport.deserializeUser(function(id, cb) { | |
console.log("deserializeUser", id); | |
findById(id, function(err, user) { | |
if (err) { | |
return cb(err); | |
} | |
cb(null, user); | |
}); | |
}); | |
/** | |
* Login Required middleware. | |
*/ | |
const isAuthenticated = (req, res, next) => { | |
if (req.isAuthenticated()) { | |
return next(); | |
} | |
res.redirect("/login"); | |
}; | |
/** | |
* Authorization Required middleware. | |
* We only support passport-local so we don't need this | |
*/ | |
const isAuthorized = (req, res, next) => { | |
const provider = req.path.split("/").slice(-1)[0]; | |
const token = req.user.tokens.find(token => token.kind === provider); | |
if (token) { | |
next(); | |
} else { | |
res.redirect(`/auth/${provider}`); | |
} | |
}; | |
module.exports = { | |
isAuthorized, | |
isAuthenticated | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module.exports = { | |
github: { | |
clientId: "...", | |
clientSecret: "...", | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var passport = require("passport"); | |
var GithubStrategy = require("passport-github").Strategy; | |
const config = require("./config"); | |
passport.use( | |
new GithubStrategy( | |
{ | |
clientID: config.github.clientId, | |
clientSecret: config.github.clientSecret, | |
callbackURL: "http://localhost:3000/auth/github/callback", | |
passReqToCallback: true | |
}, | |
function(req, accessToken, refreshToken, profile, done) { | |
console.log(profile); | |
// placeholder for translating profile into your own custom user object. | |
// for now we will just use the profile object returned by GitHub | |
return done(null, profile); | |
} | |
) | |
); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"name": "simple_auth", | |
"version": "1.0.0", | |
"description": "", | |
"main": "server.js", | |
"scripts": { | |
"test": "echo \"Error: no test specified\" && exit 1" | |
}, | |
"author": "", | |
"license": "MIT", | |
"dependencies": { | |
"body-parser": "^1.18.2", | |
"express": "^4.13.3", | |
"express-session": "^1.11.3", | |
"express-validator": "^4.2.1", | |
"passport": "^0.3.0", | |
"passport-github": "^1.0.0", | |
"passport-local": "^1.0.0" | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var express = require("express"); | |
var passport = require("passport"); | |
var auth = require("./auth"); | |
var github = require("./github"); | |
const expressValidator = require("express-validator"); | |
const bodyParser = require("body-parser"); | |
const path = require("path"); | |
var app = express(); | |
app.use(expressValidator()); | |
app.use(bodyParser.json()); | |
app.use(bodyParser.urlencoded({ extended: true })); | |
app.use(express.static(path.join(__dirname, "public"), { maxAge: 1 })); | |
// Express and Passport Session | |
var session = require("express-session"); | |
app.use( | |
session({ | |
secret: process.env.SESSION_SECRET || "foobar", | |
resave: false, | |
saveUninitialized: false | |
}) | |
); | |
app.use(passport.initialize()); | |
app.use(passport.session()); | |
app.get("/login", (req, res) => { | |
const html = `<form method="POST" action="/login"> | |
<label>Email</label><input name="email" type="email" /><br><br> | |
<label>Password</label><input type="password" name="password" /><br> | |
<input type="submit" value="Login" /> | |
</form>`; | |
res.send(html); | |
}); | |
app.post("/login", (req, res, next) => { | |
console.log("app.post/login", req.body); | |
req.assert("email", "Email is not valid").isEmail(); | |
req.assert("password", "Password cannot be blank").notEmpty(); | |
req.sanitize("email").normalizeEmail({ gmail_remove_dots: false }); | |
const errors = req.validationErrors(); | |
if (errors) { | |
return res.json({ errors: errors }); | |
// return res.redirect('/login') | |
} | |
passport.authenticate("local", (err, user, info) => { | |
if (err) { | |
console.log("err", err); | |
return next(err); | |
} | |
if (!user) { | |
console.log("!user", info, user); | |
return res.json(info); | |
} | |
req.logIn(user, err => { | |
if (err) { | |
console.log("logIn", err); | |
return next(err); | |
} | |
console.log(user); | |
// If this is an API | |
// res.json({ user: user }); | |
// If this is a regular POST request | |
res.redirect("/"); | |
}); | |
})(req, res, next); | |
}); | |
// we will call this to start the GitHub Login process | |
app.get("/auth/github", passport.authenticate("github")); | |
// GitHub will call this URL | |
app.get( | |
"/auth/github/callback", | |
passport.authenticate("github", { failureRedirect: "/" }), | |
function(req, res) { | |
res.redirect("/"); | |
} | |
); | |
app.get("/", function(req, res) { | |
var html = | |
"<ul>\ | |
<li><a href='/auth/github'>GitHub</a></li>\ | |
<li><a href='/login'>Login</a></li>\ | |
<li><a href='/logout'>logout</a></li>\ | |
<li><a href='/admin'>Admin</a></li>\ | |
</ul>"; | |
// dump the user for debugging | |
if (req.isAuthenticated()) { | |
html += "<p>authenticated as user:</p>"; | |
html += "<pre>" + JSON.stringify(req.user, null, 4) + "</pre>"; | |
} | |
// dump the user for debugging | |
if (req.isAuthenticated()) { | |
html += "<p>authenticated as user:</p>"; | |
html += "<pre>" + JSON.stringify(req.user, null, 4) + "</pre>"; | |
} | |
res.send(html); | |
}); | |
app.get("/logout", function(req, res) { | |
req.logout(); | |
res.redirect("/"); | |
}); | |
app.get("/admin", auth.isAuthenticated, function(req, res) { | |
res.send("Private Admin Area"); | |
}); | |
const port = process.env.PORT || process.env.OPENSHIFT_NODEJS_PORT || 3000; | |
var server = app.listen(port, function() { | |
console.log( | |
"Example app listening at http://%s:%s", | |
server.address().address, | |
server.address().port | |
); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment