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.
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.csalso 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 = trueValidateLifetime = true(withClockSkew = 1 minute-- tighter than .NET's 5-minute default)ValidateIssuer = false,ValidateAudience = false--iss/audNOT enforced (consistent with shared-secret intra-suite model). Per the CMMC L2 scorecard (../../../suite/_docs/05_security/cmmc_l2_scorecard.mdrow 3), this is a known finding tracked at the suite level under AZ-487/AZ-494; the remediation will copy thesatellite-providerpattern acrossannotationsandmissions.
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
- Shared-secret trust model -- any service that knows
JWT_SECRETcan 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. - No claim type for "user id" is consumed -- only the
permissionsclaim 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. - No offline-grace-window logic in this service --
../../../suite/_docs/10_auth.mddescribes an offline JWT cache; that lives in the UI /adminconsumption pattern, not here. - Hardcoded fallback secret in
Program.cs("development-secret-key-min-32-chars!!") is dev-only. Production deployments MUST setJWT_SECRET. FLpermission code carries the legacy "Flight" name even after the service rename tomissions. 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.