Skip to content
Merged
6 changes: 6 additions & 0 deletions .changeset/poor-knives-laugh.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@clerk/backend': patch
'@clerk/nextjs': patch
---

Fixes a bug where Clerk's Handshake mechanism would not run when an application is rendered in an iframe.
3 changes: 2 additions & 1 deletion packages/backend/src/tokens/request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ function isRequestEligibleForHandshake(authenticateContext: { secFetchDest?: str
const { accept, secFetchDest } = authenticateContext;

// NOTE: we could also check sec-fetch-mode === navigate here, but according to the spec, sec-fetch-dest: document should indicate that the request is the data of a user navigation.
if (secFetchDest === 'document') {
// Also, we check for 'iframe' because it's the value set when a doc request is made by an iframe.
if (secFetchDest === 'document' || secFetchDest === 'iframe') {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ℹ️ When document requests happend from inside an iframe the Sec-Fetch-Dest value is set to iframe. Fetch/XHR requests do not use this value.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I propose exporting a SAFE_SEC_FETCH_DESTS array from shared and then consuming it in backend and nextjs, and just checking SAFE_SEC_FETCH_DESTS.includes(secFetchDest)

return true;
}

Expand Down
1 change: 1 addition & 0 deletions packages/nextjs/src/server/protect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ const isServerActionRequest = (req: Request) => {
const isPageRequest = (req: Request): boolean => {
return (
req.headers.get(constants.Headers.SecFetchDest) === 'document' ||
req.headers.get(constants.Headers.SecFetchDest) === 'iframe' ||

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❓ why do we need this as part of this PR? Is this related to the handshake mechanism?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe we need this in order for pages wrapped with protect work properly in the first load via an iframe

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not a handshake particular thing, but as @panteliselef said, it will help with protect and iframes.

req.headers.get(constants.Headers.Accept)?.includes('text/html') ||
isAppRouterInternalNavigation(req) ||
isPagesRouterInternalNavigation(req)
Expand Down