feat: defer most session/ban authority to kf-auth#3627
Merged
Conversation
Contributor
There was a problem hiding this comment.
Pull request overview
This PR updates PubPub’s KF-Auth integration to keep PubPub sessions aligned with KF-Auth bans/session revocations by switching to a new webhook endpoint and adding session correlation (via sid → kfSessionId) plus middleware to re-authenticate or block banned users.
Changes:
- Replace
/api/kf/profile-syncwith/api/kf/webhooksand add handlers for profile updates, bans/unbans, and session revocation events. - Stamp KF-Auth session ID (
sid) onto PubPub sessions to support targeted session deletion onsession.revoked. - Tighten session cookie settings and add middleware for silent OIDC re-auth (prompt=none) and platform-level ban enforcement.
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| stubstub/global/setup.ts | Removes noisy env logging during test setup. |
| server/utils/session.ts | Adds session deletion by KF-Auth session id (kfSessionId). |
| server/spamTag/userQueries.ts | Sync bans/unbans outbound to KF-Auth (deferred) and add a skipKfAuthSync guard for webhook-driven updates. |
| server/server.ts | Updates session secret/cookie settings; wires in silent reauth + platform ban guard. |
| server/middleware/silentReauth.ts | Adds browser-only silent reauth redirect logic using pp-lic and a circuit-breaker cookie. |
| server/middleware/platformBanGuard.ts | Blocks API access for platform-banned users (SpamTag confirmed-spam), with caching. |
| server/kf/webhookHandlers.ts | Implements KF-Auth webhook event handlers (profile, bans, session revocations). |
| server/kf/oidc.server.ts | Adds prompt support for authorize URL, ID token claim decoding for sid, and outbound ban/unban sync helpers. |
| server/kf/api.ts | Implements /api/kf/webhooks, silent-renew login flow, and logout redirect change. |
| server/envSchema.ts | Introduces SESSION_SECRET env var in schema. |
| infra/.env.test | Adds SESSION_SECRET for test env validation. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Issue(s) Resolved
Currently you can ban a user or revoke their in KF-Auth, but this still keeps people signed into pubpub. This shouldnt happen. This PR lets kf-auth act as the session authority for PubPub, making sessions in PubPub linked to sessions in kf-auth, allowing targeted session revocation sync, allowing bans from kf-auth to affect pubpub and vice-versa, and making sessions much shorter on PubPub requiring occasional silent round trips to kfauth to confirm the session is still valid, which creates eventual consistency between PubPub session state and KF Auth sessions state
This implements the slightly different webhooks tructure from (https://github.com/knowledgefutures/kf-auth/pull/12)
Listens on
/api/kf/webhooksrather than/api/kf/profile-syncSee https://github.com/knowledgefutures/kf-auth/pull/12
Explanation of the general idea
explanation_comp.mp4
Demo of the functionality
dem_comp.mp4
Robo summary
Move session & ban management to kf-auth (OIDC) with silent re-auth
What & why
PubPub now delegates identity, sessions, and bans to kf-auth
over OIDC. Previously
PubPub sessions lived 30 days and a ban relied on a single
fire-and-forget webhook —
if it failed, a banned/return user kept a valid session for up
to a month.
This PR makes kf-auth the source of truth and turns PubPub
sessions into short-lived
caches, refreshed transparently via OIDC
prompt=none. Bans areenforced through
several independent layers so no single failure leaves a session
alive.
Changes
Auth flow (
server/kf/api.ts,server/kf/oidc.server.ts)/auth/login→/auth/callback→/auth/session-setOIDCflow with PKCE.
users are renewed in the
background via
prompt=none(buildAuthorizeUrl(..., 'none')), no login page.account the expired session
belonged to (compared via the
pp-lichash carried inencrypted state) — switching
accounts must be a deliberate interactive choice, never a side
effect of renewal.
custom domains receive a
one-time encrypted token and establish the session via
/auth/session-set.kfSessionId(the ID tokensid) is stamped on each sessionso a single revoked
kf-auth session can be targeted precisely.
Session hardening (
server/server.ts,server/envSchema.ts)SESSION_SECRETfrom env (was a hardcoded literal);httpOnly: true;securein prod.proxy: trueso theSecurecookie is emitted behind Fastlywithout the global
trust proxyside effects that would breakreq.hostname-based community routing.domainchosen from the deployment env(
.pubpub.org/.duqduq.org), not the edge-rewritten hostname.silentReauthMiddlewareregistered before the route handlers.Ban enforcement (
server/kf/webhookHandlers.ts,server/spamTag/userQueries.ts,server/utils/session.ts)user.updated,user.banned/unbanned(→ SpamTag),user.sessions-revokedandsession.revoked(→ deletematching local sessions).
Redirect-loop fixes (staging)
Rolling this out on duqduq surfaced an infinite silent-reauth
loop. Root causes, all fixed:
/auth/callbackand/auth/session-setreturned 500 on a renewal without tripping
pp-renew-failed,so any transient failure
re-looped. Now every renewal failure path uses
failRenew()(sets the 1h breaker, 302s
back anonymously, never 500s).
OIDC code →
invalid_grant.Fixed by (1) — renewals no longer 500. (A matching
vcl_fetchguard for^/auth/isrecommended as defense-in-depth; see infra.)
pp-lic(thesession cookie isn't in the page
cache key), replaying "go reauth" after a successful login.
silentReauthMiddlewarenowsends
Cache-Control: private, no-store.Securecookie dropped behind the edge — a smallmiddleware maps Fastly's
Fastly-SSLheader toX-Forwarded-Proto: httpsbefore thesession/SSL middleware.
Test Plan
Screenshots (if applicable)
Optional
Notes/Context/Gotchas
Supporting Docs