Add dual-auth dependency for jersey and checkout routes #255

Closed
opened 2026-03-29 23:11:19 +00:00 by forgejo_admin · 0 comments
Contributor

Type

Feature

Lineage

Child of forgejo_admin/westside-landing#196 (spike: player self-service jersey ordering).
Story: WS-S18 — "As a parent, I want to receive a branded email with jersey ordering link so that I can order without bringing cash"

Repo

forgejo_admin/basketball-api

User Story

As a logged-in parent
I want to access jersey ordering and checkout using my Keycloak session
So that I can order directly from my profile without needing the email token link

Context

The jersey and checkout routes currently authenticate exclusively via Parent.registration_token passed as a ?token= query param. This works for email-link flows but blocks self-service ordering from the SPA where parents are already authenticated via Keycloak JWT.

The account route (account.py line 57) already demonstrates the pattern: Parent.email.ilike(user.email) resolves a Parent from a Keycloak session. This ticket creates a reusable dependency that accepts EITHER auth method.

register.py and tryouts.py also use registration_token but in completely separate code paths with no shared helpers — zero blast radius.

File Targets

Files the agent should modify or create:

  • src/basketball_api/auth.py — add get_parent_dual_auth(token: str | None, credentials, db) dependency that tries token first, then Keycloak JWT + email lookup
  • src/basketball_api/routes/jersey.py — lines 109-122 (jersey_player_info) and lines 227-235 (jersey_checkout): replace inline Parent.registration_token lookup with new dependency
  • src/basketball_api/routes/checkout.py — lines 115-122 (create_checkout_session): replace inline Parent.registration_token lookup with new dependency
  • tests/ — add tests for both auth paths

Files the agent should NOT touch:

  • src/basketball_api/routes/register.py — uses registration_token in separate code paths
  • src/basketball_api/routes/tryouts.py — uses registration_token in separate code paths

Acceptance Criteria

  • When I call /jersey/player-info?token=abc123, then the existing token auth works unchanged
  • When I call /jersey/player-info with a Keycloak Bearer token (no ?token=), then it resolves the parent via email match
  • When I call /jersey/checkout or /checkout/create-session with either auth method, then both work
  • When I call with neither token nor Bearer, then I get 401
  • When register.py and tryouts.py are diffed, then zero changes

Test Expectations

  • Unit test: get_parent_dual_auth returns Parent when given valid registration token
  • Unit test: get_parent_dual_auth returns Parent when given valid Keycloak JWT with matching email
  • Unit test: get_parent_dual_auth raises 401 when neither auth method provided
  • Unit test: get_parent_dual_auth raises 404 when Keycloak email matches no parent
  • Integration test: /jersey/player-info works with both auth methods
  • Run command: pytest tests/ -k "dual_auth or jersey or checkout"

Constraints

  • The token query param must remain optional (not removed) for backwards compatibility
  • Follow the existing dependency injection pattern from auth.py (get_current_user)
  • The dependency must eagerly load Parent.players relationship (use joinedload)

Checklist

  • PR opened
  • Tests pass
  • No unrelated changes
  • westside-basketball — project this affects
  • forgejo_admin/westside-landing#196 — parent spike issue
### Type Feature ### Lineage Child of `forgejo_admin/westside-landing#196` (spike: player self-service jersey ordering). Story: WS-S18 — "As a parent, I want to receive a branded email with jersey ordering link so that I can order without bringing cash" ### Repo `forgejo_admin/basketball-api` ### User Story As a logged-in parent I want to access jersey ordering and checkout using my Keycloak session So that I can order directly from my profile without needing the email token link ### Context The jersey and checkout routes currently authenticate exclusively via `Parent.registration_token` passed as a `?token=` query param. This works for email-link flows but blocks self-service ordering from the SPA where parents are already authenticated via Keycloak JWT. The account route (`account.py` line 57) already demonstrates the pattern: `Parent.email.ilike(user.email)` resolves a Parent from a Keycloak session. This ticket creates a reusable dependency that accepts EITHER auth method. `register.py` and `tryouts.py` also use `registration_token` but in completely separate code paths with no shared helpers — zero blast radius. ### File Targets Files the agent should modify or create: - `src/basketball_api/auth.py` — add `get_parent_dual_auth(token: str | None, credentials, db)` dependency that tries token first, then Keycloak JWT + email lookup - `src/basketball_api/routes/jersey.py` — lines 109-122 (`jersey_player_info`) and lines 227-235 (`jersey_checkout`): replace inline `Parent.registration_token` lookup with new dependency - `src/basketball_api/routes/checkout.py` — lines 115-122 (`create_checkout_session`): replace inline `Parent.registration_token` lookup with new dependency - `tests/` — add tests for both auth paths Files the agent should NOT touch: - `src/basketball_api/routes/register.py` — uses `registration_token` in separate code paths - `src/basketball_api/routes/tryouts.py` — uses `registration_token` in separate code paths ### Acceptance Criteria - [ ] When I call `/jersey/player-info?token=abc123`, then the existing token auth works unchanged - [ ] When I call `/jersey/player-info` with a Keycloak Bearer token (no `?token=`), then it resolves the parent via email match - [ ] When I call `/jersey/checkout` or `/checkout/create-session` with either auth method, then both work - [ ] When I call with neither token nor Bearer, then I get 401 - [ ] When register.py and tryouts.py are diffed, then zero changes ### Test Expectations - [ ] Unit test: `get_parent_dual_auth` returns Parent when given valid registration token - [ ] Unit test: `get_parent_dual_auth` returns Parent when given valid Keycloak JWT with matching email - [ ] Unit test: `get_parent_dual_auth` raises 401 when neither auth method provided - [ ] Unit test: `get_parent_dual_auth` raises 404 when Keycloak email matches no parent - [ ] Integration test: `/jersey/player-info` works with both auth methods - Run command: `pytest tests/ -k "dual_auth or jersey or checkout"` ### Constraints - The `token` query param must remain optional (not removed) for backwards compatibility - Follow the existing dependency injection pattern from `auth.py` (`get_current_user`) - The dependency must eagerly load `Parent.players` relationship (use `joinedload`) ### Checklist - [ ] PR opened - [ ] Tests pass - [ ] No unrelated changes ### Related - `westside-basketball` — project this affects - `forgejo_admin/westside-landing#196` — parent spike issue
Sign in to join this conversation.
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/basketball-api#255
No description provided.