Skip to content

feat: add support for anonymous sessions - #156

Open
rmad17 wants to merge 7 commits into
mainfrom
feat/anonymous-sessions
Open

feat: add support for anonymous sessions#156
rmad17 wants to merge 7 commits into
mainfrom
feat/anonymous-sessions

Conversation

@rmad17

@rmad17 rmad17 commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

Changes

Added

  • Adds ServerClient.anonymous for pre-login anonymous sessions: create_session,
    get_token, introspect, and logout. Gives a visitor a persistent anon@<uuid>
    identity plus a short-lived access token before they authenticate, with up to 1 KB of metadata attached at
    creation. Framework-agnostic RWA core — mounts no routes and sets no cookies.
    identifier, isolated from the authenticated _a0_session store. AnonymousSession never
    exposes the raw session token to the caller.
  • Adds a token renewal ladder on get_token: fresh cached access token is returned;
    expired access token is re-minted with the session token; an expired or invalid session
    token silently creates a brand-new session, once, surfaced via
    AnonymousSession.is_new. Metadata is lost and sub changes on that silent re-mint — this
    never raises, since an anonymous pre-login session carries no authorization.
  • Injects the anonymous session_token into start_interactive_login() automatically when
    a session is active, sourced only from the SDK's own encrypted store and bound into
    TransactionData under the existing state binding.
  • Adds typed anonymous option/response models (AnonymousSession,
    AnonymousTokenResponse, AnonymousSessionContext, AnonymousSessionIntrospection) and a
    typed error hierarchy under AnonymousApiError, including five config subclasses
    (AnonymousFeatureNotEnabledError, AnonymousClientNotEnabledError,
    AnonymousClientNotSupportedError, AnonymousResourceServerError, AnonymousScopeError)
  • Enforces metadata safeguards client-side before any network call: rejects dangerous keys
    (__proto__, constructor, prototype) and enforces a 1 KB (UTF-8 JSON) size cap.

Testing

As part of manual testing following flows have been completed:

Happy Path

  1. CreatePOST /anonymous/session mints an anon@<uuid> identity; returns session_token (opaque JWE, ANONYMOUS_SESSION_ prefix) + access_token (RS256 JWS, audience-bound).
  2. Get tokenGET /anonymous/session walks the renewal ladder: cached → re-mint via session_token → silent new session.
  3. Login injectionGET /anonymous/login-url confirms session_token is auto-injected into /authorize (session_token_injected: true), no call-site change.
  4. LogoutPOST /anonymous/logout best-effort calls /anonymous/logout, then always clears local store; post-logout GET returns AnonymousTokenError (fail-closed). Issued access tokens self-expire (not
    revoked).

Negative / Fail-Closed

# Scenario Expected result Status
N1 invalid audience anonymous_resource_server_error
N2 ungranted scope anonymous_scope_error
N3 non-string metadata value invalid_metadata (local, pre-network)
N4 dangerous key __proto__ invalid_metadata
N5 metadata >1KB metadata_too_large
N6 no session AnonymousTokenError
  • This change adds unit test coverage
  • This change adds integration test coverage
  • This change has been tested on the latest version of the platform/language or why not

Checklist

try:
async with self._get_http_client() as client:
await client.post(f"{base_url}/anonymous/logout", json=body)
except httpx.HTTPError:
@rmad17
rmad17 marked this pull request as ready for review August 14, 2026 06:11
@rmad17
rmad17 requested a review from a team as a code owner August 14, 2026 06:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants