CLOSE

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.