# Backend Authentication & Authorization

Modern authentication patterns including OAuth 2.1, JWT, RBAC, and MFA (2025 standards).

## OAuth 2.1 (2025 Standard)

### Key Changes from OAuth 2.0

**Mandatory:**

- PKCE (Proof Key for Code Exchange) for all clients
- Exact redirect URI matching
- State parameter for CSRF protection

**Deprecated:**

- Implicit grant flow (security risk)
- Resource owner password credentials grant
- Bearer token in query strings

### Authorization Code Flow with PKCE

```typescript
// Step 1: Generate code verifier and challenge
import crypto from "crypto";

const codeVerifier = crypto.randomBytes(32).toString("base64url");
const codeChallenge = crypto
  .createHash("sha256")
  .update(codeVerifier)
  .digest("base64url");

// Step 2: Redirect to authorization endpoint
const authUrl = new URL("https://auth.example.com/authorize");
authUrl.searchParams.set("client_id", "your-client-id");
authUrl.searchParams.set("redirect_uri", "https://app.example.com/callback");
authUrl.searchParams.set("response_type", "code");
authUrl.searchParams.set("scope", "openid profile email");
authUrl.searchParams.set("state", crypto.randomBytes(16).toString("hex"));
authUrl.searchParams.set("code_challenge", codeChallenge);
authUrl.searchParams.set("code_challenge_method", "S256");

// Step 3: Exchange code for token (with code_verifier)
const tokenResponse = await fetch("https://auth.example.com/token", {
  method: "POST",
  headers: { "Content-Type": "application/x-www-form-urlencoded" },
  body: new URLSearchParams({
    grant_type: "authorization_code",
    code: authCode,
    redirect_uri: redirectUri,
    client_id: clientId,
    code_verifier: codeVerifier,
  }),
});
```

## JWT (JSON Web Tokens)

### Structure

```
Header.Payload.Signature
eyJhbGciOi...  .  eyJzdWIiOi...  .  SflKxwRJ...
```

### Best Practices (2025)

1. **Short expiration** - Access tokens: 15 minutes, Refresh tokens: 7 days
2. **Use RS256** - Asymmetric signing (not HS256 for public APIs)
3. **Validate everything** - Signature, issuer, audience, expiration
4. **Include minimal claims** - Don't include sensitive data
5. **Refresh token rotation** - Issue new refresh token on each use

### Implementation

```typescript
import jwt from "jsonwebtoken";

// Generate JWT
const accessToken = jwt.sign(
  {
    sub: user.id,
    email: user.email,
    roles: user.roles,
  },
  process.env.JWT_PRIVATE_KEY,
  {
    algorithm: "RS256",
    expiresIn: "15m",
    issuer: "https://api.example.com",
    audience: "https://app.example.com",
  },
);

// Verify JWT
const decoded = jwt.verify(token, process.env.JWT_PUBLIC_KEY, {
  algorithms: ["RS256"],
  issuer: "https://api.example.com",
  audience: "https://app.example.com",
});
```

## Role-Based Access Control (RBAC)

### RBAC Model

```
Users → Roles → Permissions → Resources
```

### Implementation (NestJS Example)

```typescript
// Define roles
export enum Role {
  ADMIN = 'admin',
  EDITOR = 'editor',
  VIEWER = 'viewer',
}

// Role decorator
export const Roles = (...roles: Role[]) => SetMetadata('roles', roles);

// Guard implementation
@Injectable()
export class RolesGuard implements CanActivate {
  constructor(private reflector: Reflector) {}

  canActivate(context: ExecutionContext): boolean {
    const requiredRoles = this.reflector.get<Role[]>('roles', context.getHandler());
    if (!requiredRoles) return true;

    const request = context.switchToHttp().getRequest();
    const user = request.user;

    return requiredRoles.some((role) => user.roles?.includes(role));
  }
}

// Usage
@Post()
@UseGuards(JwtAuthGuard, RolesGuard)
@Roles(Role.ADMIN, Role.EDITOR)
async createPost(@Body() createPostDto: CreatePostDto) {
  return this.postsService.create(createPostDto);
}
```

### RBAC Best Practices

1. **Deny by default** - Explicitly grant permissions
2. **Least privilege** - Minimum permissions needed
3. **Role hierarchy** - Admin inherits Editor inherits Viewer
4. **Separate roles and permissions** - Flexible permission assignment
5. **Audit trail** - Log role changes and access

## Multi-Factor Authentication (MFA)

### TOTP (Time-Based One-Time Password)

```typescript
import speakeasy from "speakeasy";
import QRCode from "qrcode";

// Generate secret
const secret = speakeasy.generateSecret({
  name: "MyApp",
  issuer: "MyCompany",
});

// Generate QR code for user
const qrCode = await QRCode.toDataURL(secret.otpauth_url);

// Verify TOTP token
const verified = speakeasy.totp.verify({
  secret: secret.base32,
  encoding: "base32",
  token: userToken,
  window: 2, // Allow 2 time steps drift
});
```

### FIDO2/WebAuthn (Passwordless - 2025 Standard)

**Benefits:**

- Phishing-resistant
- No shared secrets
- Hardware-backed security
- Better UX (biometrics, security keys)

