Learn by Directing AI
All materials

auth-guide.md

Authentication and Authorisation Guide

Authentication vs Authorisation

Authentication answers: "Who are you?" The user proves their identity -- typically with a username and password, sometimes with a third-party provider (Google, GitHub).

Authorisation answers: "What are you allowed to do?" After the system knows who you are, it checks whether your role permits the action you're requesting.

These are separate concerns. A system can have working authentication (everyone logs in successfully) and broken authorisation (everyone sees everything regardless of role). Broken Access Control is the #1 vulnerability on the OWASP Top 10 -- it means a logged-in user can access another user's data or perform actions their role shouldn't permit.

Sessions vs JWTs

Two approaches to maintaining auth state after login:

Sessions JWTs
Where state lives Server (database or memory store) Client (in the token itself)
Revocation Simple -- delete the session record Difficult -- token is valid until it expires
Scaling Requires shared session store across servers Stateless -- any server can verify the token
Storage cost Server memory/database None on server
Security surface Session fixation if not regenerated on login Token theft if stored insecurely
Complexity Simpler to implement correctly More moving parts (signing, verification, refresh tokens)
When to choose Most web applications, especially when revocation matters APIs consumed by multiple clients, microservice architectures

Neither is universally better. The choice depends on the application's requirements. For a patient records system where revoking access quickly matters (a compromised account should be locked immediately), sessions are often the simpler, more appropriate choice.

Password Hashing

Passwords must never be stored as plaintext or with reversible encryption.

bcrypt and argon2 are one-way hashing algorithms designed for passwords:

  • They include a built-in salt (random data added before hashing) so identical passwords produce different hashes
  • They have a configurable cost parameter that controls how long hashing takes
  • The cost should be tuned so hashing takes roughly 250ms on current hardware -- fast enough for login, slow enough to make brute force impractical
  • A bcrypt hash looks like: $2b$12$LJ3m4ys.RP3mJCjPGq1h7u8xGzV5YX9B3Ue1Y1fJG7/KDvRTBjxS6

The $2b$ prefix identifies the algorithm. The 12 is the cost factor. The rest is the salt and hash combined.

Trust Boundaries

A trust boundary separates code that has been verified from code that has not.

  • Above the boundary (server-side, after auth verification): Code can trust that the user is who they claim to be and that their role is what the session says it is
  • Below the boundary (client-side, before verification): Code cannot be trusted. Any user who can open browser DevTools can modify client-side state

This means: all authorisation decisions must be enforced on the server. Client-side role checks (hiding a button, removing a menu item) are visual guidance for the user interface. They are not security. A user who can construct an HTTP request -- and anyone with curl or Postman can -- bypasses the client entirely.

The trust boundary is not a line in your code. It's a design principle that determines where every security decision is enforced.

RBAC Patterns

Role-Based Access Control (RBAC) assigns permissions to roles, then assigns roles to users.

A typical implementation:

  • Users table: id, email, password_hash, role_id
  • Roles table: id, name (doctor, nurse, admin)
  • Permissions: either a separate permissions table or a middleware function that maps roles to allowed actions

The authorisation middleware pattern:

  1. Extract the session token from the request
  2. Validate the token (is it real? is it expired?)
  3. Look up the user and their role
  4. Check if the role permits the requested action
  5. Allow or deny (200 or 403)

Steps 1-3 are authentication. Steps 4-5 are authorisation. A common AI failure is implementing steps 1-3 and skipping 4-5 -- the middleware checks "is someone logged in?" but not "does their role permit this action?"

Secure Cookie Configuration

Session cookies should be configured with these flags:

  • httpOnly: true -- the cookie cannot be read by JavaScript. This prevents XSS attacks from stealing the session token
  • secure: true -- the cookie is only sent over HTTPS. This prevents the token from being intercepted on unencrypted connections
  • sameSite: 'lax' (or 'strict') -- the cookie is not sent with cross-site requests. This prevents CSRF attacks

A session token stored in localStorage has none of these protections. Any JavaScript running on the page -- including injected scripts from an XSS vulnerability -- can read localStorage. This is why sessions should use httpOnly cookies, not localStorage.

Common AI Auth Pitfalls

These are patterns AI generates that look correct but have security gaps:

  1. Client-side enforcement only. AI hides the admin button in React when user.role !== 'admin' but doesn't add middleware to the /api/admin routes. The button is hidden but the endpoint is open.

  2. localStorage for tokens. AI stores the JWT or session token in localStorage because it's simpler to demonstrate. Any XSS vulnerability exposes the token.

  3. Authentication without authorisation. AI creates middleware that checks if (!user) return 401 but never checks if (user.role !== requiredRole) return 403. Every logged-in user can access every endpoint.

  4. No rate limiting on login. AI generates a /api/auth/login endpoint with no rate limiting. An attacker can make thousands of login attempts per second.

  5. Informative error messages. AI generates login errors like "No account found with that email" or "Incorrect password" -- these tell an attacker which emails exist in the system. The safe response: "Invalid email or password" for both cases.

  6. Missing token expiry. AI generates JWT validation that checks the token signature but not the expiry. Tokens are valid forever once issued.

  7. Missing logout invalidation. AI generates a logout endpoint that clears the client-side cookie but doesn't invalidate the session on the server. The session token is still valid if someone intercepts it.