Skip to content

Commit fa7ddee

Browse files
sametbasbugclaude
andcommitted
Stop telling people a revoke closes their session on the site
It does not, and saying so is worse than saying nothing. Revoking burns the Orbit tokens the site holds; the site's own session belongs to the site — Supabase issues its own JWT and refresh token and never asks Orbit again when it refreshes. A custom OIDC provider has no back-channel logout, so there is nothing to implement here, only something to stop claiming. The failure mode is not cosmetic: on a shared computer, "your session on that site will close" sends someone away from an open session. The confirm dialog, the success message, the dashboard card and the consent screen now state the same true thing, and a test holds the consent screen to it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1 parent 78fc9fb commit fa7ddee

5 files changed

Lines changed: 35 additions & 4 deletions

File tree

‎docs/V6_PROJECT_LEDGER.md‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2285,3 +2285,23 @@ Anything under `docs/archive/` describes an earlier state and is frozen. Read it
22852285
tokens minted — so the server side had completed and the failure had to be in
22862286
the browser's last hop. Checking the database first turned a vague "the screen
22872287
is still there" into a bounded search.
2288+
- The revoke button promised something it cannot deliver, and the promise was
2289+
the dangerous part. The confirm dialog read "O sitedeki oturumun kapanır" —
2290+
your session on that site will close. It does not. Revoking burns the Orbit
2291+
tokens the site holds, and the audit trail records `site.grant_revoked`, but
2292+
the site's own session is the site's: Supabase mints its own JWT and refresh
2293+
token and never re-checks Orbit when refreshing. There is no back-channel
2294+
logout with a custom OIDC provider, so this is not a bug to fix in code — it
2295+
is a sentence to fix in the interface.
2296+
- Why it matters beyond wording: someone who revokes on a shared computer and
2297+
reads "your session will close" walks away believing they are signed out. The
2298+
dialog, the success message, the dashboard card and the consent screen now all
2299+
say the same true thing — the keys drop immediately, the site session stays
2300+
open and has to be closed there. A test asserts the consent screen carries the
2301+
caveat and fails when it is removed.
2302+
- Re-consent after a revoke reuses the same grant row and clears its
2303+
`revoked_at`, so the row alone cannot tell you a revocation ever happened. The
2304+
history lives in `audit_events`, which held `site.consent_recorded`,
2305+
`site.tokens_issued`, `site.grant_revoked`, then a fresh consent and issue —
2306+
in that order. Worth knowing before anyone reads a live grant row as proof
2307+
that access was never withdrawn.

‎scripts/orbit-site-authorization-tests.ts‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -973,6 +973,12 @@ describe('Orbit as a sign-in door for other sites', { concurrency: false }, () =
973973
/* İstenmeyen kapsamın metni sayfaya hiç girmiyor. */
974974
assert.equal(html.includes('Herkese açık gönderilerin'), false);
975975
assert.match(html, /@samet/u);
976+
/* İptalin NE YAPMADIĞI da ekranda. Panelde "o sitedeki oturumun kapanır"
977+
* yazıyordu ve bu yanlıştı: Supabase kendi oturumunu üretiyor, yenilerken
978+
* Orbit'e bir daha sormuyor, ve bizim uzaktan kapatma yolumuz yok. Yanlış
979+
* söz burada zararsız değil — paylaşılan bir bilgisayarda "kestim, çıktım"
980+
* diye kalkan biri açık oturum bırakır. */
981+
assert.match(html, /oturumu ayrıca kapatman gerekir/u);
976982
});
977983

978984
test('a hostile client label cannot inject markup into the consent screen', async () => {

‎src/pages/dashboard.astro‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ import { LEGAL_LAST_UPDATED } from '../data/legal';
226226
kişinin neyi kestiğini bilmemesi olurdu. -->
227227
<article id="connected-sites-card" class="dashboard-card account-card section-card">
228228
<h2>Bağlı siteler</h2>
229-
<p class="section-help">Orbit hesabınla giriş yaptığın siteler. Bağlantıyı kesmek o sitedeki anahtarları anında düşürür; sitenin kendi kaydına aldığı bilgileri silmez.</p>
229+
<p class="section-help">Orbit hesabınla giriş yaptığın siteler. Bağlantıyı kesmek Orbit’in o siteye verdiği anahtarları anında düşürür ve site Orbit’ten yeni bilgi alamaz. İki şeyi yapmaz: sitedeki oturumunu kapatmaz (oradan ayrıca çıkman gerekir) ve sitenin kendi kaydına aldığı bilgileri silmez.</p>
230230
<div id="connected-sites" class="dashboard-list"></div>
231231
</article>
232232
<div class="truth-note">

‎src/scripts/dashboard.js‎

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -337,12 +337,17 @@ async function loadConnectedSites() {
337337
? ` · son giriş ${new Date(site.lastUsedAt).toLocaleDateString('tr-TR')}`
338338
: '';
339339
item.innerHTML = `<strong>${escapeHtml(site.label)}</strong><div class="meta">${escapeHtml(since)} tarihinden beri${escapeHtml(lastUsed)} · ${escapeHtml(site.scopes.join(', '))}</div>`;
340+
/* Uyarı metni bilerek "oturumun kapanır" DEMİYOR, çünkü kapanmıyor.
341+
İptal Orbit'in o siteye verdiği anahtarları düşürüyor; sitenin kendi
342+
açtığı oturum bize ait değil ve ona uzaktan dokunamıyoruz. Eski metin
343+
kapandığını söylüyordu ve bu, paylaşılan bir bilgisayarda "kestim,
344+
çıktım" diye kalkan birini açık oturumla bırakır. */
340345
item.append(actionButton('Bağlantıyı kes', async () => {
341-
if (!window.confirm(`${site.label} bağlantısı kesilsin mi? O sitedeki oturumun kapanır.`)) return;
346+
if (!window.confirm(`${site.label} bağlantısı kesilsin mi? Orbit'in o siteye verdiği anahtarlar hemen düşer ve site Orbit'ten yeni bilgi alamaz. Sitedeki oturumun açık kalır; oradan ayrıca çıkman gerekir.`)) return;
342347
try {
343348
await mutate(`/v1/me/connected-sites/${encodeURIComponent(site.id)}/revoke`);
344349
await loadConnectedSites();
345-
flash('Site bağlantısı kesildi.');
350+
flash('Bağlantı kesildi. Sitedeki oturumun varsa oradan ayrıca çıkman gerekir.');
346351
} catch (error) { flash(error.message, 'error'); }
347352
}, 'danger'));
348353
host.append(item);

‎src/server/http/site-consent-page.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -233,7 +233,7 @@ ${details}
233233
</form>
234234
235235
<p class="fine">İzni Orbit panelindeki <strong>bağlı siteler</strong> bölümünden
236-
geri alabilirsin.</p>
236+
geri alabilirsin; sitedeki oturumu ayrıca kapatman gerekir.</p>
237237
</main>
238238
</body>
239239
</html>`;

0 commit comments

Comments
 (0)