Unit 4.2 · Tutorial 2

OAuth2 & Role-Based Access Control

Chapter 11 · Backend Development
~3 hours Advanced OAuth2 · Passport.js · RBAC · Security

Overview

OAuth2 enables third‑party authentication (Google, GitHub, etc.) without sharing passwords. Role‑Based Access Control (RBAC) defines what users can do based on their roles. This tutorial covers OAuth2 flows, Passport.js integration, RBAC implementation, and API security best practices.

Why this matters: OAuth2 improves user experience with social login. RBAC ensures users have the appropriate permissions. Both are critical for modern applications.

1. OAuth2 Fundamentals

OAuth2 is an authorization framework that allows third‑party applications to access user data without exposing credentials.

  • Resource Owner: The user.
  • Client: The application requesting access.
  • Authorization Server: Issues tokens (Google, GitHub).
  • Resource Server: Hosts protected resources.
// OAuth2 Authorization Code Flow 1. Client redirects user to Authorization Server 2. User authenticates and grants consent 3. Authorization Server redirects to Client with authorization code 4. Client exchanges code for access token 5. Client uses access token to access Resource Server

Grant types

  • Authorization Code: Most common, secure (uses client secret).
  • Implicit: Deprecated, less secure.
  • Client Credentials: Machine‑to‑machine.
  • Refresh Token: Used to obtain new access tokens.

2. Passport.js Integration

Passport.js is a popular authentication middleware for Node.js supporting OAuth2 and many other strategies.

npm install passport passport-google-oauth2 passport-github2
// Google OAuth2 with Passport const passport = require('passport'); const GoogleStrategy = require('passport-google-oauth2').Strategy; passport.use(new GoogleStrategy({ clientID: process.env.GOOGLE_CLIENT_ID, clientSecret: process.env.GOOGLE_CLIENT_SECRET, callbackURL: '/api/auth/google/callback', passReqToCallback: true, }, async (req, accessToken, refreshToken, profile, done) => { // Find or create user in database const user = await findOrCreateUser(profile); return done(null, user); })); // Routes app.get('/api/auth/google', passport.authenticate('google', { scope: ['profile', 'email'], })); app.get('/api/auth/google/callback', passport.authenticate('google', { failureRedirect: '/login' }), (req, res) => { // Successful authentication res.redirect('/dashboard'); } );
// GitHub OAuth2 const GitHubStrategy = require('passport-github2').Strategy; passport.use(new GitHubStrategy({ clientID: process.env.GITHUB_CLIENT_ID, clientSecret: process.env.GITHUB_CLIENT_SECRET, callbackURL: '/api/auth/github/callback', }, async (accessToken, refreshToken, profile, done) => { const user = await findOrCreateUser(profile); return done(null, user); }));

3. Role-Based Access Control (RBAC)

RBAC restricts access based on user roles (e.g., admin, user, moderator).

// User roles in JWT payload const token = jwt.sign({ userId: user.id, email: user.email, role: user.role, // 'admin', 'user', 'moderator' }, JWT_SECRET); // Authorization middleware const authorize = (...roles) => { return (req, res, next) => { const user = req.user; // from authenticate middleware if (!user || !roles.includes(user.role)) { return res.status(403).json({ error: 'Forbidden' }); } next(); }; }; // Usage // Only admins can access app.delete('/api/users/:id', authenticate, authorize('admin'), (req, res) => { // Delete user }); // Admins and moderators can access app.put('/api/posts/:id', authenticate, authorize('admin', 'moderator'), (req, res) => { // Update post });

Permissions model

// Fine‑grained permissions (CASL or custom) const permissions = { admin: ['read:all', 'write:all', 'delete:all'], moderator: ['read:all', 'write:posts', 'delete:posts'], user: ['read:own', 'write:own'], }; const hasPermission = (user, action) => { const userPermissions = permissions[user.role] || []; return userPermissions.includes(action); }; // Middleware for specific actions const can = (action) => { return (req, res, next) => { if (!hasPermission(req.user, action)) { return res.status(403).json({ error: 'Insufficient permissions' }); } next(); }; }; app.post('/api/admin', authenticate, can('write:all'), (req, res) => { // Admin only });

4. API Security Best Practices

  • HTTPS: Always use HTTPS in production.
  • Helmet: Set secure HTTP headers.
  • Rate limiting: Prevent brute‑force attacks.
  • Input validation: Validate and sanitize all inputs.
  • CORS: Restrict allowed origins.
  • JWT expiry: Set short‑lived access tokens with refresh tokens.
