Authentication means verifying a user's identity.
Authorization determines what the user is allowed to do.
1️⃣ Session Management
How It Works:
- When a user logs in, the server creates a session and stores user data (like an ID) in memory or a persistent store.
- A session ID is sent back to the client as a cookie.
- On subsequent requests, the cookie is used to retrieve the session data.
Example with Express:
const session = require('express-session');
app.use(session({
secret: 'your-secret-key', // used to sign the session ID cookie
resave: false,
saveUninitialized: true,
cookie: { secure: false } // set to true when using HTTPS in production
}));
app.get('/login', (req, res) => {
// After successful login:
req.session.user = { id: 1, name: 'Alice' };
res.send('Logged in!');
});
Pros & Cons:
- Pros: Simple to implement and stateful.
- Cons: May not scale well without a shared session store when using multiple servers.
2️⃣ JWT (JSON Web Tokens)
How It Works
- Upon successful login, the server creates a signed token (JWT) that encodes user information.
- The token is sent to the client, which stores it (often in localStorage or a cookie).
- With each request, the client sends the token (typically in the
Authorization
header), and the server verifies it.
Example with Express and jsonwebtoken:
const jwt = require('jsonwebtoken');
// Issue token on login
app.post('/login', (req, res) => {
// Validate user credentials here...
const user = { id: 1, name: 'Alice' };
const token = jwt.sign(user, 'your-secret-key', { expiresIn: '1h' });
res.json({ token });
});
// Middleware to protect routes
const authenticateJWT = (req, res, next) => {
const authHeader = req.headers.authorization;
if (authHeader) {
// Bearer token format
const token = authHeader.split(' ')[1];
jwt.verify(token, 'your-secret-key', (err, user) => {
if (err) {
return res.sendStatus(403);
}
req.user = user;
next();
});
} else {
res.sendStatus(401);
}
};
app.get('/protected', authenticateJWT, (req, res) => {
res.send('This is a protected route.');
});
Pros & Cons:
- Pros: Stateless, scalable, and well-suited for distributed systems.
- Cons: Token revocation and secure storage on the client can be challenging.
3️⃣ OAuth Integration
How It Works
- OAuth is a protocol that allows users to authenticate using third-party providers (e.g., Google, Facebook).
- The application redirects the user to the provider's login page.
- After login, the provider redirects back to your application with an authorization code or token that you can exchange for user data.
Example with Express and Passport.js (Google OAuth):
const passport = require('passport');
const GoogleStrategy = require('passport-google-oauth20').Strategy;
// Configure Passport with the Google strategy
passport.use(new GoogleStrategy({
clientID: 'YOUR_GOOGLE_CLIENT_ID',
clientSecret: 'YOUR_GOOGLE_CLIENT_SECRET',
callbackURL: '/auth/google/callback'
},
(accessToken, refreshToken, profile, done) => {
// Find or create user logic goes here
return done(null, profile);
}
));
// Initialize Passport
app.use(passport.initialize());
app.use(passport.session());
// Route to start OAuth flow
app.get('/auth/google', passport.authenticate('google', { scope: ['profile', 'email'] }));
// Callback route for Google to redirect to
app.get('/auth/google/callback',
passport.authenticate('google', { failureRedirect: '/login' }),
(req, res) => {
// Successful authentication
res.redirect('/');
}
);
Pros & Cons:
- Pros: Offloads authentication to trusted providers; users often prefer signing in with a familiar service.
- Cons: Adds complexity; requires managing third-party tokens and callback routes.