AUTH4D-11 sessions and refresh behavior

This ticket adds the authoritative session service and its storage adapters; it does not add HTTP routes. The API composition should call SessionService after a trusted sign-in or device approval, and from the OAuth token, revocation, and logout route factories.

Session creation issues an RS256 access token for the requested client audience, with only scopes allowed by the current tenant application policy. Access and ID tokens each expire after five minutes. An ID token is returned only when the request included openid; its audience is the client ID, and it preserves the original auth_time during refresh. Browser applications also receive a tenant-scoped opaque handle in a __Host-auth4_session cookie (Secure, HttpOnly, SameSite=Lax, Path=/, no Domain). Native applications receive no browser cookie.

Refresh tokens are issued only for offline_access and a client that permits the refresh-token grant. They are client-bound, rotate on each successful refresh, idle-expire after seven days, and have a thirty-day absolute lifetime. Reuse of a consumed refresh token atomically revokes its whole family and associated session, including the current successor. Concurrent refreshes run through SQLite-backed Durable Object transactions; a duplicate refresh cannot retain a live successor. Disabled users, disabled clients, and unavailable tenants are rejected before refresh and revoke the associated family.

Browser handles have a twelve-hour idle deadline and a seven-day absolute deadline. Online access token checks verify the signed access-token class and consult Durable Object session state so revocation takes effect immediately. Offline JWT checks continue to have a maximum five-minute revocation delay.

D1 session_indexes stores only tenant, user, client, session ID, timestamps, and revocation metadata for console queries. It never stores refresh tokens, browser handles, or their hashes and is never used to authenticate or refresh a session. If D1 indexing fails during session creation or browser-session touch, the service fails closed and revokes the authority record where possible.

The API Worker must register and bind SessionStateStore as a tenant-routed SQLite Durable Object namespace before constructing the production service. Each object name and each stored row includes the tenant ID; its RPC methods are internal Worker calls and have no public HTTP surface.

Source: docs/api-spec/auth4d-11.md