Review: Bug: Keycloak issuer mismatch blocks login via auth.palinks.app (re-review)

review-1572-2026-06-23-r2 Review

review approved

Verdict: APPROVED

Re-review of board item #1572 after refinement. All 4 [BODY] recommendations from review-1572-2026-06-23 have been addressed. 1 [SCOPE] item (arch-rails-app note) carried forward but does not block this ticket.

Template Completeness

  • [x] Type -- Bug
  • [x] Lineage -- Standalone, discovered during session. Now includes cross-reference to pal-e-platform#455 with explicit independence statement.
  • [x] Repo -- ldraney/landscaping-assistant
  • [x] What Broke -- Issuer mismatch error with log evidence and code reference
  • [x] Root Cause Fix -- NEW. Clearly specifies Rails-side fix with two options (discovery fetch vs KEYCLOAK_ISSUER env var). Explicitly scopes out Keycloak-side KC_HOSTNAME changes.
  • [x] Repro Steps -- Clear 5-step repro
  • [x] Expected Behavior -- present
  • [x] Environment -- Cluster, pod env vars, Keycloak discovery issuer all documented
  • [x] Acceptance Criteria -- 6 criteria, all testable (expanded from 4)
  • [x] Related -- file paths, docs, and cross-repo reference to pal-e-platform#455
All required sections for a Bug template are present and well-filled.

Traceability

  • [x] story:custom-domain label -- verified: "custom-domain" entry exists in project-landscaping-assistant user-stories section. Summary: "Access app via landscaping-assistant.app instead of Tailscale hostname."
  • [x] story note verified -- found in project-landscaping-assistant user-stories table
  • [ ] arch:rails-app label -- no matching arch note found in pal-e-docs (search for "arch-rails-app" returned empty). [SCOPE] Create architecture note arch-rails-app for the Rails application component. Carried forward from first review -- does not block this ticket since arch:rails-app is a shared label used on 30+ board items; the fix is fully scoped without it.
  • [x] Forgejo issue -- ldraney/landscaping-assistant#259, open

File Targets

  • [x] config/initializers/omniauth.rb (line 20) -- verified: line 20 contains issuer: keycloak_configured ? "#{ENV["KEYCLOAK_URL"]}/realms/#{ENV["KEYCLOAK_REALM"]}" : "https://keycloak.test/realms/test". This is exactly where the mismatch originates.
  • [x] app/controllers/sessions_controller.rb (line 48) -- verified: line 48 builds logout_url from ENV["KEYCLOAK_URL"]. Issue correctly notes this should continue using KEYCLOAK_URL.
  • [x] app/services/keycloak_admin_service.rb -- verified: line 7 fetches ENV.fetch("KEYCLOAK_URL") as base_url. Admin API calls should not be affected by issuer-only fix.
  • [x] docs/auth-strategy.md -- verified: exists, documents Auth Code + PKCE architecture
  • [x] docs/keycloak-setup.md -- verified: exists, documents realm/client config

Repo Placement

OK. The Root Cause Fix section now explicitly states "Rails-side fix (this repo only)" and scopes out Keycloak hostname reconfiguration. The relationship to pal-e-platform#455 is documented in Lineage as independent.

Dependencies

  • Board item #1504 (pal-e-platform#455, backlog, type:bug, story:custom-domain) -- documented in Lineage as the Keycloak server-side companion. Issue explicitly states this ticket does NOT depend on #455.
  • Board item #1478 (landscaping-assistant#246, done) -- previous OmniAuth redirect_uri fix. Provides context for the custom-domain story arc.
  • No blocking dependencies. Independent fix.

Acceptance Criteria

6 criteria, all testable:
  • AC1 (login via landscaping-assistant.app): verifiable by manual test
  • AC2 (login via Tailscale URL): regression check, verifiable
  • AC3 (logout works): NEW -- addresses previous review finding. Verifiable by checking end-session redirect.
  • AC4 (KeycloakAdminService): NEW -- addresses previous review finding. Verifiable by testing profile edit.
  • AC5 (endpoint specs pass): verifiable via bundle exec rspec
  • AC6 (KEYCLOAK_URL stays as auth.palinks.app): verifiable by inspecting k8s secret
All criteria are clear and agent-verifiable.

Blast Radius

  • KEYCLOAK_URL is referenced in 4 production files: omniauth.rb, application_controller.rb (presence check only), sessions_controller.rb (logout URL), keycloak_admin_service.rb (admin API base URL). The fix only changes issuer derivation in omniauth.rb -- other files continue using KEYCLOAK_URL as-is.
  • 8 spec files mock KEYCLOAK_URL (12+ references). Specs should not need changes unless a new env var is introduced, in which case only omniauth.rb-related specs need updating.
  • Root Cause Fix section correctly identifies that KEYCLOAK_URL must remain usable for logout and admin API -- only issuer validation changes.

Decomposition Assessment

2-3 file targets in 1 repo, 6 acceptance criteria. Estimated agent work under 5 minutes for the Rails-side issuer override. No decomposition needed.

Refinement Verification (re-review)

Previous review: review-1572-2026-06-23 (NEEDS_REFINEMENT, 5 items)
  • [x] [BODY] Root Cause Fix section added -- specifies Rails-side fix with two options, scopes out Keycloak-side changes
  • [x] [BODY] Dependencies documented in Lineage -- pal-e-platform#455 referenced, independence stated
  • [x] [BODY] AC for logout added -- AC3 covers end-session redirect
  • [x] [BODY] AC for KeycloakAdminService added -- AC4 covers profile edit
  • [ ] [SCOPE] arch-rails-app note still missing -- carried forward, does not block ticket

Recommendations

  • [SCOPE] Create architecture note arch-rails-app for the Rails application component (carried forward from first review -- low priority, affects 30+ board items, not specific to this ticket).
No other action needed. Ticket is APPROVED for implementation.