user-engine/workplans/USER-WP-0022-public-registration-and-jit-application-profiles.md
tegwick 0669fa7a85
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Add public registration browser journey
2026-08-10 15:59:50 +02:00

173 lines
7.4 KiB
Markdown

---
id: USER-WP-0022
type: workplan
title: "Public registration and JIT application profiles"
domain: communication
repo: user-engine
status: active
owner: codex
topic_slug: netkingdom
created: "2026-08-09"
updated: "2026-08-10"
depends_on:
- USER-WP-0021
- NK-WP-0025
state_hub_workstream_id: "97145e5b-5f8f-4cb1-9135-2593f5baac8f"
---
# USER-WP-0022 - public registration and application JIT
Turn the existing provider-neutral registration domain into a safe public
product flow and provide idempotent first-login application-profile creation.
user-engine remains the user/profile source of truth but delegates login
identity creation to NetKingdom.
## T01 - Publish the public registration journey
```task
id: USER-WP-0022-T01
status: progress
priority: high
state_hub_task_id: "43dd49b7-6dbc-4117-a401-6d9f6e59aa26"
```
Add accessible browser/API entry points for start, email verification,
provider password-setup handoff, resume, expiry, cancel, and completion.
Enable public registration only through explicit runtime configuration and
signed allow-listed return context. Apply rate limits, anti-enumeration
responses, CSRF, idempotency, and safe diagnostics.
Done when the flow can be enabled per deployment without exposing whether an
email or username already exists.
Implementation contract established in NetKingdom at
`docs/public-registration-orchestration-contract.md`. The current
authenticated registration API will not be moved ahead of authentication;
the public adapter will use opaque intent handles and construct a narrowly
scoped applicant actor only from consumed verification evidence. First code
slice added `RegistrationVerificationPort`, bound request/receipt/evidence
types, and a fail-closed HTTP adapter with purpose checking and normalized
mailbox evidence. Adapter tests and the full 123-test suite pass.
Second code slice adds explicit allow-listed anonymous endpoints:
`POST /api/v1/public/registrations` returns only a generic 202 status, while
`POST /api/v1/public/registrations/verify` consumes purpose-bound evidence and
attaches the verified email factor. Persisted registration sessions bind the
random applicant subject, canonical username, client, and tenant. Evidence
mismatch fails closed, browser-supplied return URLs are ignored, and this
transition creates neither a user nor an LLDAP identity. Full suite now passes
125 tests with 3 environment-dependent skips.
Third code slice completes the verified happy path: create the local user,
call identity-provisioner with deterministic registration idempotency and only
the baseline `user` role, link the returned subject under the configured
KeyCape issuer, and redirect only to an allow-listed HTTPS provider password
setup origin. Full suite now passes 126 tests with 3 skips. Automated recovery
after local completion/provider failure remains open before production enablement.
2026-08-10 browser increment: `/register` now provides the accessible public
account form and the home page links to it only when registration is configured.
Anonymous mutations use a short-lived Secure/HttpOnly/SameSite double-submit
CSRF cookie. Verification links land on an explicit one-time confirmation page,
successful provisioning presents the allow-listed provider password handoff,
and provider outages render a retry form backed by the separate resume handle.
Responses remain non-enumerating. The full suite passes 128 tests with three
environment-dependent skips. Cancellation, ingress rate limiting, and the
credential-gated production enablement remain.
## T02 - Orchestrate provider identity creation
```task
id: USER-WP-0022-T02
status: done
priority: high
state_hub_task_id: "74239ce4-5c1e-46cf-8abf-3cbec3f3f989"
```
Use the existing provisioning port to create or resume an ordinary NetKingdom
identity only after required verification. Persist lifecycle intent and outbox
state atomically; compensate or surface recoverable partial state on provider
failure. Never accept or retain an LLDAP password, admin credential, MFA seed,
or verification secret in the user-engine domain.
Done when a registration can resume safely across timeout/retry and produces
one external identity link.
The existing provisioning port remains the privileged boundary. Public
registration adds canonical username and uses the registration ID as its
stable idempotency key; it accepts only the baseline ordinary-user group and
the provider-owned password-setup handoff. `ProvisioningRequest` now carries
an optional canonical `preferred_username` through the HTTP adapter without
changing existing callers.
Retry-safe recovery is now implemented for the local-completion/provider-
failure window. A single-use mailbox handle is never replayed; instead,
user-engine returns a separate random resume handle, stores only its SHA-256
digest, retries with the same registration idempotency key and local user,
and invalidates the handle after provider linking. Replay is denied. The full
suite passes 127 tests with 3 environment-dependent skips.
2026-08-10 completion: identity-provisioner now validates and honors the
canonical preferred username instead of silently deriving it from the mailbox.
The corrected image is live at immutable digest
`sha256:4a6ec93d74eed6e17065a7e5d4c3d8d0ed14078bdfda0112738438528c6b2680`.
Together with the deterministic retry path, this completes the provider
orchestration boundary without exposing provider credentials or passwords.
## T03 - Create application profiles on first login
```task
id: USER-WP-0022-T03
status: cancel
priority: high
state_hub_task_id: "01fa1a22-0f4a-4a36-a9b3-0f94d3c70be1"
```
Implement an idempotent ensure-application-profile operation keyed by
application plus verified issuer and subject. Seed only approved profile
defaults and preserve application ownership of application-specific data.
Verified email may suggest an explicit link to an existing local profile but
must never authorize an automatic takeover.
Done when repeated OIDC callbacks return the same profile and collisions
require explicit authenticated resolution.
Cancelled here because application profiles are application-owned. The
coulomb-social consumer implements this under CSOC-WP-0003 using its unique
`(issuer, subject)` Member binding; user-engine continues to supply `/me`.
## T04 - Carry assurance and step-up requirements
```task
id: USER-WP-0022-T04
status: cancel
priority: high
state_hub_task_id: "d3bec8c6-e8d8-46d5-8fa2-b4675ff1ade8"
```
Model the application's minimum assurance and per-user/profile step-up policy
as data consumed by KeyCape/application authorization. Do not let profile data
issue tokens or weaken client minimums. Add a reauthentication/step-up handoff
that returns to the intended action after fresh OIDC authentication.
Done when a regular profile can be password-only while a profile or protected
action can require MFA without changing global identity facts.
Cancelled here in favor of KEY-WP-0008 client policy and CSOC-WP-0003 action
step-up. user-engine must not become the token assurance authority.
## T05 - Registration and JIT security matrix
```task
id: USER-WP-0022-T05
status: progress
priority: high
state_hub_task_id: "0a5a5f3a-0d47-4d5d-bda5-e2c7c737fee6"
```
Cover enumeration resistance, duplicate username/email, verification
replay/expiry, provider outage and compensation, return-state tampering, JIT
replay, account-link collision, cross-tenant profile access, step-up downgrade,
unlink, and deletion. Verify audit/outbox redaction and correlation.
Done when the full suite and deployed consumer conformance both pass.