Authentication Strategy β GIW
Status: POC Β· Date: 2026-09-21 Authority: TASK ORDER β APPLY AUTH ARCHITECTURE GUARDRAILS, 21/09/2026
DIRECT GRANT / PASSWORD GRANT = POC-ONLY IMPLEMENTATION
Not a production architecture. Not a production Galaxy ID flow. Not a production employee authentication recommendation.
RFC 9700 (OAuth 2.0 Security Best Current Practice) states the password grant MUST NOT be used, and OAuth 2.1 removes it. No standards exception is claimed here. Direct Grant is used only as a constrained POC workaround for captive-portal UX validation. Production authentication architecture remains TBC and should prefer modern browser-based OIDC/federation where operationally feasible.
1. Two modes
Both are configured in the realm. Only Mode A is wired to the portal.
MODE A β POC LOCAL
Wi-Fi Portal / BFF
β Direct Grant (POST /token, grant_type=password)
β Keycloak
β HR Verification API (employee path only)
Status: IMPLEMENTED / POC ONLY
| Clients | wifi-portal-api, wifi-portal-employee-api β both confidential |
| Customer | grant_type=password |
| Registration | client_credentials β Admin API β password |
| Employee | grant_type=password + employeeId + citizenId β custom employee-direct-grant flow β Keycloak calls HR |
| Browser sees | The portal only. One opaque sid cookie. |
| Why it exists | To validate the captive-portal journey end to end without a redirect. |
What it does not do: SSO, MFA, step-up, federation, credential isolation.
MODE B β PRODUCTION CANDIDATE
Wi-Fi Portal
β Authorization Code + PKCE
β Keycloak
β Enterprise IdP / Federation / MFA
β Keycloak
β Wi-Fi Portal
Status: PROPOSED / NOT IMPLEMENTED
| Clients | wifi-portal, wifi-portal-employee β public, PKCE S256 enforced |
| Flow | employee-browser β employee-verify-form β giw-employee-verify |
| Present in the realm? | Yes. Configured, importable, and exercised by earlier POC revisions. |
| Wired to the portal? | No. Deliberately unused. |
| Why retained | This is the path an Enterprise IdP federates into. ADR-003 recommends corporate IdP federation in place of CCCD; without this path that recommendation cannot be implemented without rebuilding the architecture. |
Do not delete: employee-browser flow Β· employee-verify-form sub-flow Β· EmployeeVerifyAuthenticator Β· giw-employee-verify provider Β· the galaxy login theme and employee-verify.ftl Β· clients wifi-portal and wifi-portal-employee Β· their giw-identity scope attachment and flow binding override.
bootstrap reconciles both sets on every start, so Mode B stays working rather than rotting.
2. Comparison
| Capability | Direct Grant (Mode A, POC) | Browser/OIDC (Mode B, production candidate) |
|---|---|---|
| Captive portal simplicity | High | TBC β must be validated against real CNA behaviour |
| SSO | No | Yes |
| MFA / step-up | Limited / No | Yes |
| Federation (Enterprise IdP, social) | No | Yes |
| Credential isolation | Lower β the portal transits the password | Better β the portal never sees it |
| CNA compatibility | Better in this POC, on a laptop browser | Must validate on real devices, real captive networks |
| Standards position | RFC 9700: MUST NOT | Recommended |
| Security / audit scope | Wider β portal is in credential scope | Narrower |
| Brand continuity | No visible hand-off | A visible hand-off, themeable |
| Production recommendation | No | Candidate |
Two rows deserve care, because the POC has not earned them:
- CNA compatibility. "Better in POC" means better on a desktop browser against a local stack. Nobody has tested either mode inside a real iOS or Android captive network assistant on an aircraft. Until that test exists, this is a hypothesis, not a finding.
- Captive portal simplicity. Mode B's cell is
TBCfor the same reason.
3. Migration path, Mode A β Mode B
Nothing below is built. It is recorded so the move is a change of route, not a rewrite.
| Step | What changes | What does not |
|---|---|---|
| 1 | Portal adds /login/oidc β redirect to wifi-portal client |
Entitlement, Session, HR, portal UI for every other screen |
| 2 | Portal adds /callback β code + PKCE verifier exchange |
The establish() path: token β entitlement β session β sid cookie |
| 3 | Employee journey points at wifi-portal-employee |
EmployeeVerification, the HR contract, CCCD handling |
| 4 | Keycloak adds the Enterprise IdP as an identity provider | Claim contract: user_type, employee_verified, employee_ref, company |
| 5 | employee-browser flow gains an IdP redirector ahead of giw-employee-verify |
Everything downstream of the token |
| 6 | Direct Grant disabled on both API clients; EmployeeDirectGrantAuthenticator removed |
β |
The reason this is cheap: the portal's establish() function takes a token and does everything after it. Whatever produced the token is interchangeable.
4. Security boundary
Who knows what. This is the property the BFF design buys, and it survives a move to Mode B.
Browser
| Knows | Holds | Never |
|---|---|---|
| The portal host, and nothing else | One opaque sid cookie β HttpOnly, SameSite=Strict, Max-Age=3600 |
An access token Β· a refresh token Β· an ID token |
| The Keycloak endpoint | ||
| The HR endpoint | ||
| The Entitlement endpoint | ||
| The Session endpoint |
The sid is a UUID with no meaning outside the portal's in-memory map. HttpOnly keeps it away from script; SameSite=Strict means no cross-site request carries it.
Exception, POC demo aid: DEBUG_EXPOSE_TOKEN=1 returns the raw access token on GET /api/v1/auth/session, so an API client can be seeded during a demo. It is off by default and must stay off outside a laptop.
Portal / BFF
| Does | Does not |
|---|---|
| Holds tokens server-side only, in a map with a 1 h TTL reaped every 5 minutes | Never persists a password β no store, no file, no database |
| Transits credentials in the POC Direct Grant flow | Never persists a CCCD |
| Validates shape before calling anything (email format, password length, field presence) | Never logs a credential β no log statement takes a password or a CCCD |
| Orchestrates: Galaxy ID β Entitlement β Session | Never decides authentication |
| Never decides entitlement | |
| Never touches a network device |
On "clear sensitive values immediately after the request" β what is actually guaranteed.
JavaScript strings are immutable. A password or CCCD read from a request body cannot be zeroed; there is no memset available. What the code does instead:
- The value is read into a local variable and passed directly to the outbound request.
- It is never assigned to a field, a session object, a cache or a closure that outlives the request.
- It goes out of scope when the handler returns, and is left to the garbage collector.
- No log statement anywhere in the portal takes it as an argument.
Points 2β4 are enforceable and enforced. Point 1 is not a wipe, and this document will not claim it is. A language with controlled memory would do better; that is a real limitation of a Node BFF handling credentials, and one more reason Mode A is POC-only.
The same applies inside Keycloak: EmployeeVerification holds the CCCD in a local variable, hands it to HrVerificationClient, and never writes it to a field, a user attribute, an auth-session note, an event detail or a log line. HrVerificationClient logs e.getClass().getSimpleName() on failure, never e.getMessage(), because some transport stacks echo the request body into the exception message.
Authority map
| System | Authority over | Never |
|---|---|---|
| Keycloak (Galaxy ID) | Authentication | Opens the network Β· decides entitlement |
| HR Verification API | Employment status β is this an active, eligible employee | Returns a profile Β· stores anything Β· is a system of record for identity |
| Entitlement Service | Authorization β what access this subject may have | Enforces Β· creates sessions |
| Session Service | Enforcement β access state (CREATED/GRANTED/REVOKED/EXPIRED) |
Decides. POST /sessions/{id}/grant returns 422 without an entitlementId |
| Wi-Fi Portal / BFF | Orchestration and presentation | Decides anything |
5. Decision record
| Question | Ref | Status |
|---|---|---|
| Is Direct Grant acceptable beyond the POC? | T-GRANT | No. POC only. |
| What is the production auth architecture? | β | TBC / NOT APPROVED |
| If MFA is required, what carries the step-up? | T-MFA | TBC. Mode A cannot. |
| Corporate IdP federation for employees? | ADR-003 | PROPOSED. Requires Mode B. |
| Is CCCD acceptable in production? | T-CCCD, ADR-003, D3 | TBC. Requires Security + Legal/DPO + HR approval. |
| Does Mode A survive a real CNA on a real aircraft? | β | Untested. |
| Does Mode B survive a real CNA? | β | Untested. |
6. Official status
| Item | Status |
|---|---|
| POC UX / API | ACCEPTABLE FOR LOCAL DEMO |
| POC Identity | PASS |
| Direct Grant | POC ONLY |
| OIDC Browser / Federation | PRODUCTION CANDIDATE / TBC |
| Production Auth Architecture | NOT APPROVED / TBC |
| CCCD | POC VERIFICATION INPUT ONLY. Production use requires Security + Legal/DPO + HR approval. |