Skip to content

Platform Identity Current Consumer Refresh — 2026-08-10

1. Scope And Precedence

This document refreshes current Identity/Session/Impersonation consumers only. It does not activate the target rebuild packet, change authentication/session policy, authorize credential access, or prove runtime behavior.

Precedence for this review is:

current source at 8981a02
> accepted current policy
> prior current-source refresh
> original rebuild/source packet
> historical candidate

The 2026-08-09 refresh remains useful history but is stale wherever current source has changed since its reviewed baseline.

2. Core Owner Freshness

The original identity packet used 3c084671.... Current owner blobs were compared against that baseline and current source semantics were reread where the blob changed.

Owner Original blob / current blob Classification Current-source meaning
login.php bd73f235... / 2b47ba68... CHANGED, AUTH CORE SUBSTANTIALLY PRESERVED Username-only active-user lookup, password verification/rehash, session ID regeneration and original session fields remain. LAST_LOGIN write now uses a PHP timestamp and ID+tenant predicate rather than the prior username predicate. No source-visible MFA, lockout or privileged reauth was added.
config/session.php c2fb4d25... / c2fb4d25... BLOB UNCHANGED One 20-hour cookie/session/GC lifetime; strict mode, cookies only, HttpOnly, SameSite=Lax and Secure when HTTPS is detected. No separate idle/absolute/revocation timers.
config/config.php b49bdf04... / 5daf910b... MATERIAL IDENTITY CHANGE Scalar effective Actor/Subject/Tenant helpers remain, and request-time active-user/role validation plus session clearing now exist.
app/platform/audit/super_admin_post_helper.php prior/current 76c9bef4... BLOB UNCHANGED FROM RECONCILED OWNER Super-admin user impersonation start remains a current writer; no new reason, expiry or reauth contract is visible in this owner.
app/platform/tenant/api_strict_principal.php current b613e783... CURRENT STRICT ADAPTER Strict API requests reconstruct typed tenant execution context and reject malformed tenant-only impersonation.
app/shared/api/runtime.php prior refresh blob 54675... / current 6ca30568... MATERIAL INTEGRATION CHANGE apiAssertAuthenticated() now invokes active-user validation before protected routes continue. Legacy apiContext() and strict apiStrictPrincipalContext() still coexist.
app/shared/api/router.php current 70fbdaef... CURRENT MIXED-MODE DISPATCH strictTenantPrincipal=true routes use the strict adapter before module/handler dispatch; other protected routes continue through scalar apiContext().
admin-console.php current bd6e5ba5... CURRENT CONSUMER CHANGED Physical super admin can select any existing tenant for console viewing; tenant admin is pinned to its session tenant. main_open creates tenant-only impersonation for super admin. impersonate_end only unsets IMPERSONATE.

Blob change alone is not interpreted as a security improvement. The semantic differences above are the current facts relevant to this task.

3. New Session Invalidation Semantics Since The Prior Refresh

config/config.php now defines two materially relevant functions:

kjClearAuthenticatedSession()
kjValidateActiveSessionUser()

3.1 Original actor validation

On validated protected requests, current source rereads the original physical session identity from:

login_id
CLIENT_ID
login_username
login_role

It then queries the active T_USER row by ID + tenant + username and compares the active role IDs with the session role IDs.

If the original user is missing/deleted or the active role list differs, current source clears the in-memory session, expires the session cookie with the existing cookie parameters and destroys the current PHP session.

This changes the prior gap classification:

role/user drift for an active request
= request-time invalidation now present

central all-session revocation/versioning
= still not established

The mechanism is request-time validation, not a persisted revocation ledger. Another existing browser/session is not shown being proactively deleted; it is expected to fail when it next reaches a path that invokes the validator.

3.2 Impersonated target validation

When IMPERSONATE.TARGET_USER_ID > 0, the validator also checks that the target user still exists for the target tenant/username. If not, it removes IMPERSONATE but preserves the physical actor session.

This is a useful current fail-safe, but it does not establish target-role freshness comparison, privileged reauthentication, impersonation expiry, or a durable revocation record.

3.3 Fail-closed request behavior versus durable session destruction

If the validation query throws, kjValidateActiveSessionUser() returns false. Current page/API callers then deny the request or redirect to login. The catch path itself does not prove that the stored PHP session was destroyed. Therefore:

request continuation on validation error = denied
persistent session deletion on validation error = NOT ESTABLISHED

4. Current Validation Consumers

Current repository search shows kjValidateActiveSessionUser() used by:

  • index.php for the main PHP application shell;
  • app/shared/api/runtime.php for protected API dispatch;
  • app/shared/endpoint/response.php for the legacy endpoint response boundary;
  • tests that assert the contract.

This increases coverage compared with the original packet, but does not prove every standalone/public/provider callback or historical PHP entrypoint uses the validator. Unlisted entrypoints remain evidence-required.

5. High-Risk Consumer Inventory

5.1 Provider credential reveal API

Current route remains:

POST /api/platform/admin/tenants/{clientId}/credentials/{credentialKey}/reveal

