From b987a3de9e39d9bda6a4bf1acf8f4f64c23090ca Mon Sep 17 00:00:00 2001
From: tegwick
Date: Sat, 26 Sep 2026 23:48:00 +0200
Subject: [PATCH] Name the account site NetKingdom Identity.
Say "Signed in as" the identity, and describe a one-time code as a
higher security level of the NetKingdom sign-in rather than another
sign-in. The account site keeps its own session.
Assistant: grok
Assistant-Session: 01a0d25d-d358-7e13-b84a-d007fbb7e34f
---
docs/account-journeys.md | 10 +++--
src/user_engine/authentication_policy.py | 2 +-
src/user_engine/web.py | 54 +++++++++++++-----------
tests/test_account_awareness.py | 9 ++--
tests/test_account_clarity.py | 4 +-
tests/test_account_recovery.py | 4 +-
tests/test_authentication_policy.py | 2 +-
tests/test_platform_support.py | 2 +-
tests/test_portal_navigation.py | 2 +-
9 files changed, 50 insertions(+), 39 deletions(-)
diff --git a/docs/account-journeys.md b/docs/account-journeys.md
index 860bd3a..d7d3950 100644
--- a/docs/account-journeys.md
+++ b/docs/account-journeys.md
@@ -9,9 +9,11 @@ headless capability alone does not mean a journey is usable or verified live.
## Common interaction rules
-- The header states the verified portal identity, or “Not signed in to this
- portal.” A valid portal session shows Log out; an absent/expired session shows
- Sign in. Never infer identity from URL parameters or an existing provider tab.
+- The header is titled NetKingdom Identity. It states “Signed in as” the
+ verified identity, or “Not signed in.” A valid account-site session shows
+ Log out; an absent or expired session shows Sign in. A one-time code raises
+ the security level of the NetKingdom sign-in and is not another sign-in.
+ Never infer identity from URL parameters or an existing provider tab.
- The portal cannot observe every application or shared-provider session. Explain
this once in sign-out confirmation or expandable identity-switch help, not as
competing login/logout actions everywhere. “Use another account” remains
@@ -34,7 +36,7 @@ headless capability alone does not mean a journey is usable or verified live.
| ID / intent | Success | Failure and recovery | Current support / acceptance |
|---|---|---|---|
-| U01 — Know whether I am signed in | Header and the home page name the verified portal identity, or say the portal session is absent. An application may keep its own session | Expired/unknown cookie shows signed-out state; a query does not invent a session; sign in again | Implemented; automated anonymous/expired/member/operator tests, including the home login-state section |
+| U01 — Know whether I am signed in | Header and the home page say “Signed in as” the verified identity, or that no account-site session exists. An application may keep its own session. A one-time code is a higher security level, not another sign-in | Expired/unknown cookie shows signed-out state; a query does not invent a session; sign in again | Implemented; automated anonymous/expired/member/operator tests, including the home identity section |
| U02 — Sign in to my company application | Personal login lands in the intended tenant and application | Wrong credentials stay on provider; denied membership leads to account help with identity switching | Recovery deployed previously; actual fresh-user acceptance waiting on OTP |
| U03 — Accept an invitation | Confirm intended tenant/role, accept once, then see next setup step | Expired/used/wrong-person invitation explains next step; admin reissues without duplicates | Service/browser routes exist; live delivery and full browser acceptance pending |
| U04 — Set or recover my password | Use actual login name, complete single-use setup, return to sign-in | Missing mail or expired link offers admin-assisted new setup link | Password setup reported successful; login name and sign-in address now named at handoff and in the user entry (2026-09-23 run, USER-WP-0035-T01); email delivery unresolved (USER-WP-0035-T02) |
diff --git a/src/user_engine/authentication_policy.py b/src/user_engine/authentication_policy.py
index 078654b..1f2318e 100644
--- a/src/user_engine/authentication_policy.py
+++ b/src/user_engine/authentication_policy.py
@@ -19,7 +19,7 @@ def page(csrf, result=None):
failure = result.get('failure')
if failure:
messages = {
- 'fresh_platform_mfa_required': 'Verify your identity with a fresh MFA sign-in before viewing or changing policy.',
+ 'fresh_platform_mfa_required': 'Raise the security level with a one-time code before viewing or changing policy.',
'preview_expired_or_changed': 'The review expired, changed or belongs to another session. Check the current policy and review again.',
'policy_changed_review_again': 'Policy changed after this review. Check the current policy and review again.',
'reference_already_used': 'This reference is already recorded. Check the history; use a new reference for a new change.',
diff --git a/src/user_engine/web.py b/src/user_engine/web.py
index 5e609a7..2fe5ede 100644
--- a/src/user_engine/web.py
+++ b/src/user_engine/web.py
@@ -226,9 +226,9 @@ class PortalApplication:
actor = None
self._set_account_navigation(environ, actor)
identity = (
- f'
This portal is signed in as {escape(actor.preferred_username or actor.subject)}.
'
+ f'
Signed in as {escape(actor.preferred_username or actor.subject)}.
This ends your portal session. Your shared NetKingdom sign-in stays active.
'
+ "Log out", '
End this account-site session?
'
+ '
This ends the session on the account site. Your NetKingdom sign-in stays active.
'
'',
), correlation_id)
if path == "/logout" and method == "POST":
@@ -1317,15 +1317,15 @@ class PortalApplication:
def _operation_capabilities(self) -> str:
capabilities = (
- ("Portal sign-in", self.oidc_client is not None, "An existing portal session does not prove a fresh provider sign-in works."),
+ ("Account-site session", self.oidc_client is not None, "An existing account-site session does not prove a fresh NetKingdom sign-in works."),
("Tenant identity management", self.provisioning is not None, "Use tenant administration for login setup or tenant access recovery. Shared identity and factor recovery belong to the sign-in service."),
("Tenant lifecycle", self.tenant_management is not None, "Review the authority's returned version after a change."),
("Notification delivery", self.outbox_delivery is not None, "Inspect the delivery record below. If email cannot be received, use the tenant's assisted password setup process."),
)
- rows = "".join(f'
{escape(name)}
{"Configured; live health unverified" if configured else "Unavailable in this portal"}
{escape(help_text)}
'
+ rows = "".join(f'
{escape(name)}
{"Configured; live health unverified" if configured else "Unavailable on this account site"}
{escape(help_text)}
'
for name, configured, help_text in capabilities)
return ('
Use this page for help with your password and authenticator app.
Two-step verification
-
An authenticator app generates a short-lived code to enter after your password.
-This portal cannot currently confirm whether an authenticator is enabled for your account.
+
An authenticator app generates a short-lived code. Entering that code raises the security level of your NetKingdom sign-in. It is not another sign-in.
+This account site cannot currently confirm whether an authenticator is enabled for your account.
""" + handoff + """
How to set up an authenticator when setup is available
Open authenticator management and check that it shows your account.
Choose Enroll Token, select TOTP, and scan its QR code with your authenticator app.
Enter a current code to confirm setup. Wait for the sign-in service to confirm activation.
-
Follow the recovery instructions shown there, then test a new sign-in before closing your current session.
+
Follow the recovery instructions shown there, then confirm the new security level before closing your current session.
Opening the setup page does not activate two-step verification. To cancel unfinished setup, open All Tokens, select the pending token, and choose Delete. A confirmed authenticator cannot be removed or replaced from this password-only management session; ask your administrator to use audited authenticator recovery.
A code is rejected, or I have lost my authenticator
Use the newest code for the correct account and check that your device sets its time automatically.
@@ -2197,19 +2197,25 @@ Use the login name they provide; it may differ from your display name.
str:
+ level = (
+ "
A one-time code raises the security level of a NetKingdom sign-in. "
+ "It is not another sign-in.
"
+ )
if actor is None:
return (
- '
Login state
'
- "
You are not signed in to this portal.
"
+ '
Identity
'
+ "
You are not signed in.
"
+ f"{level}"
)
name = escape(actor.preferred_username or actor.subject)
verification = "Verified by your identity provider" if actor.assurance else "Verification pending"
return (
- '
Login state
'
- f"
Signed in to this portal as {name}.
"
- "
This is the portal session. An application can keep its own session.
"
+ '
Identity
'
+ f"
Signed in as {name}.
"
+ "
This session is for the account site. An application can keep its own session.
After the password is set, sign in at {escape(self.login_url)}. '
- "This portal does not deliver the setup link; pass it and the login name on yourself.
"
+ "This account site does not deliver the setup link; pass it and the login name on yourself."
f'
",
)
@@ -2372,7 +2378,7 @@ Use the login name they provide; it may differ from your display name. None:
if actor is None:
- _ACCOUNT_NAVIGATION.set('
Not signed in to this portal
')
+ _ACCOUNT_NAVIGATION.set('
Not signed in
')
return
links = 'HomeMy accountSign-in security'
if "platform-operator" in actor.roles:
@@ -2384,13 +2390,13 @@ Use the login name they provide; it may differ from your display name.Log out'
identity = escape(actor.preferred_username or actor.subject)
- _ACCOUNT_NAVIGATION.set(f'