Replace pal-e-auth with Keycloak OIDC JWT validation #78
No reviewers
Labels
No labels
domain:backend
domain:devops
domain:frontend
status:approved
status:in-progress
status:needs-fix
status:qa
type:bug
type:devops
type:feature
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
forgejo_admin/basketball-api!78
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "77-replace-pal-e-auth-with-keycloak-oidc-jw"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Replace the custom
pal-e-auth-ldraneylibrary with direct Keycloak JWT validation via JWKS. Tokens are validated using RS256 public keys from the realm's JWKS endpoint -- no client secret needed in basketball-api.Changes
src/basketball_api/auth.py(NEW) --Userdataclass,get_current_userasync dependency (validates JWTs via JWKS with key rotation support),require_rolefactory for role-checking dependenciessrc/basketball_api/config.py-- Replacejwt_secret_key,google_client_id,google_client_secretwith singlekeycloak_realm_urlsetting (default: in-cluster Keycloak service)src/basketball_api/main.py-- Remove allpal_e_authimports (AuthConfig,auth_router),_build_auth_config(),app.state.auth_config, and auth router registrationsrc/basketball_api/routes/admin.py-- ImportUser,require_rolefrombasketball_api.authsrc/basketball_api/routes/roster.py-- Same import updatesrc/basketball_api/routes/tryouts.py-- Same import updatepyproject.toml-- Removepal-e-auth-ldraney>=0.1.0, addpython-jose[cryptography]>=3.3andhttpx>=0.27k8s/deployment.yaml-- Removepal-e-auth-secretsSecret references (jwt-secret-key, google-client-id, google-client-secret), addBASKETBALL_KEYCLOAK_REALM_URLenv vartests/conftest.py-- Remove Google OAuth env vars, remove_auth_configusage, setBASKETBALL_KEYCLOAK_REALM_URLfor teststests/test_admin.py-- ImportUserfrombasketball_api.authtests/test_tryouts.py-- ImportUserfrombasketball_api.auth, remove_auth_configimport and usageTest Plan
pytest tests/ -v)pal_e_auth/pal-e-authreferences in src/, tests/, k8s/, pyproject.tomlReview Checklist
Related
plan-pal-e-platform-- Phase 5 (Keycloak IdP integration)Self-Review
Reviewed all 11 changed files (195 additions, 59 deletions).
Findings
No blocking issues.
keycloak_realm_url), sensible in-cluster default_build_auth_config(),auth_router,app.state.auth_configremoved. Stripe lifespan preservedpal_e_auth->basketball_api.auth)pal-e-auth-ldraneyreplaced withpython-jose[cryptography]+httpx_auth_configreferences removed, mock pattern preservedNit (non-blocking):
httpx>=0.27now appears in both maindependenciesand[project.optional-dependencies] dev. Harmless (pip deduplicates), but could remove from dev deps in a follow-up.Verdict: Ready for human review.
PR #78 Review
BLOCKERS
README.md not updated -- stale auth references remain.
Two locations in
/README.mdstill reference the removedpal-e-authlibrary and its infrastructure:pal-e-auth-secretsK8s secret is listed under Prerequisites./auth/googleendpoint is listed in the endpoint table (this route was removed withauth_router).pal-e-authlibrary and/auth/google.These must be updated to reflect the Keycloak OIDC flow. The Prerequisites should list
BASKETBALL_KEYCLOAK_REALM_URL(or note it defaults to the in-cluster URL). The endpoint table should remove/auth/google. The Auth section should describe Keycloak realm token validation.NITS
verify_aud: Falseis intentional but undocumented. Thejwt.decode()call disables audience verification (line 133 ofauth.py). This is a reasonable choice since basketball-api accepts any token from thewestside-basketballrealm regardless of client, but a code comment explaining the rationale would help future reviewers understand this is deliberate and not an oversight.Module-level
_jwks_cacheis synchronous. The_fetch_jwks()function uses synchronoushttpx.get()inside anasync def get_current_user()dependency. This blocks the event loop during the initial JWKS fetch (and during rotation retries). With a single Keycloak instance on the same cluster the latency is negligible, but if you later move to an external IdP or experience network delays, consider switching tohttpx.AsyncClient. Not blocking for current deployment topology.Test mocks set
mock_user.role(singular) which is not a field on the newUserdataclass. Intests/test_admin.py(line 45) andtests/test_tryouts.py(line 108), the mock sets.role = "admin"but the newUserdataclass has.roles(list). This works becauseMagicMockallows arbitrary attributes and the route code never reads.roledirectly (the role check is insiderequire_role()which is overridden). Still, updating the mocks to set.roles = ["admin"]would be more accurate and prevent confusion.SOP COMPLIANCE
77-replace-pal-e-auth-with-keycloak-oidc-jwreferences issue #77)plan-pal-e-platform)Closes #77present in PR body.envfiles committedpal-e-authreferences -- see BLOCKER #1)SECURITY NOTES (all positive)
kidmatching with rotation retry -- handles Keycloak key rotation correctly.kid-- good balance of performance and rotation handling.HTTPBearer(auto_error=False)with explicitNonecheck -- clean 401 for missing tokens.VERDICT: NOT APPROVED
The README blocker must be fixed. The stale
pal-e-auth-secretsprerequisite and/auth/googleendpoint reference will mislead anyone deploying or onboarding to this codebase. Once the README is updated to reflect Keycloak auth, this is ready to merge.