Files
missions/_docs/02_document/components/05_identity/description.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

6.3 KiB

05 — Identity & Authorization

Spec source: ../../../suite/_docs/10_auth.md (suite-wide JWT model), ../../../suite/_docs/00_roles_permissions.md (the FL permission code).

Implementation status: implemented. Single policy FL is declared and consumed by every controller.

NOTE (forward-looking): post-rename + post-GPS-Denied-removal. Today's JwtExtensions.cs also declares a "GPS" policy reserved for the (now-removed-from-this-repo) GPS-Denied endpoints. After Jira AZ-EPIC child B7 lands, only "FL" remains.

Files: Auth/JwtExtensions.cs

1. High-Level Overview

Purpose: Validate JWT bearer tokens issued by the remote admin service and expose the named authorization policy (FL) used by controllers in the feature components. This service does not issue tokens -- it consumes them.

Architectural pattern: ASP.NET Core extension method (AddJwtAuth) configuring IServiceCollection at DI time.

Upstream dependencies: None internally.

Downstream consumers: 07_host (calls AddJwtAuth(jwtSecret) once); 01_vehicle_catalog, 02_mission_planning (controllers carry [Authorize(Policy = "FL")]).

2. Internal Interface

public static IServiceCollection AddJwtAuth(this IServiceCollection services, string jwtSecret);

Side effects: registers JwtBearerDefaults.AuthenticationScheme and one named authorization policy in DI:

Policy Requirement
"FL" JWT contains a permissions claim with value "FL"

3. Suite-wide JWT pattern

This is the canonical "every backend service" identity model in the Azaion suite. Per ../../../suite/_docs/00_top_level_architecture.md and ../../../suite/_docs/10_auth.md:

┌─────────────────────┐                 ┌──────────────────────┐
│ Operator UI         │  POST /login    │ admin (.NET, remote) │
│ (React, edge)       │ ──────────────► │ central user DB      │
│                     │ ◄────────────── │ mints HS256 JWT      │
│                     │   Bearer JWT    │   (claim: permissions)│
└──────────┬──────────┘                 └──────────────────────┘
           │ Bearer JWT (the SAME token reused for every service)
           │
           ├──────────────────► annotations  (.NET, edge)  -- ANN claim
           ├──────────────────► missions     (.NET, edge)  -- FL claim   ◄── this service
           ├──────────────────► satellite-provider (.NET, remote) -- ADM claim
           └──────────────────► (any future .NET service)

Every service (admin, annotations, missions, satellite-provider, ...) shares one HMAC secret (JWT_SECRET) and validates tokens locally with no network round-trip. The user logs in once at the UI; the resulting bearer token is reusable across every service. This service neither issues tokens nor talks to the central user DB -- it only validates.

The permissions claim drives per-service [Authorize(Policy = "...")] checks. The role -> permission matrix lives in ../../../suite/_docs/00_roles_permissions.md. All routes here require FL.

4. External API

None directly. Auth contract is observable only via 401 Unauthorized / 403 Forbidden on protected routes.

5. Data Access Patterns

None.

6. Implementation Details

Algorithm: HMAC-SHA256 signature validation via SymmetricSecurityKey(UTF-8(jwtSecret)). Matches the suite-wide shared-secret model.

Token validation flags:

  • ValidateIssuerSigningKey = true
  • ValidateLifetime = true (with ClockSkew = 1 minute -- tighter than .NET's 5-minute default)
  • ValidateIssuer = false, ValidateAudience = false -- iss / aud NOT enforced (consistent with shared-secret intra-suite model). Per the CMMC L2 scorecard (../../../suite/_docs/05_security/cmmc_l2_scorecard.md row 3), this is a known finding tracked at the suite level under AZ-487/AZ-494; the remediation will copy the satellite-provider pattern across annotations and missions.

Key Dependencies:

Library Version Purpose
Microsoft.AspNetCore.Authentication.JwtBearer 10.0.5 JWT bearer middleware + handler
Microsoft.IdentityModel.Tokens (transitive) SymmetricSecurityKey, TokenValidationParameters

7. Extensions and Helpers

None.

8. Caveats & Edge Cases

  1. Shared-secret trust model -- any service that knows JWT_SECRET can mint tokens this API will accept. Not safe for multi-tenant or third-party token issuance. Consistent with the rest of the suite; tightening this is suite-wide work, not a per-service decision.
  2. No claim type for "user id" is consumed -- only the permissions claim is checked. Services don't know who is calling them; per-user audit trails / business rules cannot be enforced at the service layer today. When a future feature needs an "applied by" attribution this gap will need to close.
  3. No offline-grace-window logic in this service -- ../../../suite/_docs/10_auth.md describes an offline JWT cache; that lives in the UI / admin consumption pattern, not here.
  4. Hardcoded fallback secret in Program.cs ("development-secret-key-min-32-chars!!") is dev-only. Production deployments MUST set JWT_SECRET.
  5. FL permission code carries the legacy "Flight" name even after the service rename to missions. The plan documents this explicitly: changing the permission code is a fleet-wide auth change (would break every issued token until new ones are minted) and is NOT in this Epic's scope. Tracked as a TODO in ../../../suite/_docs/00_roles_permissions.md.

9. Dependency Graph

Must be implemented after: nothing.

Can be implemented in parallel with: 04_persistence, 06_http_conventions.

Blocks: 07_host, 01_vehicle_catalog, 02_mission_planning.

10. Logging Strategy

ASP.NET Core's JwtBearer handler logs token validation outcomes at default levels (Information / Debug). Not customized.