The route is authenticated, moduleKey = null, and marks redactRequestBody = true. The handler calls platformApiTenantManagedCredentialAccess(..., 'REVEAL'), which first requires Admin Console access. A non-superadmin caller is additionally restricted to clientId === getClientId().

Current guard meaning:

  • physical super admin: allowed by isSuperAdmin();
  • non-superadmin: effective role ID 1 required and URL tenant must equal effective tenant;
  • an impersonating physical super admin is still physically super admin because isSuperAdmin() reads the original session identity;
  • no current route-level check prohibits reveal while impersonation is active;
  • no current route-level privileged reauthentication, MFA, reason reference or short-lived reveal grant is visible.

Secret-safe note: this task did not call the route, read a credential value, inspect ciphertext, or retrieve any provider secret.

5.2 Current Admin Console UI versus reveal API

Current frontend/pages/platform/admin-console/tenants.php does not contain a /reveal caller in the reviewed source. Provider secret fields render as password inputs with an empty value and only indicate that an existing secret is set. Saving requires entering a replacement secret; blank input does not reveal the stored value.

Therefore the current source distinction is:

reveal API surface = PRESENT
current reviewed Admin Console reveal UI caller = NOT FOUND
current Admin Console secret replacement UI = PRESENT

This corrects any reading of the 2026-08-09 refresh that implied the reviewed current UI necessarily exercised reveal. The API remains high risk because it exists even without a current UI caller.

5.3 Provider credential update/replacement

Current provider UI sends replacement values through the general tenant config save path. Separately, the managed credential update route exists under /credentials/{credentialKey} and shares Admin Console access plus tenant-boundary checks. Identity implications are the same: authorization is based on the current physical/effective PHP session, not on a separate privileged-action reauthentication state.

Credential storage/resolver semantics belong to CTC-CDOC-005 and are intentionally not redefined here.

5.4 Admin Console tenant selection

admin-console.php distinguishes physical super admin from tenant admin:

  • super admin may choose an ID from the current T_CLIENT list;
  • tenant admin ignores client_id selection and stays on its physical session CLIENT_ID;
  • the selected client is placed in KJ_ADMIN_CONSOLE_CLIENT_ID for the console projection;
  • selecting a tenant for console viewing is not by itself persisted impersonation.

Actor/Subject/Tenant:

super-admin console selection:
Actor = physical super admin
Subject = none
Tenant = selected console tenant for the affected console operation
Access mode = admin selection/override, not user impersonation

5.5 Tenant-only impersonation

admin-console.php?action=main_open creates an IMPERSONATE object for physical super admin with TARGET_USER_ID=0, target tenant ID, display username/name and start timestamp.

Current strict adapter explicitly recognizes tenant-only impersonation only when target user ID is exactly zero and target username is non-empty.

Actor = physical super admin
Subject = none
Tenant = target tenant
Access mode = IMPERSONATION

This is support context, not target-role acceptance evidence.

5.6 User impersonation

The super-admin writer remains in super_admin_post_helper.php.

Actor = physical super admin
Subject = target user
Tenant = target user's tenant
Access mode = IMPERSONATION

Current scalar helpers project target user/tenant values to legacy callers, while physical-super-admin checks continue to see the original actor. This duality is intentional compatibility but remains high risk for any mutation that does not explicitly distinguish Actor from Subject.

5.7 API admin override

Legacy apiContext() permits X_ADMIN_CLIENT_ID only for a bounded path allowlist and only when isSuperAdmin() is true. It changes the request's effective clientId without writing IMPERSONATE.

Actor = physical super admin
Subject = none unless another caller-specific projection says otherwise
Tenant = validated header target tenant
Access mode = API ADMIN OVERRIDE

It must not be described as impersonation or target-role evidence.

5.8 Strict API tenant principal

Routes opting into strictTenantPrincipal=true clear the preexisting scalar telemetry context, authenticate, build a typed tenant execution context, and only then perform strict module checks.

tenantApiStrictPrincipalContext() resolves:

  • direct session: Actor and Subject are the direct user;
  • user impersonation: Actor is original super admin, Subject is target user;
  • tenant-only impersonation: Actor is original super admin, Subject is null, Tenant is target tenant;
  • malformed tenant-only principal: rejected.

The strict adapter is a current compatibility bridge, not evidence that all APIs are strict. Non-opted routes continue through scalar apiContext().

5.9 Legacy scalar PHP session paths

The scalar compatibility model remains:

  • getClientId() returns impersonated target tenant first, then session tenant;
  • getSessionUserId() returns target user when present, otherwise original login ID;
  • getSessionUsername() returns target username when present, otherwise original username;
  • physical-super-admin checks use original session state.

Consequently a legacy caller using only effective scalar identity can lose Actor/Subject distinction during impersonation. Such a caller must be classified as SCALAR COMPATIBILITY / PROVENANCE INCOMPLETE unless it separately records the physical actor.

6. Actor / Subject / Tenant Reconciliation

