# Authentication & Authorization Implementation This document describes the complete authentication and authorization system implemented for BuySellService. ## Overview The system implements a comprehensive security middleware chain that: 1. ✅ Validates JWT tokens from Authorization header 2. ✅ Applies rate limiting (per userId, fallback to IP) 3. ✅ Enforces coarse-grained authorization (route level) 4. ✅ Enforces fine-grained authorization (business logic) 5. ✅ Logs all API requests for audit ## Middleware Chain Order The middleware is applied in this **critical order**: ``` 1. requestContext → Extract IP, user agent, request ID 2. auditLogger → Attach audit logger to request 3. jwtAuthenticate → Validate JWT token, extract user info 4. rateLimiter → Apply rate limiting 5. coarseAuthorize → Route-level role checking 6. fineAuthorize → Business logic authorization (per route) 7. routeHandler → Actual business logic ``` ## Implementation Details ### 1. Request Context (`middleware/requestContext.js`) **Purpose**: Extract and attach request metadata **Extracts**: - Client IP (considers proxies) - User agent - Request ID (for tracing) - Request timestamp **Usage**: Applied globally first in middleware chain --- ### 2. JWT Authentication (`middleware/jwtAuthenticate.js`) **Purpose**: Validate JWT tokens and extract user information **Validates**: - ✅ Token signature - ✅ Token expiry - ✅ Issuer (iss) - ✅ Audience (aud) **Token Validation**: - **Calls auth service API**: All token validation is done by the auth service - **Endpoint**: `POST /auth/validate-token` on auth service - **Auth service validates**: Signature, expiry, issuer, audience, token_version (for logout-all) - **Response**: Returns `{ valid: true, payload: {...} }` or `{ valid: false, error: "..." }` **Extracts to `req.user`**: ```javascript { userId: payload.sub, // User ID role: payload.role, // User role (USER, ADMIN) userType: payload.user_type, phoneNumber: payload.phone_number, tokenVersion: payload.token_version, highAssurance: payload.high_assurance, tenantId: payload.tenant_id, // For multi-tenant apps } ``` **Error Responses**: - `401 Unauthorized` - Missing or invalid token **Environment Variables**: - `AUTH_SERVICE_URL` (required) - URL of the auth service (default: 'http://localhost:3000') - `AUTH_SERVICE_TIMEOUT` (optional) - Timeout for auth service calls in ms (default: 5000) --- ### 3. Rate Limiting (`middleware/rateLimiter.js`) **Purpose**: Prevent API abuse by limiting requests per user/IP **Strategy**: - **Preferred**: Rate limit per `userId` (if authenticated) - **Fallback**: Rate limit per IP (if not authenticated) **Storage**: - **Redis** (if available) - Distributed rate limiting - **In-memory** (fallback) - Single-instance rate limiting **Pre-configured Limiters**: - `rateLimiterRead` - 100 requests per 15 minutes (GET operations) - `rateLimiterWrite` - 20 requests per 15 minutes (POST, PUT, DELETE) - `rateLimiterSensitive` - 10 requests per hour (sensitive operations) **Response Headers**: ``` X-RateLimit-Limit: 100 X-RateLimit-Remaining: 95 X-RateLimit-Reset: 2024-01-20T15:30:00Z X-RateLimit-Type: read ``` **Error Responses**: - `429 Too Many Requests` - Rate limit exceeded **Environment Variables**: - `REDIS_URL` (optional) - Redis connection URL - `RATE_LIMIT_MAX_REQUESTS` (optional, default: 100) - `RATE_LIMIT_WINDOW_SECONDS` (optional, default: 900) --- ### 4. Coarse-Grained Authorization (`middleware/coarseAuthorize.js`) **Purpose**: Route-level role-based access control **Route-to-Role Mapping**: ```javascript '/admin/*' → ['ADMIN'] '/users/*' → ['USER', 'ADMIN'] '/orders/*' → ['USER', 'ADMIN'] '/listings/*' → ['USER', 'ADMIN'] '/locations/*' → ['USER', 'ADMIN'] '/chat/*' → ['USER', 'ADMIN'] '*' → ['USER', 'ADMIN'] // Default ``` **Usage**: ```javascript // Use route mapping const requireUserOrAdmin = createCoarseAuthorize(); // Or specify roles explicitly const requireAdmin = createCoarseAuthorize(['ADMIN']); ``` **Error Responses**: - `403 Forbidden` - User role doesn't match required roles --- ### 5. Fine-Grained Authorization (`middleware/fineAuthorize.js`) **Purpose**: Business logic level authorization (resource ownership, action permissions) **Authorization Rules**: **Users**: - ✅ Users can read their own profile - ✅ Users can update their own profile - ❌ Users cannot access other users' data (unless admin) **Orders**: - ✅ Users can create orders - ✅ Users can read/update/delete their own orders - ❌ Users cannot access other users' orders **Listings**: - ✅ Users can create listings - ✅ Users can read all active listings (public) - ✅ Users can update/delete their own listings **Usage**: ```javascript router.get('/users/:id', fineAuthorize({ action: 'read', resource: 'user', getResourceOwnerId: (req) => req.params.id, }), handler ); ``` **Helper Function**: ```javascript const result = authorizeAction({ user: req.user, action: 'read', resource: 'user', resourceOwnerId: userId, }); if (!result.authorized) { // Handle unauthorized } ``` **Error Responses**: - `403 Forbidden` - Action not authorized on resource --- ### 6. Audit Logging (`services/auditLogger.js`) **Purpose**: Log all API requests for security auditing **Logged Information**: - Timestamp - Request ID - User ID - Action - Route - HTTP Method - Status (success, failed, forbidden, etc.) - Client IP - User Agent - Additional metadata **Usage**: ```javascript // Automatic logging via middleware req.auditLogger.logSuccess('get_user', { userId: id }); req.auditLogger.logFailure('get_user', 'User not found', { userId: id }); req.auditLogger.logForbidden('get_user', 'Access denied', { userId: id }); ``` **Storage**: - Currently logs to console and in-memory store - TODO: Integrate with external logging service (CloudWatch, Elasticsearch, etc.) --- ## Example: GET /users/:userId Endpoint Here's how the complete flow works for `GET /users/:userId`: ``` 1. Request arrives with: Authorization: Bearer 2. requestContext → Extracts IP: 192.168.1.1 → Extracts User-Agent: Android App → Generates Request-ID: abc123 3. auditLogger → Attaches logger to req.auditLogger 4. jwtAuthenticate → Validates JWT token → Extracts: userId = "user-123", role = "USER" → Sets: req.user = { userId: "user-123", role: "USER", ... } 5. rateLimiterRead → Checks rate limit for user-123 → Count: 5/100 (under limit) → Sets headers: X-RateLimit-Remaining: 95 6. coarseAuthorize → Checks route: /users/:id → Required roles: ['USER', 'ADMIN'] → User role: 'USER' ✅ → Allows request 7. fineAuthorize → Action: 'read' → Resource: 'user' → Resource owner: req.params.id = "user-456" → Checks: Can user-123 read user-456? → Rule: Users can only read their own profile → Result: user-123 !== user-456 → ❌ Unauthorized → Returns: 403 Forbidden (unless user-123 === user-456 or user-123 is ADMIN) 8. routeHandler → Fetches user from database → Returns user data → Logs success via req.auditLogger ``` --- ## Configuration ### Environment Variables Create a `.env` file: ```env # Server PORT=3200 TRUST_PROXY=false # JWT (REQUIRED - must match auth service) JWT_ACCESS_SECRET=your_jwt_secret_here JWT_ISSUER=farm-auth-service JWT_AUDIENCE=mobile-app # Rate Limiting (Optional) REDIS_URL=redis://localhost:6379 RATE_LIMIT_READ_MAX=100 RATE_LIMIT_READ_WINDOW=900 # Auth Service (Optional - for centralized validation) VALIDATE_VIA_AUTH_SERVICE=false AUTH_SERVICE_URL=http://localhost:3000 ``` --- ## Testing ### Test with Valid Token ```bash # Get token from auth service (via login) TOKEN="your_access_token_here" # Test GET /users/:userId curl -X GET http://localhost:3200/users/user-123 \ -H "Authorization: Bearer $TOKEN" ``` ### Test without Token (Should return 401) ```bash curl -X GET http://localhost:3200/users/user-123 # Returns: 401 Unauthorized ``` ### Test with Invalid Token (Should return 401) ```bash curl -X GET http://localhost:3200/users/user-123 \ -H "Authorization: Bearer invalid_token" # Returns: 401 Unauthorized ``` ### Test Rate Limiting (Should return 429 after limit) ```bash # Make many rapid requests for i in {1..101}; do curl -X GET http://localhost:3200/users/user-123 \ -H "Authorization: Bearer $TOKEN" done # After 100 requests, returns: 429 Too Many Requests ``` --- ## Security Features ✅ **JWT Token Validation**: Signature, expiry, issuer, audience ✅ **Rate Limiting**: Per-user and per-IP ✅ **Role-Based Access Control**: Route-level and resource-level ✅ **Audit Logging**: All requests logged with context ✅ **No Cookies**: Uses Bearer tokens only ✅ **No Server-Side Token Storage**: Stateless JWT validation ✅ **HTTPS Assumed**: No certificate handling in app code --- ## Files Structure ``` Backend/ ├── middleware/ │ ├── requestContext.js # Request metadata extraction │ ├── jwtAuthenticate.js # JWT token validation │ ├── rateLimiter.js # Rate limiting │ ├── coarseAuthorize.js # Route-level authorization │ └── fineAuthorize.js # Business logic authorization ├── services/ │ └── auditLogger.js # Audit logging service ├── routes/ │ └── userRoutes.js # User routes with auth middleware └── server.js # Server setup with middleware chain ``` --- ## Next Steps 1. **Install Dependencies**: ```bash cd Backend npm install ``` 2. **Configure Environment**: ```bash cp .env.example .env # Edit .env with your JWT_ACCESS_SECRET from auth service ``` 3. **Start Server**: ```bash npm start ``` 4. **Test Endpoint**: - Use Android app to call GET /users/:userId - Verify authentication and authorization work correctly --- ## Integration with Auth Service The BuySellService calls the auth service API to validate JWT tokens. All token validation logic is centralized in the auth service. **Token Flow**: 1. User logs in via auth service → Receives JWT token 2. Android app stores token securely 3. Android app sends token in `Authorization: Bearer ` header to BuySellService 4. BuySellService extracts token and calls auth service: `POST /auth/validate-token` 5. Auth service validates token (signature, expiry, token_version, claims) and returns user info 6. BuySellService receives validated user info and attaches to `req.user` 7. BuySellService continues with authorization checks and processes request **Auth Service Endpoint**: - `POST /auth/validate-token` - Request: `{ token: "..." }` - Response (valid): `{ valid: true, payload: { sub, role, user_type, ... } }` - Response (invalid): `{ valid: false, error: "..." }` **Benefits of Centralized Validation**: - ✅ Single source of truth for token validation - ✅ Token version checking (for logout-all functionality) handled centrally - ✅ No need to share JWT secrets between services - ✅ Easier to update validation logic in one place