---
name: auth-flow
description: Implement or extend login / refresh / logout with JWT + refresh-token rotation. Use for auth changes.
---

# Skill: Auth Flow

## When to use

Login, token refresh, logout, password reset, or MFA work.

## Architecture

- **.NET API owns issuance** (`dotnet/src/Infrastructure/Auth/JwtService.cs` + `RefreshTokenService.cs`).
- **Node hosts only verify** via `@loma-portal/em-auth` (`JwtVerifierService`, jose).
- Access token: 15 min. Refresh token: 30 days, rotated on every use, hashed (SHA-256) in DB.

## Steps

1. Frontend: `AuthService.login()` → `POST /api/auth/login` → store tokens → navigate.
2. `authInterceptor` attaches `Authorization: Bearer`. On 401, `errorInterceptor` logs out.
3. Refresh: call `/api/auth/refresh` before access expiry; rotate refresh token.

## Gotchas

- Argon2id for password hashing (`Argon2PasswordHasher`). The seed uses scrypt (no native deps); the API rehashes to argon2id on first login.
- Refresh tokens are stored **hashed** — never store/log the plaintext.
- Claim names from the .NET issuer: `sub`, `email`, `tenant_id`, `role` (per role), `perm` (per permission). `em-auth` maps these to `AuthClaims`.
- JWT secrets MUST be ≥ 32 chars (validated by `JwtOptions` DataAnnotations + zod env).
- CORS must expose `X-Correlation-Id` and allow credentials.

## Validation

Login → dashboard works with seeded admin; refresh rotates; 401 logs out; tokens never logged.
