Draft preview via York Factory OAuth (Doorkeeper)#22
Open
xrendan wants to merge 11 commits into
Open
Conversation
Add Next.js Draft Mode support gated behind York Factory OAuth with admin scope, enabling admins to preview unpublished memos directly in TradingPost. - src/app/api/auth/login/ — initiates OAuth flow with CSRF state cookie - src/app/api/auth/callback/ — exchanges code for token, enables Draft Mode, stores Doorkeeper access token as httpOnly cookie - src/app/api/auth/logout/ — disables Draft Mode and revokes Doorkeeper token - src/lib/api/client.ts — apiFetch accepts previewToken; passes as Bearer header and bypasses ISR caching for preview requests - src/lib/api/memos.ts — fetchMemo threads previewToken through to apiFetch - src/app/memos/[slug]/page.tsx — reads draftMode() + yf_preview_token cookie; fetches draft content when active; shows "Draft Preview Mode" banner with Exit link; generateMetadata also respects draft mode - src/middleware.ts — wires up proxy.ts as actual Next.js middleware so the PostHog dashboard gate runs correctly
NextResponse.redirect() in Next.js 16 does not reliably merge cookies set via draftMode().enable() from next/headers. The yf_preview_token cookie is sufficient as the preview indicator and is passed directly to fetchMemo.
Share the yf_preview_token cookie from the memo Server Component to apiFetch via a React.cache() per-request store (setPreviewToken/getPreviewToken) instead of threading it through fetchMemo args. Add DraftPreviewBanner shown below the navbar when previewing a draft, and document production OAuth / API env vars in .env.local.example.
16091e1 to
67dd33c
Compare
The OAuth provider is now general login: request no admin scope. After the token exchange the callback calls York Factory's /api/v1/me to learn whether the user is an admin and stores it in a yf_admin cookie. Draft preview (the banner + uncached draft fetch) is enabled only for admins; non-admins get a normal logged-in session. Draft access is still enforced server-side by York Factory, so the cookie is a UI hint, not a security boundary.
Keep in sync with york_factory's registered redirect_uri; OAuth requires an exact redirect_uri match.
…in PostHog - rename yf_preview_token -> yf_access_token (general login, not just preview) - add lib/auth.ts getCurrentUser() — admin/identity resolved live from /me, React.cache-deduped per request; removes the stale yf_admin cookie - collapse duplicated cookie checks in memos/[slug] into one helper - /api/auth/me proxy + <IdentifyUser/> to identify users in PostHog on login, reset on logout (once-per-session gate)
- PostHog identify keyed on email (no internal id in the frontend) - YfUser drops id; getCurrentUser no longer maps it - resolvePreviewToken -> resolveAccessToken, previewToken var -> accessToken
- M2: store refresh token + middleware that silently renews the access token when it expires; logout now revokes both access and refresh tokens - M1: safeRedirectPath() rejects protocol-relative/absolute redirects in login and callback (no more //evil.com open redirect) - H1: oauthConfig() refuses localhost fallback in production (fail loudly) - L2: getCurrentUser logs YF 5xx/network errors instead of silently treating a transient outage as 'signed out' - centralize OAuth config/cookies in lib/oauth.ts
Converts the 'Exit preview' links to POST forms and the logout route from GET to POST with an Origin check + 303 redirect. Removes the CSRF force-logout vector (cross-site <img>/<a> could previously hit GET logout).
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.
Summary
Admin draft-preview mode for memos, backed by York Factory's Doorkeeper OAuth provider (paired with york_factory PR #64).
/api/auth/login,/callback,/logout): authorization-code flow against York Factory. The access token is stored in an httpOnlyyf_preview_tokencookie (never readable by browser JS).preview-token.ts): the memo Server Component reads the cookie and callssetPreviewToken;apiFetchreads it viagetPreviewTokenand forwards it asAuthorization: Bearer <token>on the server-to-server call to York Factory. The browser never talks to York Factory directly.DraftPreviewBanner: amber "DRAFT — not yet published" bar rendered in-flow below the navbar; a "not found" variant for admins hitting a missing slug.Env vars
See
.env.local.example. Production values (set in the buildcanada.com deployment env — none are currently set):YF_OAUTH_URLhttps://auth.buildcanada.comYF_OAUTH_CLIENT_IDdb:seedYF_OAUTH_CLIENT_SECRETdb:seedYF_OAUTH_CALLBACK_URLhttps://buildcanada.com/api/auth/callbackYORK_FACTORY_API_URLhttps://yorkfactory.buildcanada.com/api/v1Without these,
YF_OAUTH_URL/YF_OAUTH_CALLBACK_URLfall back tolocalhost, so production preview login is currently broken.Testing
npx tsc --noEmitclean;eslintclean on changed files.