- Added comprehensive JWT_AUTHENTICATION.md documentation - Covers backend (JwtAuthenticationHandler, LoginEndpoint) and frontend (useAuthApi, LoginPage) - Includes configuration for development and production modes - Security considerations and best practices - Token refresh enhancement recommendations - Testing guide and troubleshooting - API contract documentation - Deployment checklist - Added appsettings.Release.json for production JWT configuration - Placeholders for environment-specific values (JWT_KEY) - Proper listen address (0.0.0.0:5002) for containerized deployments Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
6.6 KiB
JWT Token Authentication
Overview
K-ArtSell Aegis uses JWT (JSON Web Token) for production authentication, replacing the Development-only header-based authentication.
Architecture
Backend (ASP.NET Core)
JwtAuthenticationHandler (src/KArtSell.Host/Security/JwtAuthenticationHandler.cs)
- Validates Bearer tokens from
Authorizationheader - Verifies signature using HS256 algorithm
- Validates issuer, audience, and expiration
- Extracts claims: NameIdentifier, Name, Role, auth_mode
LoginEndpoint (src/KArtSell.Host/Endpoints/Auth/LoginEndpoint.cs)
POST /api/auth/login- Issues JWT tokens- Request:
{ username, password, role? } - Response:
{ accessToken, expiresIn, tokenType: "Bearer" }
Frontend (Vue 3)
useAuthApi (frontend/src/features/auth/composables/useAuthApi.ts)
- Token lifecycle: login, logout, getToken
- Token persistence: localStorage
- Expiration tracking and validation
- Automatic cleanup on expiration
LoginPage (frontend/src/features/auth/pages/LoginPage.vue)
- Username/password form
- Token acquisition on successful login
- Redirect to home on auth success
Auth Interceptor
- Global fetch interceptor (setupAuthInterceptor)
- Automatically adds
Authorization: Bearer {token}to all requests - Initialized in
main.ts
Configuration
Development Mode
File: appsettings.json
{
"Authentication": {
"Mode": "DevelopmentHeader"
},
"Jwt": {
"Key": "KArtSell.Aegis.SecretKey.256Bits.v1.2026.Development.1234567890ABCDEF",
"Issuer": "KArtSell.Aegis",
"Audience": "KArtSell.Aegis",
"ExpirationMinutes": 60
}
}
Backend: Reads X-KArtSell-User and X-KArtSell-Role headers
Frontend: Skips login, uses static headers in API requests
Production Mode
File: appsettings.Release.json
{
"Authentication": {
"Mode": "JWT"
},
"Jwt": {
"Key": "${JWT_KEY}",
"Issuer": "KArtSell.Aegis",
"Audience": "KArtSell.Aegis",
"ExpirationMinutes": 60
}
}
Environment Variable: Set JWT_KEY during deployment
- Must be at least 256 bits (32 bytes) for HMAC SHA256
- Use cryptographically secure random string (e.g.,
openssl rand -hex 32)
Usage
Development
- Backend starts with DevelopmentHeaderAuthenticationHandler
- Frontend requests include static
X-KArtSell-User/X-KArtSell-Roleheaders - No login required for testing
Production
- User navigates to application
- Router redirects to
/login - User enters credentials
- Frontend calls
POST /api/auth/login - Backend validates credentials and returns JWT token
- Frontend stores token in localStorage
- All subsequent requests include
Authorization: Bearer {token} - Backend validates token in each request
Security Considerations
Token Storage
- Tokens stored in localStorage (accessible to XSS attacks)
- For sensitive applications, consider using httpOnly cookies
Token Expiration
- Default: 60 minutes
- Configurable via
Jwt:ExpirationMinutes - Frontend automatically detects expiration and logs out
Credential Validation
- Current implementation accepts any non-empty username/password
- TODO: Integrate with identity database for real validation
- Add rate limiting for login attempts
- Hash passwords with bcrypt/argon2
HTTPS Only (Production)
- Always use HTTPS in production
- Set
Secureflag on cookies if using cookie-based tokens - Implement token rotation/refresh mechanism
Token Refresh (Optional Enhancement)
For long-running applications, implement refresh token flow:
- Add
RefreshTokenEndpoint(POST /api/auth/refresh) - Issue longer-lived refresh tokens (1 week)
- Implement automatic token refresh in frontend
- Add refresh token rotation to prevent token reuse
Example implementation:
// useAuthApi.ts - future enhancement
async function refreshToken() {
const response = await fetch('/api/auth/refresh', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ refreshToken: getRefreshToken() })
})
// Store new token
}
Testing
Backend Unit Tests
dotnet test KArtSell.sln -c Release
Frontend Unit Tests
cd frontend
pnpm test
Local Testing (Development Mode)
# Terminal 1: SSH tunnel
ssh -L 5432:127.0.0.1:5432 kjh2064@178.104.200.7
# Terminal 2: Backend
cd src/KArtSell.Host
dotnet run -c Debug
# Terminal 3: Frontend
cd frontend
pnpm dev
Visit http://localhost:5174
Local Testing (Production Mode - JWT)
# Backend (Release mode)
dotnet run -c Release --project src/KArtSell.Host
# Frontend (will show login)
pnpm dev
# Login with any username/password
# Will receive JWT token and be redirected to home
Troubleshooting
401 Unauthorized (Release Mode)
- Missing
JWT_KEYenvironment variable - Invalid/expired JWT token
- Token not included in Authorization header
Token Not Persisting
- Check localStorage is enabled (not in private/incognito mode)
- Check browser console for storage quota errors
Clock Skew Issues
- Server/client time out of sync
- Default clock skew: 30 seconds (configurable)
- Ensure server time is synchronized (NTP)
API Contract
POST /api/auth/login
Request
{
"username": "john_doe",
"password": "secure_password",
"role": "Admin" // optional
}
Success Response (200)
{
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"expiresIn": 3600,
"tokenType": "Bearer"
}
Error Response (401)
{
"type": "about:blank",
"title": "Unauthorized",
"status": 401
}
Protected Endpoints
Header
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Invalid Token (401)
Authorization: Bearer invalid_token
Deployment Checklist
- Set
JWT_KEYenvironment variable (256+ bit secure random) - Configure
Jwt:IssuerandJwt:Audienceto match environment - Update
Jwt:ExpirationMinutesbased on security requirements - Enable HTTPS only (redirect HTTP to HTTPS)
- Set up database validation for credentials (not mock)
- Implement token refresh mechanism (optional but recommended)
- Configure rate limiting on
/api/auth/login - Enable audit logging for authentication events
- Test login flow end-to-end in staging environment
References
- JWT.io - JWT debugger and documentation
- Microsoft Identity Model Documentation
- OWASP Authentication Cheat Sheet