Skip to content

Commit

Permalink
Use separate jwt's for invoking preview and storing preview state (#2691
Browse files Browse the repository at this point in the history
)
  • Loading branch information
fraxachun authored and Markus Fichtner committed Nov 7, 2024
1 parent 360e661 commit 9b7b3f1
Show file tree
Hide file tree
Showing 4 changed files with 29 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export class SitePreviewResolver {
},
})
.setProtectedHeader({ alg: "HS256" })
.setExpirationTime("1 day")
.setExpirationTime("10 seconds")
.sign(new TextEncoder().encode(this.config.secret));
}
}
13 changes: 9 additions & 4 deletions packages/site/cms-site/src/sitePreview/SitePreviewUtils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { jwtVerify } from "jose";
import { errors, jwtVerify } from "jose";

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export type Scope = Record<string, any>;
Expand All @@ -12,10 +12,15 @@ export type SitePreviewParams = {
previewData?: SitePreviewData;
};

export async function verifySitePreviewJwt(jwt: string): Promise<SitePreviewParams> {
export async function verifySitePreviewJwt(jwt: string): Promise<SitePreviewParams | null> {
if (!process.env.SITE_PREVIEW_SECRET) {
throw new Error("SITE_PREVIEW_SECRET environment variable is required.");
}
const data = await jwtVerify<SitePreviewParams>(jwt, new TextEncoder().encode(process.env.SITE_PREVIEW_SECRET));
return data.payload;
try {
const data = await jwtVerify<SitePreviewParams>(jwt, new TextEncoder().encode(process.env.SITE_PREVIEW_SECRET));
return data.payload;
} catch (e) {
if (e instanceof errors.JOSEError) return null;
throw e;
}
}
Original file line number Diff line number Diff line change
@@ -1,21 +1,33 @@
import "server-only";

import { SignJWT } from "jose";
import { cookies, draftMode } from "next/headers";
import { redirect } from "next/navigation";
import type { NextRequest } from "next/server";
import { NextRequest, NextResponse } from "next/server";

import { SitePreviewParams, verifySitePreviewJwt } from "../SitePreviewUtils";

export async function sitePreviewRoute(request: NextRequest, _graphQLFetch: unknown /* deprecated: remove argument in v8 */) {
const params = request.nextUrl.searchParams;
const jwt = params.get("jwt");
if (!jwt) {
throw new Error("Missing jwt parameter");
return NextResponse.json({ error: "JWT-Parameter is missing." }, { status: 400 });
}

const data = await verifySitePreviewJwt(jwt);
if (!data) {
return NextResponse.json({ error: "JWT-validation failed." }, { status: 400 });
}

cookies().set("__comet_preview", jwt);
const cookieJwt = await new SignJWT({
scope: data.scope,
path: data.path,
previewData: data.previewData,
})
.setProtectedHeader({ alg: "HS256" })
.setExpirationTime("1 day")
.sign(new TextEncoder().encode(process.env.SITE_PREVIEW_SECRET));
cookies().set("__comet_preview", cookieJwt, { httpOnly: true, sameSite: "lax" });

draftMode().enable();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,13 @@ async function legacyPagesRouterSitePreviewApiHandler(
const jwt = params.jwt;

if (typeof jwt !== "string") {
throw new Error("Missing jwt parameter");
return res.status(400).json({ error: "JWT-Parameter is missing." });
}

const data = await verifySitePreviewJwt(jwt);
if (!data) {
return res.status(400).json({ error: "JWT-validation failed." });
}

res.setPreviewData(data);
res.redirect(data.path);
Expand Down

0 comments on commit 9b7b3f1

Please sign in to comment.