Overview
The AuthService implements a secure, token-based authentication flow using JWT access tokens and refresh tokens. This dual-token approach balances security with user experience, keeping access tokens short-lived while allowing seamless session renewal.Complete Authentication Journey
Registration
New users create an account by providing username, email, and password.Endpoint: What happens internally (AuthService.cs:43-65):
POST /api/auth/register- Check if email already exists
- Hash password using PBKDF2 with 600k iterations
- Create user record with default settings
- Generate access token (JWT) and refresh token
- Store refresh token in database with IP tracking
- Return both tokens to client
The password is immediately hashed using PBKDF2-SHA512 before storage. The plaintext password never touches the database.
Login
Existing users authenticate with email and password.Endpoint: What happens internally (AuthService.cs:67-112):
POST /api/auth/login- Fetch user by email (case-insensitive)
- Check if account is active
- Check if account is locked out from failed attempts
- Verify password hash using constant-time comparison
- On success: Reset failed login counter, update last login timestamp
- On failure: Increment failed attempts, lock account after 5 failures
- Generate fresh access + refresh tokens
- Return tokens to client
Access Token Usage
The client includes the access token in every authenticated request.HTTP Header:Access Token Contents (TokenService.cs:33-42):
sub: User ID (GUID)email: User email addressunique_name: Usernamejti: Unique token IDiat: Issued at timestamp- Expiry: 15 minutes (configurable)
- Signature integrity (HMAC-SHA256)
- Issuer and audience claims
- Expiration time
- Not-before time
Token Refresh
When the access token expires (after 15 minutes), the client uses the refresh token to get a new one.Endpoint: What happens internally (AuthService.cs:114-152):
POST /api/auth/refresh- Look up refresh token in database
- Verify token is not revoked or expired
- Detect reuse attacks: If token was already used, revoke entire token family
- Rotate token: Create new refresh token, mark old one as replaced
- Generate new access token
- Clean up old tokens (>30 days)
- Return new token pair
Logout
Users explicitly revoke their refresh token when logging out.Endpoint: What happens internally (AuthService.cs:154-170):
POST /api/auth/revoke- Verify token exists and is active
- Mark token as revoked with timestamp
- Record IP address and reason
- Log revocation event
The access token cannot be revoked since it’s stateless. It remains valid until expiry (15 minutes). For immediate invalidation, implement a token blacklist or reduce access token lifetime.
Sequence Diagram
Token Lifecycle
Access Token
Lifetime: 15 minutes (default)Storage: Client-side only (memory or secure storage)Purpose: Authorize individual API requestsValidation: Stateless (signature-based)Revocation: Not possible (expires naturally)
Refresh Token
Lifetime: 7 days (default)Storage: Database + client-sidePurpose: Obtain new access tokensValidation: Stateful (database lookup)Revocation: Explicit (logout, security events)
Error Handling
The service returns specific error messages while maintaining security:Generic error messages for authentication failures
Generic error messages for authentication failures
To prevent username enumeration attacks, login failures always return the same generic message:This applies whether:
- Email doesn’t exist
- Password is wrong
- Account is inactive
Account lockout messages are specific
Account lockout messages are specific
When an account is locked, the user receives a specific message:This is acceptable because:
- The attacker already knows the account exists (5 successful lookups)
- It helps legitimate users understand why they can’t log in
- The lockout duration deters continued attacks
Token-related errors
Token-related errors
Best Practices for Clients
Store tokens securely
Web apps: Use
httpOnly cookies for refresh tokens, memory for access tokensMobile apps: Use platform secure storage (Keychain/Keystore)Never: Store tokens in localStorage on web (XSS risk)Implement automatic retry on 401
When a request fails with 401:
- Try to refresh the access token
- Retry the original request with new token
- If refresh fails, redirect to login
Configuration
Token lifetimes are configurable inappsettings.json:
Related Topics
Token Rotation
Learn how refresh token rotation prevents token reuse attacks
Security Features
Explore all security mechanisms in the service
API Reference
Complete endpoint documentation