Consumer Actor Subject Tenant Current certainty
Direct PHP/API user logged-in user same user session tenant RESOLVED
Super-admin Admin Console tenant selection physical super admin none selected tenant RESOLVED
User impersonation physical super admin target user target tenant RESOLVED
Tenant-only impersonation physical super admin none target tenant RESOLVED
Legacy scalar caller during user impersonation physical actor exists but may not be passed effective target user target tenant PROVENANCE GAP AT CALLER
Legacy scalar caller during tenant-only impersonation physical actor exists but may not be passed none semantically; scalar username is tenant display label target tenant PROVENANCE GAP AT CALLER
API admin override physical super admin none header-selected tenant RESOLVED AT API BOUNDARY
Strict API direct typed direct actor same typed subject strict local tenant RESOLVED
Strict API user impersonation typed physical actor typed target subject strict target tenant RESOLVED
Strict API tenant-only impersonation typed physical actor null strict target tenant RESOLVED
Credential reveal/update physical actor is inferable from session; handler context is not a full typed provenance envelope effective subject depends on impersonation URL/effective tenant guard AUTHZ RESOLVED; DURABLE PROVENANCE/REAUTH UNKNOWN

7. Logout, Timeout, Revocation And Reauthentication Refresh

Logout

Current index.php?page=logout is still a GET action. It unsets selected session fields and calls session_destroy(). It does not call the newer kjClearAuthenticatedSession() helper, so explicit cookie expiration is still not established for the ordinary logout path.

Session timeout

config/session.php remains one 20-hour lifetime for cookie and PHP GC. Source still does not distinguish:

idle timeout
absolute session lifetime
impersonation timeout
privileged reauthentication lifetime
revocation grace period

Revocation/invalidation

Current state is now mixed:

  • deleted/missing physical user: request-time invalidation on validated paths;
  • physical user's role-list change: request-time invalidation on validated paths;
  • deleted/missing impersonated target user: impersonation object removed on validated paths;
  • password change/reset: no current session-version comparison or all-session revocation was found;
  • explicit administrator revoke-all-sessions command: not found in reviewed source;
  • session ID rotation at impersonation start/end: not found;
  • session ID rotation after own/admin password change: not found.

Privileged-action reauthentication

No separate recent-password proof, MFA proof, reauth timestamp, privilege lease or per-action grant was found for:

  • credential reveal;
  • credential replacement;
  • impersonation start/end;
  • admin password reset;
  • tenant-only support context.

This remains an open policy/implementation gap; this documentation task does not decide the policy.

8. Secret-Safe Credential-Reveal Implications

A reveal response makes secret material available to the authenticated browser/request context for at least the lifetime of that response. Even with request-body redaction and no-store/no-cache response controls, identity/session safety still depends on:

  • who the physical actor is;
  • whether impersonation/admin override is active;
  • whether the session was freshly reauthenticated;
  • whether the client/browser is trusted;
  • whether response/logging/telemetry paths exclude the secret;
  • whether a durable audit records the physical actor, target tenant, credential key, action and result without secret content.

Current source does not establish all of these as one complete control. Therefore a source-present reveal endpoint must not be treated as operationally approved merely because it is guarded by Admin Console access.

9. Current Unknowns And Policy Questions

  1. Should provider secret reveal remain available at all when the current Admin Console UI uses replacement-only behavior?
  2. If reveal remains, which actors may use it: physical super admin only, tenant role 1, or a narrower capability?
  3. Must reveal/update be prohibited during user or tenant-only impersonation?
  4. What recent-auth/MFA/step-up interval is required for reveal, password reset and impersonation?
  5. Should logout move to a POST/CSRF-protected command and use the centralized session clear helper?
  6. What are the approved idle, absolute and impersonation timeout values?
  7. What all-session revocation/version mechanism is required after password reset, account disable or high-risk role change?
  8. Which remaining legacy entrypoints bypass kjValidateActiveSessionUser()?
  9. Which current mutation/audit writers persist physical Actor separately from effective Subject?

These are not silently answered by the target rebuild packet.

10. Read-Only Evidence Boundary

The executable-but-not-run evidence plan is defined in:

../operations/platform-identity/RBR-IDENTITY-002-READONLY-PREFLIGHT.md

It is explicitly secret-safe and prohibits credential values/ciphertext, login, logout, impersonation, password changes and credential reveal/update.

11. Result

Core owner freshness classified: PASS (source review)
High-risk consumer inventory: PASS (source review)
Actor/Subject/Tenant reconciliation: PASS with caller-level provenance gaps marked
Credential secret retrieval: NOT_RUN
Session/account/credential mutation: NOT_RUN
Runtime/environment evidence: NOT_RUN
M3/M4/stabilization evidence: NOT_APPLICABLE / not claimed
External effects: NONE
Phase impact: NONE

---

Source: docs/reconstruction/PLATFORM_IDENTITY_CURRENT_CONSUMER_REFRESH_2026-08-10.md — ctc repository · This page is an English translation of the source document. Identifiers, file paths and code symbols are unchanged.