173 lines
7.4 KiB
Markdown
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.
|