Spike: Revert ROPC, restore Auth Code flow with Keycloak theme + ASWebAuthenticationSession #159

Closed
opened 2026-06-07 16:57:47 +00:00 by ldraney · 1 comment
Owner

Type

Spike

Lineage

Supersedes #157 (Direct Access Grants rewrite, PR #158 merged but NOT deployed -- tofu apply not run, prod still on OmniAuth). Corrects the correction: the original Auth Code flow (PR #134/#135) was architecturally correct, it just had UX bugs. ROPC is deprecated in OAuth 2.1 (RFC 9700) and should not be used for end-user auth.

Repo

ldraney/landscaping-assistant + ldraney/pal-e-services (terraform) + turbo-ios Xcode project

Question

What is the correct implementation path to restore standards-compliant auth (Authorization Code + PKCE) with good mobile UX? Specifically: (1) revert PR #158 or re-implement? (2) minimum viable Keycloak login theme, (3) ASWebAuthenticationSession wiring in turbo-ios, (4) how to handle the OmniAuth POST redirect bug from PR #151, (5) should terraform PR #106 (direct_access_grants_enabled) be reverted?

Time-box

4 hours

Context

PR #158 replaced OmniAuth (Authorization Code + PKCE) with ROPC Direct Access Grants because the Keycloak redirect UX was bad -- users saw Keycloak's default grey login page. But ROPC is the wrong fix:

  • ROPC is deprecated in OAuth 2.1 (RFC 9700), formally removed as a grant type
  • Rails app becomes credential intermediary -- expanded attack surface
  • Loses Keycloak features for free: brute force detection, required actions, MFA, social login federation
  • The existing keycloak-setup.md analysis was correct -- the spike agent (#132) already identified these issues

The real solution to the UX problem:

  1. Keycloak login theme -- brand the login page to match the app (sprout icon, colors, tagline)
  2. ASWebAuthenticationSession in turbo-ios -- shows themed Keycloak login in a native iOS sheet/popup, not a jarring browser redirect
  3. In mobile Safari, the redirect to themed Keycloak feels natural

Spike Questions

  1. Revert strategy: Revert PR #158 on main, or re-implement OmniAuth from scratch? Git history has all the pre-#158 code. What's cleaner?
  2. Keycloak theming: What's the minimum viable theme? Custom login.ftl template? How is it deployed (realm theme in Keycloak pod, or hosted externally)?
  3. ASWebAuthenticationSession: How does turbo-ios wire this up? Does turbo-ios have built-in auth session support, or do we need a custom WKNavigationDelegate? How does the callback URL work?
  4. POST redirect bug: PR #151 hotfixed the OmniAuth POST requirement (OmniAuth 2.x requires POST on request phase). Is this still the right fix, or does the revert restore the original bug?
  5. Terraform: PR #106 enabled direct_access_grants_enabled = true -- should we revert that too, or leave it enabled for potential admin/API use?
  6. Web + iOS parity: With Auth Code flow, the web experience redirects to Keycloak then back. On iOS, ASWebAuthenticationSession handles it natively. Confirm both flows produce identical session[:user] state.

Deliverables

  • Decision: revert #158 or re-implement
  • Keycloak theme approach (deploy mechanism, minimum viable design)
  • ASWebAuthenticationSession wiring for turbo-ios (code sketch or reference)
  • Updated auth flow mermaid diagram (Auth Code + themed Keycloak + ASWebAuthenticationSession)
  • List of follow-up implementation tickets

Constraints

  • Do NOT run tofu apply for PR #106 -- keep direct_access_grants disabled in prod
  • Prod is currently on pre-#158 code (OmniAuth still works, just has the POST bug hotfix from PR #151)
  • 5 test users in Keycloak landscaping realm, scaling to ~50

Checklist

  • Spike questions answered
  • Mermaid diagram produced
  • Follow-up tickets identified
  • ldraney/landscaping-assistant #157 -- Direct Access Grants (superseded by this spike)
  • ldraney/landscaping-assistant #132 -- original spike that correctly recommended Auth Code
  • ldraney/landscaping-assistant #158 -- ROPC PR (merged, not deployed)
  • ldraney/pal-e-services #106 -- terraform enabling direct_access_grants (merged, not applied)
  • docs/keycloak-setup.md -- existing analysis
### Type Spike ### Lineage Supersedes #157 (Direct Access Grants rewrite, PR #158 merged but NOT deployed -- tofu apply not run, prod still on OmniAuth). Corrects the correction: the original Auth Code flow (PR #134/#135) was architecturally correct, it just had UX bugs. ROPC is deprecated in OAuth 2.1 (RFC 9700) and should not be used for end-user auth. ### Repo `ldraney/landscaping-assistant` + `ldraney/pal-e-services` (terraform) + turbo-ios Xcode project ### Question What is the correct implementation path to restore standards-compliant auth (Authorization Code + PKCE) with good mobile UX? Specifically: (1) revert PR #158 or re-implement? (2) minimum viable Keycloak login theme, (3) ASWebAuthenticationSession wiring in turbo-ios, (4) how to handle the OmniAuth POST redirect bug from PR #151, (5) should terraform PR #106 (direct_access_grants_enabled) be reverted? ### Time-box 4 hours ### Context PR #158 replaced OmniAuth (Authorization Code + PKCE) with ROPC Direct Access Grants because the Keycloak redirect UX was bad -- users saw Keycloak's default grey login page. But ROPC is the wrong fix: - **ROPC is deprecated** in OAuth 2.1 (RFC 9700), formally removed as a grant type - **Rails app becomes credential intermediary** -- expanded attack surface - **Loses Keycloak features** for free: brute force detection, required actions, MFA, social login federation - **The existing `keycloak-setup.md` analysis was correct** -- the spike agent (#132) already identified these issues The real solution to the UX problem: 1. **Keycloak login theme** -- brand the login page to match the app (sprout icon, colors, tagline) 2. **ASWebAuthenticationSession** in turbo-ios -- shows themed Keycloak login in a native iOS sheet/popup, not a jarring browser redirect 3. In mobile Safari, the redirect to themed Keycloak feels natural ### Spike Questions 1. **Revert strategy**: Revert PR #158 on main, or re-implement OmniAuth from scratch? Git history has all the pre-#158 code. What's cleaner? 2. **Keycloak theming**: What's the minimum viable theme? Custom login.ftl template? How is it deployed (realm theme in Keycloak pod, or hosted externally)? 3. **ASWebAuthenticationSession**: How does turbo-ios wire this up? Does `turbo-ios` have built-in auth session support, or do we need a custom `WKNavigationDelegate`? How does the callback URL work? 4. **POST redirect bug**: PR #151 hotfixed the OmniAuth POST requirement (OmniAuth 2.x requires POST on request phase). Is this still the right fix, or does the revert restore the original bug? 5. **Terraform**: PR #106 enabled `direct_access_grants_enabled = true` -- should we revert that too, or leave it enabled for potential admin/API use? 6. **Web + iOS parity**: With Auth Code flow, the web experience redirects to Keycloak then back. On iOS, ASWebAuthenticationSession handles it natively. Confirm both flows produce identical `session[:user]` state. ### Deliverables - [ ] Decision: revert #158 or re-implement - [ ] Keycloak theme approach (deploy mechanism, minimum viable design) - [ ] ASWebAuthenticationSession wiring for turbo-ios (code sketch or reference) - [ ] Updated auth flow mermaid diagram (Auth Code + themed Keycloak + ASWebAuthenticationSession) - [ ] List of follow-up implementation tickets ### Constraints - Do NOT run `tofu apply` for PR #106 -- keep direct_access_grants disabled in prod - Prod is currently on pre-#158 code (OmniAuth still works, just has the POST bug hotfix from PR #151) - 5 test users in Keycloak landscaping realm, scaling to ~50 ### Checklist - [ ] Spike questions answered - [ ] Mermaid diagram produced - [ ] Follow-up tickets identified ### Related - `ldraney/landscaping-assistant #157` -- Direct Access Grants (superseded by this spike) - `ldraney/landscaping-assistant #132` -- original spike that correctly recommended Auth Code - `ldraney/landscaping-assistant #158` -- ROPC PR (merged, not deployed) - `ldraney/pal-e-services #106` -- terraform enabling direct_access_grants (merged, not applied) - `docs/keycloak-setup.md` -- existing analysis
Author
Owner

Scope Review: NEEDS_REFINEMENT

Review note: review-1382-2026-06-07

Spike scope is well-written with thorough context, clear questions, and concrete deliverables. Template completeness is strong. Three traceability gaps need addressing before moving to next_up:

  • [SCOPE] story:auth label is used by 15+ board items but no "auth" user story entry exists on project-landscaping-assistant user-stories section. Create the backing user story.
  • [SCOPE] arch:rails-app label has no backing architecture note in pal-e-docs. Create arch-rails-app.
  • [SCOPE] arch:ios label has no backing architecture note in pal-e-docs. Create arch-ios.
## Scope Review: NEEDS_REFINEMENT Review note: `review-1382-2026-06-07` Spike scope is well-written with thorough context, clear questions, and concrete deliverables. Template completeness is strong. Three traceability gaps need addressing before moving to next_up: - **[SCOPE]** `story:auth` label is used by 15+ board items but no "auth" user story entry exists on `project-landscaping-assistant` user-stories section. Create the backing user story. - **[SCOPE]** `arch:rails-app` label has no backing architecture note in pal-e-docs. Create `arch-rails-app`. - **[SCOPE]** `arch:ios` label has no backing architecture note in pal-e-docs. Create `arch-ios`.
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
ldraney/landscaping-assistant#159
No description provided.