Files
missions/_docs/02_document/diagrams/flows/flow_jwt_validation.md
T
Oleksandr Bezdieniezhnykh 7025f4d075 refactor: enhance JWT authentication and CORS configuration
Updated JWT authentication to use configuration values instead of hardcoded secrets, improving security and flexibility. Enhanced CORS policy to conditionally allow origins based on configuration settings, with logging for permissive defaults. Updated README to reflect project renaming and clarify service context.
2026-05-14 19:48:25 +03:00

5.2 KiB

Flow F5 — JWT bearer validation

Cross-cutting flow that runs on every [Authorize] request. Local validation only — this service never calls back to the issuing admin service.

Description

ASP.NET Core's JwtBearerHandler validates incoming Authorization: Bearer <jwt> headers against the shared HMAC secret (JWT_SECRET). On success, the request continues to the controller with a ClaimsPrincipal attached. On signature / lifetime failure → 401. On valid token but missing "FL" permission claim → 403. The iss / aud claims are intentionally NOT validated today (CMMC L2 finding tracked at suite level under AZ-487 / AZ-494 — see 05_identity § Implementation Details).

Preconditions

  • JWT_SECRET is resolved at startup (env or hardcoded dev fallback per architecture.md ADR-005).
  • AddJwtAuth(jwtSecret) was called during Program.cs startup (F6).

Sequence Diagram

sequenceDiagram
    autonumber
    participant Client as UI / Operator API client
    participant Pipeline as ASP.NET Pipeline
    participant Handler as JwtBearerHandler
    participant Policy as Auth policy "FL"
    participant Ctrl as Feature Controller
    participant Errs as 06_http_conventions

    Client->>Pipeline: HTTP request + Authorization: Bearer <jwt>
    Pipeline->>Errs: enter ErrorHandlingMiddleware
    Errs->>Handler: hand off (anonymous endpoints skip this)
    Handler->>Handler: parse token; verify HMAC-SHA256 signature using SymmetricSecurityKey(UTF-8(JWT_SECRET))
    alt Signature invalid OR token expired (ClockSkew = 1 minute)
        Handler-->>Client: 401 Unauthorized
    else Valid token
        Handler->>Handler: build ClaimsPrincipal; skip iss/aud validation
        Handler->>Policy: evaluate policy "FL" (requires permissions claim == "FL")
        alt Claim missing or != "FL"
            Policy-->>Client: 403 Forbidden
        else permissions=FL
            Policy-->>Ctrl: forward to controller action
            Ctrl-->>Client: business response
        end
    end

Flowchart

flowchart TD
    Start([Incoming request]) --> AnonEP{Endpoint requires auth?}
    AnonEP -->|no| Forward([Forward to controller])
    AnonEP -->|yes| Header{Authorization: Bearer present?}
    Header -->|no| Unauth1([401 Unauthorized])
    Header -->|yes| Sig{HMAC-SHA256 signature valid?}
    Sig -->|no| Unauth2([401 Unauthorized])
    Sig -->|yes| Life{Lifetime valid? ClockSkew=1min}
    Life -->|no| Unauth3([401 Unauthorized — expired])
    Life -->|yes| BuildPrincipal[Build ClaimsPrincipal — skip iss/aud]
    BuildPrincipal --> Policy{permissions claim == FL?}
    Policy -->|no| Forbid([403 Forbidden])
    Policy -->|yes| Forward

Data Flow

Step From To Data Format
1 Client Pipeline Authorization: Bearer <jwt> header HTTP header
2 JwtBearerHandler (in-process) parsed JWT (header, payload, signature) JSON Web Token
3 JwtBearerHandler (in-process) ClaimsPrincipal .NET principal object
4 Authorization policy evaluator Controller "policy satisfied" / 403 flag
5 JwtBearerHandler Client (only on failure) 401 / 403 HTTP status (no body)

Error Scenarios

Error Where Detection Recovery
Missing Authorization header on [Authorize] route JwtBearerHandler Header absent 401. Client must obtain a token from admin
Malformed JWT JwtBearerHandler Token parse failure 401
Signature mismatch (wrong / rotated JWT_SECRET) JwtBearerHandler HMAC verify fails 401. Suite-wide secret rotation is coordinated re-deploy of every backend that shares the secret + UI re-login
Expired token JwtBearerHandler ValidateLifetime = true (ClockSkew = 1 min) 401. Tighter than .NET's 5-min default — caller may experience earlier expiration than expected
permissions claim missing or wrong value Policy "FL" evaluator claim lookup 403
Token signed with the well-known dev fallback secret (silent acceptance) None Security risk in production. ADR-005 carry-forward; suite-tracked under CMMC L2 row 3
Token from a third-party that knows JWT_SECRET (silent acceptance) None Trust model is shared-secret intra-suite. Any third-party with the secret can mint accepted tokens. Out of this Epic's scope; suite-wide concern

Performance Expectations

Metric Target Notes
Validation latency sub-millisecond typical Pure HMAC + claim lookup; no I/O, no network call
Throughput bounded by request throughput No back-pressure; no token cache (no DB / network round-trip to cache)

Notes on iss / aud validation (suite-tracked)

ValidateIssuer = false, ValidateAudience = false — consistent with the shared-secret intra-suite model. The CMMC L2 scorecard (../../../suite/_docs/05_security/cmmc_l2_scorecard.md row 3) flags this as a finding. The remediation will copy the satellite-provider pattern across annotations and missions (suite work, AZ-487 / AZ-494). It is NOT in this Epic's scope and will not change as part of the rename refactor.