npm install helmet express-rate-limit cors
const helmet = require('helmet'); const rateLimit = require('express-rate-limit'); const cors = require('cors'); // Security middleware app.use(helmet()); // Rate limiting const limiter = rateLimit({ windowMs: 15 * 60 * 1000, // 15 minutes max: 100, // limit each IP to 100 requests per windowMs message: 'Too many requests from this IP', }); app.use('/api', limiter); // CORS app.use(cors({ origin: process.env.ALLOWED_ORIGINS?.split(',') || '*', credentials: true, })); // JWT refresh token app.post('/api/auth/refresh', async (req, res) => { const refreshToken = req.body.refreshToken; // Verify refresh token (stored in database) const user = await findUserByRefreshToken(refreshToken); if (!user) return res.status(401).json({ error: 'Invalid refresh token' }); const newToken = generateToken(user.id, user.email); res.json({ token: newToken }); });
OWASP Top 10: Always follow OWASP guidelines to protect against common vulnerabilities like injection, broken authentication, and XSS.

Quiz

Question 1

What is the primary purpose of OAuth2?

  • To encrypt user passwords
  • To allow third‑party access without sharing passwords
  • To store user sessions
  • To manage database connections
Show answer
B. To allow third‑party access without sharing passwords.

Question 2

Which Passport.js strategy is used for Google OAuth2?

  • passport-google
  • passport-google-oauth2
  • passport-oauth
  • passport-github
Show answer
B. passport-google-oauth2.

Question 3

What is the purpose of RBAC?

  • To authenticate users
  • To control access based on user roles
  • To encrypt data
  • To manage sessions
Show answer
B. To control access based on user roles.

Exercises

Exercise 1

Implement a Google OAuth2 login flow using Passport.js. Include the route definitions and the strategy configuration.

Sample answer
passport.use(new GoogleStrategy({ clientID: process.env.GOOGLE_CLIENT_ID, clientSecret: process.env.GOOGLE_CLIENT_SECRET, callbackURL: '/auth/google/callback', }, async (accessToken, refreshToken, profile, done) => { const user = await User.findOne({ googleId: profile.id }); if (user) return done(null, user); const newUser = new User({ googleId: profile.id, name: profile.displayName, email: profile.emails[0].value }); await newUser.save(); done(null, newUser); })); app.get('/auth/google', passport.authenticate('google', { scope: ['profile', 'email'] })); app.get('/auth/google/callback', passport.authenticate('google', { failureRedirect: '/login' }), (req, res) => { res.redirect('/dashboard'); });

Exercise 2

Add an `authorize` middleware that checks if the user has the `admin` role before allowing access to the `/api/admin` endpoint.

Sample answer
const authorize = (roles) => (req, res, next) => { if (!roles.includes(req.user.role)) { return res.status(403).json({ error: 'Forbidden' }); } next(); }; app.get('/api/admin', authenticate, authorize(['admin']), (req, res) => { res.json({ message: 'Admin access granted' }); });

Homework

Homework 1

Implement a full RBAC system for your capstone project. Define at least 3 roles (admin, editor, viewer) and create middleware that checks permissions for different endpoints.

Sample outline
  • Roles: admin, editor, viewer.
  • Permissions: Admin: full access. Editor: create/update posts. Viewer: read only.
  • Middleware: `authorize(['admin', 'editor'])`.
  • Implementation: Store role in JWT and check in middleware.

Mini‑Project

Enterprise Auth System

Build an enterprise authentication system with:

  • JWT authentication (login/register)
  • OAuth2 login with Google and GitHub
  • RBAC with 4 roles (admin, manager, user, guest)
  • Protected routes with role‑based permissions
  • Rate limiting and Helmet for security
  • Refresh token support
Sample outline
  • Auth: JWT + OAuth2 (Google/GitHub).
  • Roles: admin, manager, user, guest.
  • Permissions: admin (all), manager (manage users), user (own data), guest (read only).
  • Security: Helmet, rate limiting, CORS.
  • Refresh tokens: Stored in database, rotated on use.

Tutorial Summary

You learned OAuth2 fundamentals and Passport.js integration, implemented Role‑Based Access Control (RBAC), and applied API security best practices. These skills are essential for building secure, scalable applications with proper authentication and authorization.

Key takeaway: Authentication verifies identity, authorization controls access. Use OAuth2 for third‑party login and RBAC for fine‑grained permissions.