Skip to main content
Having completed a detailed look at authentication, this lesson focuses on authorization: verifying who can do what after identity is established. We’ll load Claude again, run an authorization review against the target application, and consolidate the findings, prioritized fixes, and ready-to-use remediation snippets.
A presentation slide titled "Authorization Implementation" with a dark curved shape on the right containing the word "Demo" in blue. A small "© Copyright KodeKloud" notice appears in the bottom-left.
Load the prompts and automation used for this assessment from the public repository: https://github.com/JeremyMorgan/Claude-Code-Reviewing-Prompts What to analyze
  • Authorization implementation across all routes and endpoints.
  • Broken Object Level Authorization (BOLA / IDOR).
  • Broken Function Level Authorization.
  • Missing authorization checks on sensitive endpoints (admin, bulk, debug).
  • Role-based access control (RBAC) correctness and deny-by-default enforcement.
  • Privilege escalation paths via update flows or misapplied defaults.
  • JWT validation on protected routes and token revocation checks.
  • Proper scope checking for API/service tokens and multi-tenant isolation.
  • Field-level authorization, bulk protections, and consistent error handling.
Authorization Implementation checklist (consolidated)
CheckWhat to verifyNotes / Example
Object-level authorization (BOLA/IDOR)Enforce ownership/tenant checks on GET/PUT/DELETE /:id and any identifier-based access.Validate IDs from URL/body/query against the authenticated user’s tenantId/userId.
Function-level authorizationEnsure server-side role/permission checks for all privileged routes.Don’t rely on client-side UI checks.
Sensitive endpoints protectedAudit for unprotected admin/debug/bulk export routes.Confirm middleware order: authN -> authZ -> handler.
RBAC mapping & deny-by-defaultMap roles to explicit permissions; prevent clients from setting roles.Store role assignments server-side only.
Privilege escalation vectorsBlock updates to fields like role, tenantId, isAdmin unless performed by authorized system flows.Add field-level checks in update handlers.
JWT verificationUse jwt.verify with algorithms, issuer, audience, and exp. Avoid trusting jwt.decode.Check jti/tokenVersion against a revocation list.
API token scope checksEnforce least-privilege scopes per token; separate user vs service tokens.Validate audience and intended usage.
Multi-tenant isolationFilter list/search endpoints by tenant, enforce server-side tenant constraints.Avoid client-provided tenant identifiers.
Bulk protectionsVerify ownership per item on bulk operations and limit sizes/rates.Fail-safe per-item checks.
Field-level authorizationHide sensitive fields (SSN, apiKey, secrets) from non-privileged roles.Use projection/serialization rules.
Error handling/resource enumerationReturn consistent 403 vs 404 to avoid leaking existence.Consider 404 when revealing existence is risky.
Middleware orderingEnsure no handlers run before auth middleware; check nested routers.Use top-level auth middleware where appropriate.
CORS & CSRFAvoid wildcard origins with credentials; if cookies used, enforce SameSite/CSRF tokens.Harden cross-site risks.
Open redirect protectionsValidate redirect/next parameters against an allowlist.Prevent phishing by open redirects.
Fallback/debug routesRemove or protect /seed, /reset, /debug in prod.Make admin-only or gated behind feature flags.
High-level summary (assessment snapshot)
  • Risk Score: 9.5/10 (Critical)
  • Critical issues identified:
    1. No authentication/authorization middleware — endpoints are unprotected beyond login.
    2. Weak JWT implementation — missing strict verification parameters; possible default secrets.
    3. No RBAC or object-level authorization — vulnerable to BOLA/IDOR.
    4. Inconsistent error handling — may leak resource existence.
This assessment indicates the application should not handle real user data in its current state. Immediate remediation is required before any production deployment.
Concrete remediation snippets
  1. Authentication middleware (verify JWT)
// middleware/authenticate.js
const jwt = require('jsonwebtoken');

const authenticateToken = (req, res, next) => {
  const authHeader = req.headers['authorization'] || '';
  const token = authHeader.startsWith('Bearer ') ? authHeader.slice(7) : null;

  if (!token) {
    return res.status(401).json({ error: 'Missing Authorization token' });
  }

  try {
    const payload = jwt.verify(token, process.env.JWT_SECRET, {
      algorithms: ['HS256'],
      issuer: process.env.JWT_ISS,   // e.g., 'your-app'
      audience: process.env.JWT_AUD // e.g., 'your-app-users'
    });
    // Keep minimal, validated claims only
    req.user = {
      userId: payload.userId,
      roles: payload.roles,
      tenantId: payload.tenantId,
      jti: payload.jti || payload.tokenVersion
    };
    return next();
  } catch (err) {
    return res.status(401).json({ error: 'Invalid or expired token' });
  }
};

