diff --git a/.planning/todos/pending/oauth-password-bootstrap-change-password.md b/.planning/todos/pending/oauth-password-bootstrap-change-password.md new file mode 100644 index 00000000..bf0679d3 --- /dev/null +++ b/.planning/todos/pending/oauth-password-bootstrap-change-password.md @@ -0,0 +1,20 @@ +--- +created: 2026-10-21T00:00:00.000Z +title: Let password-less social accounts set a first password through change-password +area: sm-user-plugin +priority: medium +files: + - ../fonoteka.go/plugins/golem15/user/controllers/api_controller.go + - ../sm-sociallogin-plugin/testdata/PHP_METHOD_MAP.md +g15office: not created (no g15office tool in the executing session; see 19.5-04 checkpoint) +--- + +## Problem + +Social sign-in (golem15.sociallogin, Phase 19.5, D-10) creates password-less accounts: a random password nobody knows and `has_self_set_password` false. The PHP user plugin lets such an account set its first password through change-password without the current one, after confirming a short-lived, single-use code emailed to its own address, and disarms the relaxation after the first successful write (`OAuthPasswordBootstrapTest`: `test_oauth_account_sets_password_without_current_password`, `test_disarm_closes_the_no_current_password_window`, `test_confirmation_code_is_single_use_and_time_limited`). + +The Go user plugin has no such flow: `POST /_user/api/v1/change-password` answers an opaque 500 for an account without a self-set password, and only forgot/reset works. Phase 19.5 had no CONTEXT decision for it, so the three PHP methods are mapped not-applicable in `sm-sociallogin-plugin/testdata/PHP_METHOD_MAP.md`. An application cutover whose frontend relies on the PHP flow (428 `requires_confirmation`, then `password_bootstrap_code`) needs it. + +## Solution + +Port the PHP bootstrap to sm-user-plugin as an additive change: for `has_self_set_password = false`, change-password without `current_password` issues a confirmation code mailed to the account (answers 428 with `requires_confirmation`), verifies `password_bootstrap_code` (hashed, single use, time limited), writes the password and sets `has_self_set_password` true (disarm). A real-password account stays byte-identical (`TestChangePassword/real_password_account_still_requires_current_password`). The code needs columns or a cache entry (decide in the phase; a migration needs a decision note), a mail template, and the PHP tests above ported, which turns their three map rows into ported rows.