Skip to content

Platform Identity, Session And Impersonation — Source Authority

  • Status: CURRENT SOURCE-AUTHORITY MAP / DOCUMENTATION ONLY
  • Current source baseline: qa/master@3c084671c034f8f5136b02dce990ecff6c66d107
  • Related documentation: Platform foundation index
  • Target: React + Next.js adapters over one framework-independent identity/session contract
  • Phase implementation: USER HOLD
  • Effects: no Runtime, DB, role, account, password, session, provider, Wiki DB or deployment mutation

1. Authority Decision

Identity, authentication, session and impersonation answer different questions.

Credential verification
= may this credential start an authenticated session?

Physical actor
= which person/system actually initiated the request?

Effective subject
= which user identity is being represented?

Tenant target
= which tenant owns the requested business data?

Session
= which authenticated interaction continuity is active?

Impersonation
= which explicit actor-to-subject or actor-to-tenant delegation is active?

Authorization
= may this actor/subject perform this action on this record?

A successful answer to one question does not imply the others.

1.1 Required invariants

Actor != Subject
Authenticated != Authorized
Session active != Tenant target valid
Impersonation active != Super-admin actor erased
Password changed != all sessions revoked
Provider-linked identity != local user authority
Client-side session metadata != backend authorization

1.2 No generic identity Process ID

This is a shared platform foundation, not one L3 business process. Do not add a generic identity Process merely to register login/session concerns. Business processes consume a typed identity and access result.


2. Current Source Families