**Implementation:**

```typescript
// Registration
const publicKeyCredentialCreationOptions = {
  challenge: crypto.randomBytes(32),
  rp: { name: "MyApp", id: "example.com" },
  user: {
    id: Buffer.from(user.id),
    name: user.email,
    displayName: user.name,
  },
  pubKeyCredParams: [{ alg: -7, type: "public-key" }], // ES256
  authenticatorSelection: {
    authenticatorAttachment: "platform", // 'platform' or 'cross-platform'
    userVerification: "required",
  },
  timeout: 60000,
  attestation: "direct",
};

// Use @simplewebauthn/server library
import {
  verifyRegistrationResponse,
  verifyAuthenticationResponse,
} from "@simplewebauthn/server";
```

## Session Management

### Best Practices

1. **Secure cookies** - HttpOnly, Secure, SameSite=Strict
2. **Session timeout** - Idle: 15 minutes, Absolute: 8 hours
3. **Regenerate session ID** - After login, privilege elevation
4. **Server-side storage** - Redis for distributed systems
5. **CSRF protection** - SameSite cookies + CSRF tokens

### Implementation

```typescript
import session from "express-session";
import RedisStore from "connect-redis";
import { createClient } from "redis";

const redisClient = createClient();
await redisClient.connect();

app.use(
  session({
    store: new RedisStore({ client: redisClient }),
    secret: process.env.SESSION_SECRET,
    resave: false,
    saveUninitialized: false,
    cookie: {
      secure: true, // HTTPS only
      httpOnly: true, // No JavaScript access
      sameSite: "strict", // CSRF protection
      maxAge: 1000 * 60 * 15, // 15 minutes
    },
  }),
);
```

## Password Security

### Argon2id (2025 Standard - Replaces bcrypt)

**Why Argon2id:**

- Winner of Password Hashing Competition (2015)
- Memory-hard (resistant to GPU/ASIC attacks)
- Configurable CPU and memory cost
- Combines Argon2i (data-independent) + Argon2d (data-dependent)

```typescript
import argon2 from "argon2";

// Hash password
const hash = await argon2.hash("password123", {
  type: argon2.argon2id,
  memoryCost: 65536, // 64 MB
  timeCost: 3, // 3 iterations
  parallelism: 4, // 4 threads
});

// Verify password
const valid = await argon2.verify(hash, "password123");
```

### Password Policy (2025 NIST Guidelines)

- **Minimum length:** 12 characters (not 8)
- **No composition rules** - Allow passphrases
- **Check against breach databases** - HaveIBeenPwned API
- **No periodic rotation** - Only on compromise
- **Allow all printable characters** - Including spaces, emojis

## API Key Authentication

### Best Practices

1. **Prefix keys** - `sk_live_`, `pk_test_` (identify type/environment)
2. **Hash stored keys** - Store SHA-256 hash, not plaintext
3. **Key rotation** - Allow users to rotate keys
4. **Scope limiting** - Separate keys for read/write operations
5. **Rate limiting** - Per API key limits

```typescript
// Generate API key
const apiKey = `sk_${env}_${crypto.randomBytes(24).toString("base64url")}`;

// Store hashed version
const hashedKey = crypto.createHash("sha256").update(apiKey).digest("hex");
await db.apiKeys.create({ userId, hashedKey, scopes: ["read"] });

// Validate API key
const providedHash = crypto
  .createHash("sha256")
  .update(providedKey)
  .digest("hex");
const keyRecord = await db.apiKeys.findOne({ hashedKey: providedHash });
```

## Authentication Decision Matrix

| Use Case               | Recommended Approach                |
| ---------------------- | ----------------------------------- |
| Web application        | OAuth 2.1 + JWT                     |
| Mobile app             | OAuth 2.1 + PKCE                    |
| SPA (Single Page App)  | OAuth 2.1 Authorization Code + PKCE |
| Server-to-server       | Client credentials grant + mTLS     |
| Third-party API access | API keys with scopes                |
| High-security          | WebAuthn/FIDO2 + MFA                |
| Internal admin         | JWT + RBAC + MFA                    |
| Microservices          | Service mesh (mTLS) + JWT           |

## Security Checklist

- [ ] OAuth 2.1 with PKCE implemented
- [ ] JWT tokens expire in 15 minutes
- [ ] Refresh token rotation enabled
- [ ] RBAC with deny-by-default
- [ ] MFA required for admin accounts
- [ ] Passwords hashed with Argon2id
- [ ] Session cookies: HttpOnly, Secure, SameSite
- [ ] Rate limiting on auth endpoints (10 attempts/15 min)
- [ ] Account lockout after failed attempts
- [ ] Password policy: 12+ chars, breach check
- [ ] Audit logging for authentication events

## Resources

- **OAuth 2.1:** https://oauth.net/2.1/
- **JWT Best Practices:** https://datatracker.ietf.org/doc/html/rfc8725
- **WebAuthn:** https://webauthn.guide/
- **NIST Password Guidelines:** https://pages.nist.gov/800-63-3/
- **OWASP Auth Cheat Sheet:** https://cheatsheetseries.owasp.org/cheatsheets/Authentication_Cheat_Sheet.html
