Files
egg c8966477b9 feat: Initial commit - Task Reporter incident response system
Complete implementation of the production line incident response system (生產線異常即時反應系統) including:

Backend (FastAPI):
- User authentication with AD integration and session management
- Chat room management (create, list, update, members, roles)
- Real-time messaging via WebSocket (typing indicators, reactions)
- File storage with MinIO (upload, download, image preview)

Frontend (React + Vite):
- Authentication flow with token management
- Room list with filtering, search, and pagination
- Real-time chat interface with WebSocket
- File upload with drag-and-drop and image preview
- Member management and room settings
- Breadcrumb navigation
- 53 unit tests (Vitest)

Specifications:
- authentication: AD auth, sessions, JWT tokens
- chat-room: rooms, members, templates
- realtime-messaging: WebSocket, messages, reactions
- file-storage: MinIO integration, file management
- frontend-core: React SPA structure

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-01 17:42:52 +08:00

8.3 KiB

authentication Specification

Purpose

TBD - created by archiving change add-user-authentication. Update Purpose after archive.

Requirements

Requirement: User Login with Dual-Token Session Management

The system SHALL authenticate users by forwarding credentials to the Panjit AD authentication API (https://pj-auth-api.vercel.app/api/auth/login). Upon successful AD authentication, the system SHALL generate its own internal session token (separate from the AD token), encrypt the user's password using AES-256 encryption (for auto-refresh capability), and store all session data in the database. The internal token is returned to the client for subsequent requests.

Scenario: Successful login with valid credentials

  • WHEN a user submits username "ymirliu@panjit.com.tw" and password "4RFV5tgb6yhn" to POST /api/auth/login
  • THEN the system SHALL forward the credentials to the AD API
  • AND receive a 200 response with token and username fields
  • AND encrypt the password using Fernet symmetric encryption (AES-256)
  • AND generate a unique internal session token (UUID4)
  • AND estimate or record the AD token expiry time (e.g., current_time + 1 hour)
  • AND create a session record in the user_sessions table with: username, display_name (from AD), internal_token, ad_token, encrypted_password, ad_token_expires_at, refresh_attempt_count (default 0), last_activity (current time), created_at
  • AND return status 200 with JSON body {"token": "<internal_token>", "display_name": "<username>"}

Scenario: Password stored securely with encryption

  • WHEN a password is stored in the user_sessions table
  • THEN the system SHALL encrypt it using the Fernet encryption key from environment variable FERNET_KEY
  • AND the encrypted_password field SHALL contain ciphertext that differs from the plaintext
  • AND decrypting the ciphertext SHALL reproduce the original password exactly

Scenario: Failed login with invalid credentials

  • WHEN a user submits incorrect username or password to POST /api/auth/login
  • THEN the system SHALL forward the credentials to the AD API
  • AND receive a non-200 response (e.g., 401 Unauthorized)
  • AND return status 401 to the client with error message {"error": "Invalid credentials"}
  • AND NOT create any session record in the database

Scenario: AD API service unavailable

  • WHEN a user attempts to login but the AD API (https://pj-auth-api.vercel.app) is unreachable
  • THEN the system SHALL return status 503 with error message {"error": "Authentication service unavailable"}

Requirement: User Logout

The system SHALL provide a logout endpoint that deletes the user's session record from the database.

Scenario: Successful logout with valid internal token

  • WHEN an authenticated user sends POST /api/auth/logout with header Authorization: Bearer <valid_internal_token>
  • THEN the system SHALL delete the session record from the user_sessions table
  • AND return status 200 with {"message": "Logout successful"}

Scenario: Logout without authentication token

  • WHEN a user sends POST /api/auth/logout without the Authorization header
  • THEN the system SHALL return status 401 with {"error": "No authentication token provided"}

Requirement: Automatic AD Token Refresh with Retry Limit

The system SHALL automatically refresh the AD token before it expires (within 5 minutes of expiry) when the user makes any API request, using the encrypted password stored in the database. The system SHALL limit auto-refresh attempts to a maximum of 3 consecutive failures, after which the session is forcibly terminated (to handle cases where the AD password has been changed).

Scenario: Auto-refresh AD token on protected route access

  • WHEN an authenticated user accesses a protected endpoint with a valid internal_token
  • AND the stored ad_token will expire in less than 5 minutes (ad_token_expires_at - now < 5 minutes)
  • AND refresh_attempt_count is less than 3
  • THEN the system SHALL decrypt the encrypted_password from the database
  • AND re-authenticate with the AD API using the decrypted password
  • AND if authentication succeeds: update ad_token, ad_token_expires_at, reset refresh_attempt_count to 0
  • AND update the last_activity timestamp
  • AND allow the request to proceed normally

Scenario: No refresh needed for fresh AD token

  • WHEN an authenticated user accesses a protected endpoint with a valid internal_token
  • AND the stored ad_token will not expire within 5 minutes
  • THEN the system SHALL NOT call the AD API
  • AND update only the last_activity timestamp
  • AND allow the request to proceed

Scenario: Auto-refresh fails but retry limit not reached

  • WHEN an authenticated user accesses a protected endpoint triggering auto-refresh
  • AND the AD API returns 401 (password invalid or changed)
  • AND refresh_attempt_count is 0, 1, or 2
  • THEN the system SHALL increment refresh_attempt_count by 1
  • AND log the failed refresh attempt with timestamp for audit
  • AND return status 401 with {"error": "Token refresh failed. Please try again or re-login if issue persists."}
  • AND keep the session record in the database

Scenario: Auto-refresh fails 3 consecutive times - force logout

  • WHEN an authenticated user accesses a protected endpoint
  • AND refresh_attempt_count is already 2
  • AND the AD API returns 401 on the 3rd refresh attempt
  • THEN the system SHALL increment refresh_attempt_count to 3
  • AND delete the session record from the database
  • AND log the forced logout event with reason "Password may have been changed in AD"
  • AND return status 401 with {"error": "Session terminated. Your password may have been changed. Please login again."}

Scenario: Session blocked due to previous 3 failed refresh attempts

  • WHEN an authenticated user accesses a protected endpoint
  • AND refresh_attempt_count is already 3 (from previous failed refreshes)
  • THEN the system SHALL delete the session record immediately
  • AND return status 401 with {"error": "Session expired due to authentication failures. Please login again."}

Requirement: 3-Day Inactivity Timeout

The system SHALL automatically invalidate user sessions that have been inactive for more than 3 days (72 hours). Inactivity is measured by the last_activity timestamp, which is updated on every API request.

Scenario: Reject request from inactive session

  • WHEN a user accesses a protected endpoint with an internal_token
  • AND the last_activity timestamp is more than 3 days (72 hours) in the past
  • THEN the system SHALL delete the session record from the database
  • AND return status 401 with {"error": "Session expired due to inactivity. Please login again."}

Scenario: Active user maintains session across multiple days

  • WHEN a user logs in on Day 1
  • AND makes at least one API request every 2 days (Day 2, Day 4, Day 6, etc.)
  • THEN the system SHALL keep the session active indefinitely
  • AND update last_activity on each request
  • AND auto-refresh the AD token as needed

Requirement: Token-Based Authentication for Protected Routes

The system SHALL validate internal session tokens for protected API endpoints by checking the Authorization: Bearer <internal_token> header against the user_sessions table, enforcing inactivity timeout and auto-refreshing AD tokens when necessary.

Scenario: Access protected endpoint with valid active session

  • WHEN a request includes header Authorization: Bearer <valid_internal_token>
  • AND the session exists in user_sessions table
  • AND last_activity is within 3 days
  • THEN the system SHALL update last_activity to current time
  • AND check and refresh AD token if needed (per auto-refresh requirement)
  • AND allow the request to proceed with user identity available

Scenario: Access protected endpoint with invalid internal token

  • WHEN a request includes an internal_token that does not exist in the user_sessions table
  • THEN the system SHALL return status 401 with {"error": "Invalid or expired token"}

Scenario: Access protected endpoint without token

  • WHEN a request to a protected endpoint omits the Authorization header
  • THEN the system SHALL return status 401 with {"error": "Authentication required"}