Source Current responsibility Important limitation
login.php username/password lookup, password verification/rehash, session regeneration and original session fields no visible application lockout/MFA/rate-limit; username lookup is not tenant-qualified
config/session.php cookie/session parameters and 20-hour lifetime one TTL used for cookie and GC; no separate idle/absolute/revocation model; @session_start()
app/platform/auth/password_helper.php bcrypt writes plus legacy SHA-512 compatibility verification legacy shared salt remains until legacy callers/data reach zero
app/platform/auth/account_post_helper.php current-password verification and own-password update no session regeneration or other-session invalidation is visible
app/platform/audit/super_admin_post_helper.php super-admin password reset and impersonation start impersonation reason/expiry/reauth/session regeneration are not established
admin-console.php admin entry, tenant selection, tenant-only impersonation and impersonation end impersonation start/end mutate the same PHP session and do not visibly regenerate its ID
config/config.php effective client/user/username/role helpers and physical super-admin test effective subject can replace scalar user/username while original session actor remains implicit
TenantExecutionContext.php typed tenant, actor, subject, request, provenance and strict/compatibility contract foundation is additive; it is not the universal session authority
tenant_execution_context_adapter.php direct user, impersonation, admin override, CLI and integration constructors broad caller adoption is incomplete
app/shared/api/runtime.php authenticated API session and scalar/strict request context strict principal is route opt-in
app/shared/endpoint/* legacy authenticated JSON/page/download entrypoints identity/access behavior differs from API v2 router
index.php application shell authentication, logout and UI session projection logout is a GET page action and manually unsets selected session keys

3. Current Authentication Contract

3.1 Username lookup

Current login lookup is effectively:

SELECT ...
FROM T_USER
WHERE USERNAME = ?
  AND DELETED_AT IS NULL
LIMIT 1

The request does not submit a tenant identity. Therefore one of the following must be true for safe operation:

  • active usernames are globally unique; or
  • some undocumented DB/application constraint resolves collisions; or
  • cross-tenant duplicate usernames are a latent ambiguity.

This documentation does not assert global uniqueness without current schema/data evidence.

3.2 Password verification

bcrypt/modern hash
-> password_verify

legacy 128-hex hash
-> SHA-512(password + Config::PASSWORD_SALT)

When a verified stored hash needs rehashing, login performs a compare-and-set update using the old hash. Failure to update exactly one row aborts sign-in.

3.3 Session creation

After credential verification:

session_regenerate_id(true)
-> CLIENT_ID
-> login_username
-> login_id
-> login_name
-> login_email
-> login_role
-> Telegram linkage fields
-> LAST_LOGIN update
-> role/default landing redirect

The original authenticated session fields remain the physical actor source for super-admin detection.

3.4 Current missing or unproven controls

The inspected source does not establish:

  • login-attempt throttling;
  • account lockout;
  • MFA;
  • password breach/complexity policy beyond minimum length in change/reset flows;
  • trusted-proxy allowlist for X-Forwarded-Proto;
  • session revocation version/store;
  • other-session invalidation after password change/reset;
  • privileged-action reauthentication;
  • device/session inventory;
  • security-notification workflow.

These remain OPEN POLICY / RUNTIME EVIDENCE REQUIRED, not assumed defects or automatic implementation scope.


4. Current Session Contract

4.1 Session settings

TTL: 20 hours
strict mode: enabled
cookies only: enabled
HttpOnly: enabled
SameSite: Lax
Secure: HTTPS or X-Forwarded-Proto=https
cookie lifetime = TTL
gc lifetime = TTL

There is no explicit distinction in the inspected source between:

idle timeout
absolute timeout
privileged-action timeout
impersonation timeout
remembered device
revocation time

4.2 Current session states

The current implementation mainly infers state from PHP session fields.

No login_username
-> anonymous

login_username present
-> authenticated

IMPERSONATE array present
-> impersonation context

session destroyed / expired by PHP
-> unauthenticated on next request

There is no accepted durable session row or session-version check in the inspected path.

4.3 Read-only session release

API GET routes may opt into:

sessionMode = read-only
-> copy session into request
-> session_write_close()

This reduces PHP session lock duration. It does not create a separate identity authority.

4.4 Logout and reset

Current application shell exposes GET page actions.

?page=reset
-> clears selected UI/menu/sessionStorage state
-> does not log out

?page=logout
-> manually unsets known auth/session fields
-> session_destroy()
-> browser redirect

Current source does not visibly delete the session cookie, rotate the session before destruction or revoke other sessions.


5. Actor, Subject And Effective Scalar Identity

5.1 Physical actor

isSuperAdmin() is based on the original session:

SESSION.CLIENT_ID = 0
AND SESSION.login_role = 0

User/tenant impersonation does not overwrite those original fields.

5.2 Effective scalar user

Compatibility helpers can return the impersonated subject instead of the actor.

getSessionUserId()
-> TARGET_USER_ID when selected
-> otherwise login_id

getSessionUsername()
-> TARGET_USERNAME when selected
-> otherwise login_username

getClientId()
-> TARGET_CLIENT_ID when impersonating
-> otherwise session CLIENT_ID
-> otherwise Config::CLIENT_ID

This is useful for legacy caller compatibility but can hide the physical actor unless the caller also reads typed context or audit provenance.

5.3 Effective roles

getEffectiveRoleIds():

  • rereads the impersonated target user's ROLE_ID when a target user exists;
  • otherwise rereads the logged-in user's ROLE_ID for the original session tenant;
  • falls back to session login_role after missing row or DB error;
  • caches the result for the request.

Tenant-only impersonation has no target user, so the effective role set remains the original super-admin role set unless the caller supplies a different compatibility role path. Page behavior may use special super-admin/impersonation logic rather than this role set alone.


6. Current Impersonation Modes

6.1 User impersonation

Current stored session shape:

ORIGINAL_ADMIN_ID
ORIGINAL_ADMIN_USERNAME
TARGET_USER_ID
TARGET_CLIENT_ID
TARGET_USERNAME
TARGET_NAME
STARTED_AT

Start sequence:

assert super-admin at owning endpoint
-> validate target tenant
-> if TARGET_USER_ID > 0, validate user belongs to tenant
-> clear direct-page grant
-> write IMPERSONATE session object
-> invalidate menu cache
-> redirect

Typed context reconstructs:

actor = original SUPER_ADMIN
subject = target USER
accessMode = IMPERSONATION
policyState = STRICT

6.2 Tenant-only impersonation

TARGET_USER_ID = 0
TARGET_CLIENT_ID > 0
subject = null
actor = original SUPER_ADMIN

This mode selects tenant context without representing a real tenant user. It must not be documented as equivalent to target-user role acceptance.

6.3 Admin tenant override

Typed API context supports a separate allowlisted API override:

API entry
+ physical super-admin
+ route explicitly allows override
+ target tenant
+ authorizationRef
+ no simultaneous impersonation

This is distinct from session impersonation.

6.4 Current lifecycle gaps

The inspected source does not establish:

  • reason/ticket requirement for session impersonation start;
  • explicit impersonation expiry beyond the PHP session lifetime;
  • session ID regeneration at start/end;
  • prohibited action categories during impersonation;
  • privileged reauthentication before impersonation/password reset;
  • universal durable start/end audit;
  • automatic end on password/role/tenant changes;
  • cross-device awareness;
  • a complete read-only support mode distinct from write-capable impersonation.

7. Password Change And Reset Boundaries

7.1 Own-password change

Current command uses effective scalar identity:

getSessionUserId()
+ getClientId()
+ current password verify
-> bcrypt update

During user impersonation, those effective values can point at the target user. The intended policy—whether a super-admin may invoke “change own password” while impersonating—is not established by this helper alone.

7.2 Super-admin reset

Current reset identifies:

target user ID
+ target client ID
+ new password

It verifies the target row and writes a bcrypt hash.

7.3 Non-implications

Password row updated
!= current session rotated
!= other sessions revoked
!= provider tokens revoked
!= impersonation ended
!= user notified

8. Service, CLI And Provider Identities

Typed execution context supports:

CLI explicit tenant binding
INTEGRATION explicit tenant binding
SYSTEM or INTEGRATION actor
credential owner reference
authorization reference

Legacy CLI default context remains COMPATIBILITY_ONLY and rejects a new strict write when forWrite=true.

Current provider-specific mappings—Telegram, QuickBooks, Gmail, Twilio or others—remain separate adapter concerns. A provider-linked identifier does not become the local actor or subject automatically.


9. Current Source Discrepancy And Gap Register

ID Current fact / gap Consequence
IDN-GAP-010 login query is username-only duplicate username policy must be proven
IDN-GAP-020 one 20-hour TTL, no explicit idle/absolute split timeout semantics cannot be reconstructed from UI alone
IDN-GAP-030 X-Forwarded-Proto influences Secure cookie trusted proxy boundary must be documented separately
IDN-GAP-040 no visible durable session revocation/version password/reset/logout does not prove all-session invalidation
IDN-GAP-050 impersonation start/end does not visibly regenerate session ID session-fixation and continuity policy remains open
IDN-GAP-060 scalar helpers replace actor with subject audit/authorization callers can lose physical actor provenance
IDN-GAP-070 tenant-only impersonation has no real subject cannot substitute for target-role testing
IDN-GAP-080 effective-role DB failure falls back to session role stale role compatibility is possible
IDN-GAP-090 own-password helper uses effective subject identity impersonation policy must explicitly constrain this action
IDN-GAP-100 logout is GET and destroys current PHP session only CSRF/revocation/cookie semantics remain open
IDN-GAP-110 no current PHP↔Next.js session bridge contract migration cannot begin from UI route alone
IDN-GAP-120 provider/service identities remain adapter-specific system identity must be explicit per callback/job

10. Target Authority Map

Concern Target owner
Credential verification Identity application service and password/identity repository
Session issue/rotate/revoke one session authority shared by PHP/Next.js coexistence adapters
Actor/subject/tenant construction typed ActorContext + TenantExecutionContext
Impersonation delegation explicit impersonation application command and durable audit
Privileged reauthentication identity policy/command, not React component
Service identity explicit system/integration binding
Authorization separate access policy evaluator
Business command owning application module
Audit/correlation separate evidence foundation

React renders identity/session state. Next.js authenticates/adapts requests. Neither owns password policy, impersonation authorization or record access.


11. Source Caller And Retirement Conditions

Current compatibility callers include:

  • getClientId();
  • getSessionUserId();
  • getSessionUsername();
  • getEffectiveRoleIds();
  • direct $_SESSION reads;
  • isSuperAdmin();
  • legacy endpoint authentication checks;
  • route-specific strict tenant principal opt-ins.

A compatibility helper reaches caller-zero only when:

  1. every consequential caller has an explicit actor/subject/tenant contract;
  2. current direct pages and legacy endpoints have accepted adapters;
  3. PHP and Next.js coexistence uses one authoritative session decision;
  4. impersonation start/end/audit/reauth semantics are accepted;
  5. rollback remains possible without issuing duplicate sessions;
  6. current role/page/API behavior is revalidated for Client 1 and Client 2.

12. Evidence Boundary

This source map was produced from repository source. It does not prove:

  • current Production cookie headers;
  • actual proxy topology;
  • real session expiry;
  • duplicate usernames in data;
  • active legacy-password count;
  • login failure frequency;
  • current concurrent sessions;
  • role-change propagation;
  • impersonation field usage in every caller;
  • cross-device logout;
  • provider identity mappings;
  • current Wiki content;
  • Next.js session behavior.

Those require separately authorized Runtime, DB, browser, provider or deployment evidence.

---

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