Auth Architecture: Westside Basketball

arch-auth-westside-basketball Architecture

architecture

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.roles in the JWT
  • Auth gating: src/basketball_api/auth.py — 269+ tests cover auth on all endpoints (PR #92)

Token Flow (SPA — Phase 15)