Enterprise login: Keycloak SMTP + self-service password reset #129

Closed
opened 2026-03-21 14:01:21 +00:00 by forgejo_admin · 0 comments

Type

Feature

Lineage

plan-wkq → Phase 11 → discovered scope (parents can't login)

Repo

forgejo_admin/basketball-api

User Story

As a parent
I want to reset my own password via "Forgot Password"
So that I can log in without contacting an admin

Context

Parents report they can't log in (2026-03-21). Keycloak logs confirm invalid_user_credentials for multiple users and email_send_failed: No sender address configured in realm settings. Accounts were auto-created with generated passwords emailed in plaintext — parents who lost them are stuck. Self-service password reset requires SMTP configured in Keycloak realm.

Enterprise fix: stop generating passwords entirely. Use Keycloak's execute-actions-email API to let users set their own password on first login. Keycloak SMTP uses Gmail app password for westsidebasketball@gmail.com via smtp.gmail.com:587.

File Targets

  • src/basketball_api/services/keycloak.py — change create_keycloak_user() to not set password, add trigger_set_password_email() using execute-actions-email API
  • src/basketball_api/services/email.py — remove plaintext password from announcement email templates
  • src/basketball_api/routes/admin.py — update admin_send_tryout_announcement to stop generating/resetting passwords
  • scripts/backfill_password_reset.py — one-time script to trigger password setup for all existing parents

Files the agent should NOT touch:

  • src/basketball_api/auth.py — JWT validation, unrelated
  • src/basketball_api/routes/register.py — registration flow, separate concern

Acceptance Criteria

  • Keycloak SMTP configured with Gmail app password (smtp.gmail.com:587)
  • "Forgot Password" on login page sends reset email to parent
  • New accounts created without password; execute-actions-email triggers "Set your password" flow
  • Announcement emails no longer contain plaintext passwords
  • Backfill script triggers password setup email for all existing parents
  • Token refresh failure in westside-app shows user feedback (not silent)

Test Expectations

  • Unit test: create_keycloak_user no longer sets password credential
  • Unit test: trigger_set_password_email calls execute-actions-email endpoint
  • Integration test: announcement email has no password field
  • Run command: pytest tests/ -k "keycloak or announcement"

Constraints

  • Gmail OAuth tokens already working for transactional email — SMTP is only needed for Keycloak's built-in flows
  • Gmail app password required (Lucas generates in Google Account UI)
  • Must not break existing registration flow — account creation still happens on registration
  • Follow existing patterns in services/keycloak.py

Checklist

  • PR opened
  • Tests pass
  • No unrelated changes
  • Westside Basketball — project
  • pal-e-platform #122 — Remove SendGrid dependency
### Type Feature ### Lineage `plan-wkq` → Phase 11 → discovered scope (parents can't login) ### Repo `forgejo_admin/basketball-api` ### User Story As a parent I want to reset my own password via "Forgot Password" So that I can log in without contacting an admin ### Context Parents report they can't log in (2026-03-21). Keycloak logs confirm `invalid_user_credentials` for multiple users and `email_send_failed: No sender address configured in realm settings`. Accounts were auto-created with generated passwords emailed in plaintext — parents who lost them are stuck. Self-service password reset requires SMTP configured in Keycloak realm. Enterprise fix: stop generating passwords entirely. Use Keycloak's execute-actions-email API to let users set their own password on first login. Keycloak SMTP uses Gmail app password for `westsidebasketball@gmail.com` via `smtp.gmail.com:587`. ### File Targets - `src/basketball_api/services/keycloak.py` — change `create_keycloak_user()` to not set password, add `trigger_set_password_email()` using execute-actions-email API - `src/basketball_api/services/email.py` — remove plaintext password from announcement email templates - `src/basketball_api/routes/admin.py` — update `admin_send_tryout_announcement` to stop generating/resetting passwords - `scripts/backfill_password_reset.py` — one-time script to trigger password setup for all existing parents Files the agent should NOT touch: - `src/basketball_api/auth.py` — JWT validation, unrelated - `src/basketball_api/routes/register.py` — registration flow, separate concern ### Acceptance Criteria - [ ] Keycloak SMTP configured with Gmail app password (`smtp.gmail.com:587`) - [ ] "Forgot Password" on login page sends reset email to parent - [ ] New accounts created without password; execute-actions-email triggers "Set your password" flow - [ ] Announcement emails no longer contain plaintext passwords - [ ] Backfill script triggers password setup email for all existing parents - [ ] Token refresh failure in westside-app shows user feedback (not silent) ### Test Expectations - [ ] Unit test: `create_keycloak_user` no longer sets password credential - [ ] Unit test: `trigger_set_password_email` calls execute-actions-email endpoint - [ ] Integration test: announcement email has no password field - Run command: `pytest tests/ -k "keycloak or announcement"` ### Constraints - Gmail OAuth tokens already working for transactional email — SMTP is only needed for Keycloak's built-in flows - Gmail app password required (Lucas generates in Google Account UI) - Must not break existing registration flow — account creation still happens on registration - Follow existing patterns in `services/keycloak.py` ### Checklist - [ ] PR opened - [ ] Tests pass - [ ] No unrelated changes ### Related - `Westside Basketball` — project - pal-e-platform #122 — Remove SendGrid dependency
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
forgejo_admin/basketball-api#129
No description provided.