fix: post-merge fixes for Keycloak login flow#6
Merged
Conversation
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>
There was a problem hiding this comment.
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
requestsas an explicit Python dependency. - Apply
ProxyFixso externally-generated URLs use the correct forwarded scheme/host behind CloudFront → ALB. - Mount the auth blueprint under
/authso 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.
4 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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\`):
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`
Why x_proto=2 not 1
The header value at the app is `"https, http"`. ProxyFix's `_get_real_value` returns `values[-trusted]`:
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
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