Skip to main content

User Authentication Flow

How users register, log in, refresh tokens, and access protected resources.

JWT Token Lifecycle​

Access token TTL defaults to 60 minutes (config: Jwt:ExpiryMinutes). Refresh token TTL defaults to 7 days (config: Jwt:RefreshExpiryDays). Refresh token is stored as an httpOnly cookie; Secure is enabled only on HTTPS, and SameSite is None for HTTPS/localhost (otherwise Lax).


Token Refresh Flow​


Registration Flow​


JWT Token Claims​

{
"sub": "00000000-0000-0000-0000-000000000001",
"http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name": "admin",
"http://schemas.microsoft.com/ws/2008/06/identity/claims/role": "Admin",
"jti": "unique-token-id",
"iss": "InventoryAlert.Api",
"aud": "InventoryAlert.UI",
"exp": 1713000000
}
ClaimPurpose
subUser ID (Guid) — used by all services to scope data access
nameUsername — displayed in UI
roleUser or Admin — controls endpoint authorization
expToken expiry — controlled by Jwt:ExpiryMinutes (default 60 minutes)
iss / audValidated on every request when configured (Jwt:Issuer, Jwt:Audience)

Authorization Levels​

EndpointRequired
POST /api/v1/auth/login, POST /api/v1/auth/register, POST /api/v1/auth/refresh[Public] — no token needed
All other endpoints[Authorize] — valid JWT required
POST /api/v1/stocks/sync, GET/POST /api/v1/events/*[Authorize(Roles = "Admin")]
GET /api/v1/market/status[AllowAnonymous] — explicitly public

Security Considerations​

  • Passwords are hashed with BCrypt.
  • Access token delivered in JSON body; refresh token in httpOnly cookie — not accessible to JavaScript.
  • Refresh tokens are rotated on each refresh call (revocation/deny-list can be added if strict single-use is required).
  • All sensitive config (Jwt:Key, Database:ConnectionString, Finnhub:ApiKey) lives in appsettings.*.json which is gitignored. Only appsettings.Example.json is committed.