module.exports = authenticateToken;
  1. Issuing JWTs with recommended claims (login handler)
// routes/auth.js (excerpt)
const jwt = require('jsonwebtoken');

const token = jwt.sign(
  {
    userId: user.id,
    email: user.email,
    roles: user.roles,               // array or minimal role identifiers
    tenantId: user.tenantId,         // multi-tenant context if applicable
    tokenVersion: user.tokenVersion, // used to revoke tokens server-side
    iat: Math.floor(Date.now() / 1000)
  },
  process.env.JWT_SECRET,
  {
    algorithm: 'HS256',
    issuer: process.env.JWT_ISS,
    audience: process.env.JWT_AUD,
    expiresIn: '15m' // short-lived access token
  }
);
  1. Object-level ownership authorization (authorizeOwnership middleware)
// middleware/authorizeOwnership.js
const pool = require('../db'); // adjust to your DB client

const authorizeOwnership = async (req, res, next) => {
  const resourceId = req.params.id;
  const userId = req.user && req.user.userId;

  if (!userId) {
    return res.status(401).json({ error: 'Unauthorized' });
  }

  try {
    const result = await pool.query(
      'SELECT user_id FROM resources WHERE id = $1',
      [resourceId]
    );

    if (result.rows.length === 0) {
      // Optionally hide existence to prevent enumeration
      return res.status(404).json({ error: 'Resource not found' });
    }

    if (result.rows[0].user_id !== userId) {
      return res.status(403).json({ error: 'Access denied' });
    }

    next();
  } catch (err) {
    next(err);
  }
};

module.exports = authorizeOwnership;
  1. Applying middleware and enforcing authN -> authZ -> handler order
// server.js (excerpt)
const express = require('express');
const authenticateToken = require('./middleware/authenticate');
const authorizeOwnership = require('./middleware/authorizeOwnership');
const app = express();

app.use(express.json());

// Public route
app.get('/', (req, res) => res.send('Public endpoint'));

// Protected route: authentication runs first, then ownership check, then handler
app.get('/api/resources/:id', authenticateToken, authorizeOwnership, async (req, res) => {
  // Safe to fetch and return resource because ownership was checked
  const resource = await getResourceById(req.params.id);
  res.json(resource);
});
Proof-of-Concept (what the assessment demonstrated)
# Anyone can access the public endpoint
curl http://localhost:3000/

# Login returns a JWT, but if routes do not validate it, downstream endpoints remain unprotected:
curl -X POST http://localhost:3000/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email":"test@example.com","password":"password123"}'
Recommended immediate actions (prioritized)
  1. Replace any default JWT secret (e.g., JWT_SECRET=your_jwt_secret_key_here) with a strong secret (256-bit recommended) stored in a secure secret manager.
  2. Implement and apply authentication middleware (jwt.verify with algorithms/issuer/audience) across all protected routes before any business logic.
  3. Add object-level ownership checks for all /:id and object-access routes; enforce deny-by-default for RBAC decisions.
  4. Audit and remove or strictly protect debug/admin routes (e.g., /seed, /reset, /debug) in production.
  5. Normalize error handling to avoid resource enumeration (use 404 for not-found and 403 for explicit access-denied where appropriate).
Full report and remediation expectations For each finding produce:
  • Title, Severity, CWE (if applicable)
  • Evidence (file/function/lines)
  • Why it matters
  • Exploitability notes
  • Minimal PoC (safe)
  • Code-level remediation snippets
  • Defense-in-depth guidance and recommended tests
Also produce a checklist diff marking each verification item as Pass / Fail / Not Applicable. Notes on LLM-generated code
  • LLMs synthesize examples from many sources and may suggest working but insecure defaults (weak secrets, missing validations). Treat generated code as a starting point: run automated security tests and manual code review to harden before production.
Suggested follow-up reviews
  • Input validation and sanitization for user- or bot-controlled inputs (prevent SQLi, injection).
  • Rate limiting and brute-force protections for sensitive routes.
  • Token revocation and refresh token patterns (rotate and revoke via tokenVersion/jti).
  • Logging, monitoring, and alerting for suspicious authorization failures.
Links and references

Watch Video