Implementing Authentication
1. Installing Passport.js
Example: Install
npm i passport passport-local passport-jwt passport-google-oauth20 bcrypt jsonwebtoken
2. Configuring Passport Middleware
Example: Init
import passport from "passport";
import "./auth/strategies.js"; // registers strategies
app.use(passport.initialize());
// app.use(passport.session()); // only if using sessions
3. Implementing Local Strategy
Example: Username/password
import { Strategy as LocalStrategy } from "passport-local";
import bcrypt from "bcrypt";
passport.use(new LocalStrategy({ usernameField: "email" }, async (email, password, done) => {
try {
const user = await db.users.findByEmail(email);
if (!user || !(await bcrypt.compare(password, user.passwordHash))) {
return done(null, false, { message: "Invalid credentials" });
}
return done(null, user);
} catch (err) { return done(err); }
}));
4. Serializing Users
5. Deserializing Users
Example: Load user from id
passport.deserializeUser(async (id, done) => {
try { done(null, await db.users.findById(id)); }
catch (err) { done(err); }
});
6. Using JWT Authentication
| Aspect | Recommendation |
|---|---|
| Algorithm | HS256 (shared secret) or RS256/EdDSA (key pair) |
| Access TTL | 5–15 min |
| Refresh TTL | 7–30 days, rotate on use |
| Storage | HttpOnly cookie (preferred) over localStorage |
7. Creating JWT Tokens
Example: jwt.sign
import jwt from "jsonwebtoken";
function issueTokens(user) {
const access = jwt.sign(
{ sub: user.id, role: user.role },
process.env.JWT_SECRET,
{ algorithm: "HS256", expiresIn: "15m", issuer: "api.example.com" }
);
const refresh = jwt.sign({ sub: user.id, typ: "refresh" }, process.env.JWT_REFRESH_SECRET, { expiresIn: "30d" });
return { access, refresh };
}
8. Verifying JWT Tokens
Example: Verify middleware
export function requireAuth(req, res, next) {
const token = (req.get("Authorization") || "").replace(/^Bearer\s+/i, "");
if (!token) return next(new HttpError(401, "Missing token"));
try {
req.user = jwt.verify(token, process.env.JWT_SECRET, { algorithms: ["HS256"] });
next();
} catch (err) {
next(new HttpError(401, "Invalid token"));
}
}
9. Implementing OAuth Strategies
Example: Google OAuth 2.0
import { Strategy as GoogleStrategy } from "passport-google-oauth20";
passport.use(new GoogleStrategy({
clientID: process.env.GOOGLE_ID,
clientSecret: process.env.GOOGLE_SECRET,
callbackURL: "/auth/google/callback"
}, async (accessToken, refreshToken, profile, done) => {
const user = await db.users.upsertFromGoogle(profile);
done(null, user);
}));
app.get("/auth/google", passport.authenticate("google", { scope: ["profile","email"] }));
app.get("/auth/google/callback", passport.authenticate("google", { session: false }),
(req, res) => res.json(issueTokens(req.user)));
10. Protecting Routes
Example: Apply requireAuth
app.get("/me", requireAuth, (req, res) => res.json(req.user));
app.use("/api/admin", requireAuth, requireRole("admin"), adminRouter);
11. Handling Login and Logout
Example: Login + logout (JWT cookie)
app.post("/login", passport.authenticate("local", { session: false }), (req, res) => {
const tokens = issueTokens(req.user);
res.cookie("rt", tokens.refresh, { httpOnly: true, secure: true, sameSite: "lax", path: "/auth/refresh" });
res.json({ accessToken: tokens.access });
});
app.post("/logout", (req, res) => {
res.clearCookie("rt", { path: "/auth/refresh" });
res.sendStatus(204);
});
12. Using bcrypt for Passwords
Example: Hash + compare
import bcrypt from "bcrypt";
const COST = 12;
const hash = await bcrypt.hash(password, COST);
const ok = await bcrypt.compare(password, user.passwordHash);
| Algorithm | 2026 Recommendation |
|---|---|
| bcrypt | OK — cost ≥ 12 |
| argon2id | Preferred (OWASP) RECOMMENDED |
| scrypt | Acceptable |
| MD5/SHA-1 | NEVER |