Skip to content

fix: post-merge fixes for Keycloak login flow#6

Merged
dosaki merged 2 commits into
mainfrom
fix/missing-requests-dep
May 10, 2026
Merged

fix: post-merge fixes for Keycloak login flow#6
dosaki merged 2 commits into
mainfrom
fix/missing-requests-dep

Conversation

@dosaki

@dosaki dosaki commented May 9, 2026

Copy link
Copy Markdown
Member

Two follow-ups to PR #4 needed before SSO works end-to-end. Both surfaced when actually exercising the login flow in prod.

What's broken

Hitting `https://librarian.services.keyholding.com\` returned Keycloak's `Invalid parameter: redirect_uri` error. The redirect_uri the app sent was `http://librarian.services.keyholding.com/callback\`, which is wrong on two axes vs the registered Keycloak client (`https://librarian.services.keyholding.com/auth/callback\`):

What the app sent What Keycloak expects
Scheme `http` `https`
Path `/callback` `/auth/callback`

There was also a missing runtime dependency surfaced separately during the deploy.

Fixes in this PR

1. `fix: declare requests as explicit dependency` (already on branch)
Authlib pulls `requests` transitively, but explicitly declaring it in `requirements.txt` makes the dependency contract obvious and protects against Authlib ever switching HTTP libraries.

2. `fix: route OIDC redirect through https and /auth/callback`

  • Mount the auth blueprint at `url_prefix="/auth"`. Without this, `@bp.route("/callback")` produced `/callback`, not `/auth/callback`. The blueprint name ("auth") doesn't auto-prefix paths — `url_prefix` is what does that. The original prompt to the keycloak-config session already specified `/auth/callback`, so the app side was the one out of step.
  • Add `ProxyFix(x_for=2, x_proto=2, x_host=1)` to the WSGI app. Topology is CloudFront(HTTPS) → ALB(HTTP) → ECS, so the inner WSGI scheme is `http` and `url_for(..., _external=True)` was generating `http://` URLs. With `x_proto=2` the app trusts the `X-Forwarded-Proto: https` value CloudFront stamps (ALB appends `http`, making the header `"https, http"` — ProxyFix takes `values[-x_proto]`).

Why x_proto=2 not 1

The header value at the app is `"https, http"`. ProxyFix's `_get_real_value` returns `values[-trusted]`:

  • `x_proto=1` → picks `http` (ALB's value) → app keeps generating http URLs (silent no-op, common bug)
  • `x_proto=2` → picks `https` (CloudFront's value) → correct

Safe because the ALB security group only accepts traffic from the CloudFront managed prefix list, so an attacker can't bypass CloudFront and inject a forged `X-Forwarded-Proto` directly. The 2-hop trust matches the real network topology.

Test plan

  • Hit `https://librarian.services.keyholding.com/\` — should bounce to Keycloak with `redirect_uri=https://.../auth/callback` (decoded: correct scheme and path).
  • Sign in successfully and land on the library index.
  • Confirm `/auth/login`, `/auth/callback`, `/auth/logout` all resolve (no 404s) and `/login` etc. now 404.
  • Logout returns to the Keycloak login screen and a fresh login prompts for credentials again.

Note for the keycloak-config side

No change needed there — the Keycloak client's `/auth/callback` registration was already correct. This PR moves the app to match what the IdP was already expecting.

🤖 Generated with Claude Code

dosaki and others added 2 commits May 9, 2026 23:27
Authlib's flask_client eagerly imports requests_client at module load,
so importing app.extensions fails with ModuleNotFoundError in the
hermetic deploy image (pip install --no-index from prebuilt wheels).
Authlib does not list requests as a hard install requirement, so it
never lands in /wheels.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Login was returning Keycloak's "Invalid parameter: redirect_uri" because
the URL the app generated via url_for(_external=True) was wrong on two
axes:

1. Wrong path. The auth blueprint was registered without a url_prefix,
   so its routes mounted at the root (/login, /callback, /logout). The
   Keycloak client has /auth/callback registered (matching the original
   prompt sent to the keycloak-config session). Mounting the blueprint
   under /auth aligns the app with Keycloak.

2. Wrong scheme. The stack is CloudFront(HTTPS) -> ALB(HTTP) -> ECS, so
   the WSGI scheme inside the container is http. CloudFront stamps
   X-Forwarded-Proto: https, ALB appends http, so the header reaching
   the app is "https, http". Adding ProxyFix(x_proto=2) trusts the
   CloudFront-set value, which makes url_for(_external=True) emit
   https URLs. x_for=2 mirrors this for client IPs in access logs.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings May 9, 2026 23:48

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Follow-up fixes to make the Keycloak (OIDC) login flow work end-to-end in production by ensuring generated redirect URLs match the Keycloak client configuration and by making a transitive runtime dependency explicit.

Changes:

  • Add requests as an explicit Python dependency.
  • Apply ProxyFix so externally-generated URLs use the correct forwarded scheme/host behind CloudFront → ALB.
  • Mount the auth blueprint under /auth so OIDC callback/login/logout routes align with Keycloak’s registered redirect URI paths.

Reviewed changes

Copilot reviewed 1 out of 2 changed files in this pull request and generated 1 comment.

File Description
requirements.txt Explicitly declares requests as a runtime dependency.
app/init.py Configures proxy header handling and prefixes auth routes under /auth to correct OIDC redirect URI generation.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread app/__init__.py
@dosaki dosaki merged commit c3fa681 into main May 10, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants