Auth Architecture: Westside Basketball
Auth Architecture
How authentication and authorization work across the Westside platform. Answers: who are you, what can you do, and how do we prove it?
Identity Provider
Keycloak at
keycloak.tail5b443a.ts.net, realm westside-basketball. Single source of truth for all user identities. Keycloak handles login UI, password management, session management, and token issuance.| Config | Value |
|---|---|
| Server | <code>https://keycloak.tail5b443a.ts.net</code> |
| Realm | <code>westside-basketball</code> |
| Protocol | OpenID Connect (OIDC) |
| Admin emails | <code>draneylucas@gmail.com</code>, <code>mldraney3@gmail.com</code> |
Roles
Three realm-level roles. Every authenticated user has exactly one.
| Role | Who | Can do |
|---|---|---|
| <code>admin</code> | Lucas, Marcus | Everything — draft board, user management, payment management, schedule management, all dashboards |
| <code>coach</code> | 5 coaches | View team roster, player profiles (read-only), view team schedule and events, upload playbooks. No payment info. |
| <code>player</code> | Parents (50+ accounts) | View own child's profile, team, schedule, billing. Edit own player's profile fields. |
Two Auth Patterns
The platform supports two client integration patterns against the same Keycloak server. The SSR pattern is being replaced by SPA in Phase 15.
| Concern | SSR (current — westside-app) | SPA (Phase 15 rebuild) |
|---|---|---|
| Frontend adapter | adapter-node (Node.js server) | adapter-static (static files) |
| Auth library | Auth.js (@auth/sveltekit) | keycloak-js (official Keycloak adapter) |
| Keycloak client type | Confidential (client ID + secret) | Public (PKCE, no secret) |
| Token location | Server-side session (cookie reference) | In-memory only (never localStorage) |
| Token refresh | Auth.js handles server-side | <code>keycloak.updateToken(30)</code> before API calls |
| API calls | Server-side fetch (Node.js → API) | Client-side fetch with <code>Bearer</code> token header |
| Capacitor/iOS | Not possible (requires Node.js) | Ready — static files wrap into WebView |
Keycloak Clients
| Client ID | Type | App | Status |
|---|---|---|---|
| <code>westside-app</code> | Confidential | westside-app (SSR) | Active — retired with Phase 15 |
| <code>westside-spa</code> (TBD) | Public (PKCE) | westside-app (SPA rebuild) | Created in Phase 15 |
SPA client config (Phase 15):
- Client authentication: OFF
- Valid Redirect URIs:
https://westsidekingsandqueens.tail5b443a.ts.net/*,capacitor://localhost/*,http://localhost/* - Web Origins:
https://westsidekingsandqueens.tail5b443a.ts.net,capacitor://localhost,http://localhost
Account Creation
Two paths to Keycloak account creation:
| Path | Trigger | How |
|---|---|---|
| <strong>Auto (PR #94)</strong> | Parent completes paid registration | Registration POST handler → <code>services/keycloak.py</code> → Keycloak Admin API. Creates user with email as username, generated password, <code>player</code> role, firstName/lastName. Fail-safe: errors logged, never blocks registration. |
| <strong>Batch script</strong> | Admin runs manually for backfills / cash payments | <code>scripts/create_keycloak_accounts.py</code> → same shared <code>services/keycloak.py</code> module. CSV output with credentials. |
API Auth (basketball-api)
All endpoints (except
/register and /health) require a valid Bearer token. The API validates tokens against Keycloak's JWKS endpoint. Role extracted from token claims for authorization.- Token validation: Keycloak JWKS at
keycloak.tail5b443a.ts.net/realms/westside-basketball/protocol/openid-connect/certs - Role claim:
realm_access.rolesin the JWT - Auth gating:
src/basketball_api/auth.py— 269+ tests cover auth on all endpoints (PR #92)
Token Flow (SPA — Phase 15)
Related
- Project: Westside Basketball
- Domain Model
- Data Flow
- Deployment
- Phase 15: Production Port — SPA rebuild spec
- Plan: mcd-tracker — validated the keycloak-js + Capacitor pattern