Supabase owns the login. minidauth supplies an identity the Tide network vouches for and roles a quorum decides. Free tier, no card.
Recorded against a real Supabase project and the public Tide network, in that order.
1. Signed in with Supabase, no Tide identity yet. Authentication has already happened. There is nothing to authorise against.
2. Linking goes to the Tide enclave. Not to this app and not to minidauth. The password is typed into a page served by the ORK network, and neither this app nor minidauth ever sees it.
3. Linked. minidauth verified the blind signature before answering, so the vuid is proven rather than claimed. The example says plainly that the existing token predates the link, instead of pretending it refreshed.
4. Signed in again, now carrying roles. The roles are not in the Supabase token. They were read from the grant record, which only a quorum can change.
5. The protected page. Allowed, because the grant record says so.
Without vault-reader the same page refuses, and no row you can edit in Supabase changes that.
Create a project at supabase.com, then take three values from
Project Settings → API: the URL, the anon key, and the service_role key.
While you are there, turn email confirmations off under Authentication → Providers → Email, or the demo sign-up will wait for a link in your inbox.
Register this app's Tide callback with minidauth, which merges rather than replaces:
MINIDAUTH_OPS_TOKEN=<ops token> APP_URL=http://localhost:3004 \
node ../shared/register-callback.jsThen:
npm install
export SUPABASE_URL=https://xxxx.supabase.co
export SUPABASE_ANON_KEY=...
export SUPABASE_SERVICE_ROLE_KEY=... # server side only, never sent to a browser
export MINIDAUTH_TOKEN=dev-sample-app-token
npm start # http://localhost:3004Sign up, link a Tide identity, sign in again to pick up the new token, then try the protected page.
It refuses until somebody holds vault-reader, which is granted through the quorum in minidauth's
console.
app_metadata.tide_vuid, written with the service role key.
Not user_metadata, because a user can write their own. The distinction matters more here than
elsewhere: Supabase copies app_metadata straight into the access token, so it is genuinely tempting
to put roles there and read them from the JWT.
Do not. A role in a token this project can mint is a role this project can grant itself, which is
the single point of failure minidauth exists to remove. /protected reads roles from the grant
record on every request instead, and no row you can edit in Supabase will get you into it.
One consequence worth knowing: because the token carries app_metadata, a token issued before the
link does not have the vuid in it. The example says so and asks you to sign in again rather than
pretending it refreshed.
Run end to end against a real Supabase project and the public Tide network: sign in, link, and a protected page that reads its answer from the grant record. The screenshots above are that run.
This example also mounts a tideless page at /tideless (see
../shared/tideless.js). It is the opposite of linking a Tide identity: the
signed-in Supabase user encrypts and decrypts with no Tide account and no doken. Their own
the Supabase user id is the subject, and a role a quorum granted that id is the gate; minidauth issues the
vouchers and the ORK cohort does the crypto. The browser holds no credential — the server proxies
the vouchers and sets the uid from its own verified session, so a page cannot read as another user.
Two prerequisites, both one-time:
-
minidauth must have a PUBLIC decrypt policy (voucher-gated, not doken-gated). A key's decrypt policy is either PUBLIC or PRIVATE, so this is a different key/policy from the account-linked flow above. See docs/running.md.
-
Grant the user's id a role as a tideless subject, through the quorum:
curl -sX POST localhost:8081/iga/change-requests/role -H "Authorization: Bearer $ALICE" \ -H 'Content-Type: application/json' -d '{"vuid":"<supabase user id>","role":"vault-reader","tideless":true}' # $BOB and $CAROL authorize, then commit
Then sign in and open /tideless. The trade this makes — minidauth becomes the authority for these
users' reads — is spelled out in examples/tideless.




