{"$schema":"/schemas/d06-browser-auth-pre-admission.v1.schema.json","schemaVersion":"developer.reits.tech/d06-browser-auth-pre-admission/v1","observedAt":"2026-07-24T11:04:38Z","status":"D06_PRE_ADMISSION_REPOSITORY_IMPLEMENTED_D05_AND_BROWSER_AUTH_GATES_BLOCKED","planBinding":{"planId":"D06-P0-BROWSER-AUTH-SDK-BFF-PRE-ADMISSION-V1","sha256":"0ed97d8a0844b5db0a2c8fa1c40cbcf7630f693ab3d46b9dcfcded4f28af1dc9"},"program":{"totalKnives":36,"acceptedKnives":4,"currentOrdinal":5,"currentKnife":"D05","candidateKnife":"D06","remainingIncludingCurrent":32,"remainingAfterD05":31,"d05Accepted":false,"d06Activated":false,"ledgerAdvanced":false},"knife":{"id":"D06-P0","title":"Browser Auth SDK / BFF source-bound pre-admission","kind":"PRE_ADMISSION","owner":"Identity Platform + Security + Consumer Owners","repositoryImplementationComplete":true,"countsAsProgramAcceptance":false,"nextExecutableTask":"D05-T02","activationRequires":"D05_ACCEPTED_AND_LEDGER_CAS_TO_D06"},"sourceSnapshot":{"repositoriesFetched":4,"repositories":[{"id":"reits-auth","revision":"ca7694128287621adcbf1637fbaf720831d42624","branch":"main","dirtyFiles":0,"evidence":[{"path":"docs/unified-account-auto-provision.md","gitBlob":"23185e5018d92b83779387839275b67855d276d9","finding":"The repository explicitly records missing authorization-code, PKCE, Discovery and JWKS plus HS256, long TTL and non-durable challenge blockers."}]},{"id":"miniapp-open-platform","revision":"41d67048b745fe224dac673268d8b712d2ef2a4f","branch":"main","dirtyFiles":0,"evidence":[{"path":"services/developer-api/cmd/server/main.go","gitBlob":"933c0815bfdfb9ec22f68f4913e40d08693118f7","finding":"The login routes return HTTP 421 with authBaseUrl but no browser authorization handshake."},{"path":"packages/portal-web/src/auth.tsx","gitBlob":"f6208e38942ccc8d95ffef8ba1d7797af74ccb3c","finding":"The portal reads, writes and removes reits.portal.token in localStorage."},{"path":"packages/portal-web/src/pages/LoginPage.tsx","gitBlob":"87ce6750007be5f035bd79cbc333a8b11ac6658b","finding":"The current developer login page directly requests and confirms an email challenge, then stores access_token in browser state."}]},{"id":"public-booking-platform","revision":"6a38c3df682ea225d296ec9ec50a1407f26ac7d8","branch":"main","dirtyFiles":0,"evidence":[{"path":"apps/api/server.js","gitBlob":"e827b220ad8e7f6bb7ec4467b37ac5e5434c8b76","finding":"A SameSite=Lax HttpOnly Secure member-session cookie exists and is a reusable BFF migration foundation."},{"path":"apps/web/console.js","gitBlob":"d339d86e64448ec0cd676c16f6316aa0fffc60b4","finding":"The merchant console still treats matrixOrderToken localStorage Bearer as an authentication fallback."}]},{"id":"opensdk","revision":"40d9219d607c60482c1ab11c4951296d29b22f22","branch":"main","dirtyFiles":0,"evidence":[{"path":"README.md","gitBlob":"d9dcfce9c1cb41d0d03d6b81c3c89815899fcc2e","finding":"The published SDK is a Go bot Bearer client; no browser authorization or BFF session package exists."}]}]},"foundationSignals":[{"id":"FOUNDATION-01","title":"Durable session and refresh rotation primitives","repository":"reits-auth","state":"OBSERVED_NOT_BROWSER_BOUND"},{"id":"FOUNDATION-02","title":"Explicit 421 delegation to auth.reits.tech","repository":"miniapp-open-platform","state":"OBSERVED_DEAD_END_HANDOFF"},{"id":"FOUNDATION-03","title":"HttpOnly SameSite member cookie","repository":"public-booking-platform","state":"OBSERVED_PARTIAL_BFF"}],"currentFindings":[{"id":"AUTH-01","severity":"CRITICAL","title":"HTTP 421 is a dead-end delegation","repository":"miniapp-open-platform","observed":"421 + authBaseUrl only","target":"BFF start endpoint creates PKCE, state and nonce then returns an exact redirect","state":"BLOCKED"},{"id":"AUTH-02","severity":"CRITICAL","title":"Long-lived browser Bearer storage remains","repository":"miniapp-open-platform + public-booking-platform","observed":"3 portal token storage operations + 13 matrixOrderToken operations","target":"No long-lived access or refresh token in localStorage, sessionStorage, URL, DOM or postMessage","state":"BLOCKED"},{"id":"AUTH-03","severity":"CRITICAL","title":"Standard browser authorization endpoints are absent","repository":"reits-auth","observed":"No authorization-code, PKCE, Discovery or JWKS","target":"Authorization Code + S256 PKCE + issuer discovery + ES256 JWKS","state":"BLOCKED"},{"id":"AUTH-04","severity":"HIGH","title":"Consumer BFF behavior is inconsistent","repository":"public-booking-platform + miniapp-open-platform","observed":"Booking has a partial HttpOnly cookie; Open Portal keeps a browser Bearer","target":"One host-only encrypted session family with refresh rotation and server-side token custody","state":"BLOCKED"},{"id":"AUTH-05","severity":"HIGH","title":"Browser SDK package does not exist","repository":"opensdk","observed":"Go bot SDK only","target":"Typed browser start/callback/session/logout/step-up package with no token read API","state":"BLOCKED"}],"admissionGates":[{"id":"D06-A01","title":"D05 accepted and ledger CAS completed","owner":"Program Ledger Authority","observed":"D05 0/11; ledger 4/36","state":"DENIED"},{"id":"D06-A02","title":"Authorization Code + S256 PKCE","owner":"Identity Platform","observed":"Absent","state":"DENIED"},{"id":"D06-A03","title":"Discovery + ES256 JWKS","owner":"Identity Security","observed":"Absent; HS256 remains","state":"DENIED"},{"id":"D06-A04","title":"Exact client, origin and redirect registration","owner":"Identity Platform + Consumer Owners","observed":"No source-bound browser client registry","state":"DENIED"},{"id":"D06-A05","title":"Host-only BFF session and refresh custody","owner":"Consumer Owners","observed":"Partial booking cookie only","state":"DENIED"},{"id":"D06-A06","title":"State, nonce, CSRF and replay rejection","owner":"Security Owner","observed":"No cross-repository browser flow receipt","state":"DENIED"},{"id":"D06-A07","title":"Zero long-lived browser Bearer storage","owner":"Consumer Owners","observed":"16 token storage operations","state":"DENIED"},{"id":"D06-A08","title":"Refresh rotation, logout and revocation propagation","owner":"Identity + Resource Owners","observed":"Backend primitives exist; browser journey unqualified","state":"DENIED"},{"id":"D06-A09","title":"Step-up and return-to policy","owner":"Identity Security + Product","observed":"No browser contract","state":"DENIED"},{"id":"D06-A10","title":"Three surfaces × nine real states QA","owner":"Design + QA","observed":"Target UI package only; production receipts 0/27","state":"DENIED"}],"admissionSummary":{"required":10,"satisfied":0,"denied":10,"sourceRepositories":4,"targetSurfaces":3,"realStatesPerSurface":9,"requiredStateReceipts":27,"observedStateReceipts":0,"localStorageTokenOperations":16},"targetArchitecture":[{"ordinal":1,"id":"START","component":"Consumer BFF","contract":"POST /auth/start","responsibility":"Bind issuer, client, exact origin, returnTo, S256 challenge, state and nonce; persist only a short-lived server transaction."},{"ordinal":2,"id":"AUTHORIZE","component":"reits-auth","contract":"GET /oauth2/authorize","responsibility":"Authenticate and consent against registered client, redirect and policy; never return tokens through the browser."},{"ordinal":3,"id":"CALLBACK","component":"Consumer BFF","contract":"GET /auth/callback","responsibility":"Verify state, issuer and one-time code; exchange with verifier from server custody."},{"ordinal":4,"id":"SESSION","component":"Consumer BFF","contract":"GET /auth/session","responsibility":"Issue a host-only HttpOnly Secure SameSite cookie and expose only subject-safe session metadata."},{"ordinal":5,"id":"RESOURCE","component":"Resource BFF","contract":"same-origin /api/*","responsibility":"Attach bounded access server-side and enforce subject, tenant, audience, scope and object authorization."},{"ordinal":6,"id":"REFRESH","component":"Consumer BFF","contract":"POST /auth/refresh","responsibility":"Rotate refresh material once, detect replay and revoke the session family on reuse."},{"ordinal":7,"id":"LOGOUT","component":"Consumer BFF + reits-auth","contract":"POST /auth/logout","responsibility":"Require CSRF, revoke server session, clear cookie and make all consumers deny the old session."}],"targetSurfaces":[{"id":"AUTH-S01","title":"Open Portal sign-in handoff","repository":"miniapp-open-platform","current":"Email OTP form writes access_token to reits.portal.token","target":"Identity-owned authorize handoff with exact host, return path and no token-shaped browser output","primaryAction":"Continue securely","secondaryAction":"Use another account"},{"id":"AUTH-S02","title":"Callback and session establishment","repository":"miniapp-open-platform + reits-auth","current":"421 returns only authBaseUrl","target":"State-bound callback exchanges code in BFF and establishes host-only session before redirect","primaryAction":"Return to Open Portal","secondaryAction":"Restart sign-in"},{"id":"AUTH-S03","title":"Session, expiry and step-up recovery","repository":"public-booking-platform + opensdk","current":"Cookie and localStorage Bearer fallback coexist; no browser SDK","target":"Session-safe UI exposes device, expiry, revoke and step-up state without exposing credentials","primaryAction":"Verify identity","secondaryAction":"Sign out safely"}],"realStateContract":[{"id":"READY","regionChange":"Show verified account, exact relying party, requested scopes and safe continuation."},{"id":"LOADING","regionChange":"Replace form controls with a non-repeatable transaction progress view and disable duplicate submission."},{"id":"EMPTY","regionChange":"Explain that no active session or eligible account exists and offer a source-safe start action."},{"id":"PARTIAL_ERROR","regionChange":"Preserve verified identity while isolating a failed optional profile, consent or device region."},{"id":"ERROR","regionChange":"Discard the authorization transaction and offer a fresh start without replaying code or state."},{"id":"OFFLINE","regionChange":"Stop callback polling, retain no secret material and explain that sign-in cannot complete offline."},{"id":"FORBIDDEN","regionChange":"Hide protected content, show policy owner and deny return-to escalation or scope broadening."},{"id":"CONFIRM","regionChange":"Display step-up reason, relying party, exact action and bounded confirmation window."},{"id":"SUCCESS","regionChange":"Show session established or revoked with a single safe destination and no credential values."}],"negativeTests":["unregistered_client","origin_mismatch","redirect_uri_mismatch","missing_pkce","pkce_downgrade_plain","state_mismatch","nonce_replay","authorization_code_replay","csrf_logout","refresh_token_reuse","expired_step_up","browser_token_leak"],"migrationLanes":[{"repository":"reits-auth","owner":"Identity Platform","deliverable":"OIDC-compatible authorize/token/discovery/JWKS, browser client registry and bounded step-up policy","state":"WAIT_D05"},{"repository":"miniapp-open-platform","owner":"Developer Platform","deliverable":"Replace 421 dead end and localStorage Bearer with start/callback/session/logout BFF routes","state":"WAIT_D05"},{"repository":"public-booking-platform","owner":"Booking Platform","deliverable":"Remove matrixOrderToken fallback and bind existing HttpOnly cookie to reits-auth session rotation","state":"WAIT_D05"},{"repository":"opensdk","owner":"SDK Platform","deliverable":"Add a browser/BFF package that exposes flow states but never access or refresh token values","state":"WAIT_D05"}],"activationContract":{"requiredD05AcceptanceReceipts":1,"observedD05AcceptanceReceipts":0,"requiredLedgerCasReceipts":1,"observedLedgerCasReceipts":0,"requiredAdmissionGates":10,"observedAdmissionGates":0,"requiredStateReceipts":27,"observedStateReceipts":0,"d06ActivationAuthorized":false,"externalWritesExecuted":0},"invariants":{"repositoryDiscoveryComplete":true,"targetUiDefined":true,"admissionVerifierDefined":true,"browserTokensRemoved":false,"d05Accepted":false,"d06Activated":false,"programAdvanced":false},"boundary":"D06-P0 is a source-bound pre-admission package, not D06 activation or acceptance. It records the exact current code and defines three realistic target surfaces, nine real states, ten admission gates and twelve negative tests. Until D05 has 11/11 gates, four final owners and an external ledger CAS, D06 remains blocked; the first executable program task remains D05-T02."}