Skip to content

feat!: add readSession and fake tenant org/account APIs - #46

Merged
KyleJune merged 3 commits into
mainfrom
feat/fake-tenant-org-account-api
Sep 26, 2026
Merged

KyleJune merged 3 commits into
mainfrom
feat/fake-tenant-org-account-api

Conversation

@KyleJune

@KyleJune KyleJune commented Sep 24, 2026 •

Copy link
Copy Markdown
Member

Summary

The BFF can now return token-free session state directly to server-rendered pages through HonoBff.readSession(c). The fake tenant also supports the organization, account, device-session, and linked-account APIs needed for runnable starter demos. The expanded tenant contract exercises these APIs against a fixture.

readSession shares the session probe's live-session lookup and response projection. Own-session mode enforces sessionMaxAgeMs; shared mode leaves lifetime enforcement to the application/store. Callers must apply private/no-store caching to personalized pages.

Fake tenant credentials now follow first-party session revocation rules, with an explicit third-party exception. Credential issuance is serialized per person so simultaneous exchanges from distinct browsers retain their own session binding; ending one browser session leaves the other active. Organization mutations enforce membership tiers, invitations respect ownership and expiry, and metadata validation applies its size limit to UTF-8 bytes after merging.

Breaking changes

  • TenantContractFixture.linkAccount is required; addUser must honor the profile fields for email, verification and password, and signIn accepts { sameBrowser }.
  • The fixture client must be first-party. Fake first-party credentials now end with their login session; a membership seeded without roles receives the member tier.
  • FakeTenantClient.type selects first-party (default) or third-party behavior.

The branch is refreshed onto package main at 0.7.0. The automatic release determines the next version; adopting it in the starters remains a separate change.

Validation

  • deno task check, deno task test --parallel --reporter=dot (231 tests, 2,753 steps), and deno task test:all passed on native Windows.
  • Four independent reviews covered security, correctness, test coverage and docs. Their verified findings were addressed.
  • The concurrent-browser regression failed before the fix, while a serial control and the pre-feature base remained active. The fixed test verifies each current-session identity and targeted session revocation.
  • Replacing the UTF-8 byte measurement with character count fails the new contract test at its expected refusal assertion.
  • The handoff's real-service contract validation predates this refresh; the starter adoption PR will rerun that contract against the refreshed package.

Closes

Nothing. Refs udibo/udibo#1505 and udibo/udibo#1508.

🤖 Generated with Codex

@KyleJune
KyleJune force-pushed the feat/fake-tenant-org-account-api branch from 106e607 to 75cbdf0 Compare September 24, 2026 22:51
@KyleJune KyleJune changed the title feat: add readSession and fake tenant org/account APIs feat!: add readSession and fake tenant org/account APIs Sep 24, 2026
@KyleJune

Copy link
Copy Markdown
Member Author

feat!: add readSession and fake tenant org/account APIs (75cbdf0, rebased on 0.6.0) — review fixes. The fake now follows the real service's first-party session rules: a same-browser sign-in revokes the session's earlier credentials, and revoking a token (endpoint or refresh-token family replay) ends its session. FakeTenantClient.type "third-party" keeps a credential outside its session. The contract gains checks for those rules, plain-member and cross-organization refusals on revoke/withdraw/list invitations, and the merged metadata cap; all 70 pass against Udibo's identity service. TenantContractFixture now requires linkAccount and takes signIn(..., { sameBrowser }), so the commit is marked breaking with a migration note. The testing guide's refusal wording is corrected (an admin gets 403 on owner-only actions).

@KyleJune
KyleJune force-pushed the feat/fake-tenant-org-account-api branch from 75cbdf0 to 57aee91 Compare September 24, 2026 22:57
HonoBff#readSession(c) lets a server that renders pages read who is
signed in without a round trip to GET /auth/session. It counts a session
exactly when the probe does, destroys one past sessionMaxAgeMs and clears
its cookie, needs no CSRF header, and never returns a token. It answers
the same SessionState BffClient.getSession() does, so it can seed the
React provider's initialState.

createFakeTenant now answers the tenant-host organization API
(/api/organizations: create, list, get, rename, delete, members,
member-roles, invitations, offers, accept, revoke a tier) and the
account API (/api/account metadata read and merge, login sessions with
revoke and revoke-others, linked accounts with the last-method guard).
Memberships are grants, so a pending offer confers nothing. Every
signInAs is a new browser whose first authorization starts a login
session. New seeding: FakeTenantUser userMetadata and hasPassword,
signInAs userAgent and ipAddress, linkAccount and defineOrganizationRole.

A first-party application's credentials belong to their login session,
as on a real tenant. A later sign-in in the same browser revokes the
credentials the session issued before, revoking a token at the
revocation endpoint or through refresh-token reuse ends the session,
and ending the session revokes its credentials. FakeTenantClient takes
type "third-party" for an application whose credentials only name the
session they came from and outlive it.

runTenantContractTests covers both new APIs, including those session
rules, a plain member refused every manager action, a manager kept to
the organization the path names, and the metadata cap applied to the
merged bucket. The same checks pass against the fake here and against
the identity service.

BREAKING CHANGE: TenantContractFixture asks more of a fixture.
linkAccount is now required and links an external account to a person.
addUser must honor its optional profile: give the person profile.email,
verify it unless emailVerified is false, and with password false leave
them no password while signIn can still sign them in. signIn takes a
third argument, and with { sameBrowser: true } it must sign the person
in from the browser their previous sign-in used. The fixture's client
must be first-party. createFakeTenant also changed: a second
authorization under one signInAs revokes a first-party application's
earlier credentials, so call signInAs before each sign-in that should
stay independent, or register the client with type "third-party". A
membership seeded without roles, or with [], now holds ["member"]
instead of none.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@KyleJune
KyleJune force-pushed the feat/fake-tenant-org-account-api branch from 57aee91 to 2c102c7 Compare September 24, 2026 22:58
@KyleJune

Copy link
Copy Markdown
Member Author

feat!: add readSession and fake tenant org/account APIs (2c102c7) — I moved the branch back onto 0.5.1, which supersedes 75cbdf0. A pointer at a 0.6.0 commit would take Udibo's starters (jsr:@udibo/oauth2@^0.5.0) off this branch and onto the published 0.5.0. The commit also no longer touches smoke-consumer/deno.lock: that change was only a re-resolution to the linked version, and it conflicted with #47. The content is otherwise identical. On this base, check, test:all and test --parallel all pass, and the branch merges cleanly with main.

@KyleJune
KyleJune merged commit 17e28ab into main Sep 26, 2026
7 checks passed
KyleJune pushed a commit that referenced this pull request Sep 26, 2026
# [0.8.0](0.7.0...0.8.0) (2026-09-26)

* feat!: add readSession and fake tenant org/account APIs ([#46](#46)) ([17e28ab](17e28ab))

### BREAKING CHANGES

* TenantContractFixture asks more of a fixture.
linkAccount is now required and links an external account to a person.
addUser must honor its optional profile: give the person profile.email,
verify it unless emailVerified is false, and with password false leave
them no password while signIn can still sign them in. signIn takes a
third argument, and with { sameBrowser: true } it must sign the person
in from the browser their previous sign-in used. The fixture's client
must be first-party. createFakeTenant also changed: a second
authorization under one signInAs revokes a first-party application's
earlier credentials, so call signInAs before each sign-in that should
stay independent, or register the client with type "third-party". A
membership seeded without roles, or with [], now holds ["member"]
instead of none.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(testing): isolate concurrent session issuance
@github-actions

Copy link
Copy Markdown

🎉 This PR is included in version 0.8.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant