Skip to content

feat(clerk-js,ui,shared): Add Safari ITP decorateUrl workaround to setActive - #7623

Merged
nikosdouvlis merged 10 commits into
mainfrom
nikos/safari-itp
Jan 29, 2026
Merged

feat(clerk-js,ui,shared): Add Safari ITP decorateUrl workaround to setActive#7623
nikosdouvlis merged 10 commits into
mainfrom
nikos/safari-itp

Conversation

@nikosdouvlis

@nikosdouvlisnikosdouvlis commented Jan 20, 2026

Copy link
Copy Markdown
Member

Description

Why:
Safari's Intelligent Tracking Prevention (ITP) caps cookies set via fetch/XHR
to 7 days. When users switched from redirectUrl to the navigate callback pattern,
the existing ITP workaround (via /v1/client/touch endpoint) stopped working
because the touch endpoint logic only ran in the redirectUrl branch.

What changed:

  • Added decorateUrl function to the navigate callback that wraps URLs with the
    touch endpoint when Safari ITP fix is needed (client.isEligibleForTouch())
  • Updated SetActiveNavigate type signature to include decorateUrl parameter
  • Added dev-mode warning when decorateUrl is not called but ITP fix is needed
  • Updated all internal usages in SignIn, SignUp, and SessionTasks components
    to pass decorateUrl through navigateOnSetActive

Context:
The decorateUrl may return an external URL (https://...) when ITP fix is needed,
requiring window.location.href instead of client-side navigation. This pattern
is documented in the type definitions.

Checklist

  • pnpm test runs as expected.
  • pnpm build runs as expected.
  • (If applicable) JSDoc comments have been added or updated for any package exports
  • (If applicable) Documentation has been updated

Type of change

  • 🐛 Bug fix
  • 🌟 New feature
  • 🔨 Breaking change
  • 📖 Refactoring / dependency upgrade / documentation
  • other:

Summary by CodeRabbit

  • New Features

    • Post-auth URL decoration: navigate callbacks now receive a decorateUrl(url) to wrap destinations. Decorated external URLs may trigger full-page navigation to refresh session cookies for Safari ITP.
  • Tests

    • New integration tests covering Safari ITP cookie-refresh and touch-based navigation flows.
    • Added unit tests verifying decorateUrl behavior and navigation wrapping across sign-in and set-active flows.

✏️ Tip: You can customize this high-level summary in your review settings.

…ack for Safari ITP fix
Why:
Safari's Intelligent Tracking Prevention (ITP) caps cookies set via fetch/XHR
to 7 days. When users switched from redirectUrl to the navigate callback pattern,
the existing ITP workaround (via /v1/client/touch endpoint) stopped working
because the touch endpoint logic only ran in the redirectUrl branch.
What changed:
- Added decorateUrl function to the navigate callback that wraps URLs with the
touch endpoint when Safari ITP fix is needed (client.isEligibleForTouch())
- Updated SetActiveNavigate type signature to include decorateUrl parameter
- Added dev-mode warning when decorateUrl is not called but ITP fix is needed
- Updated all internal usages in SignIn, SignUp, and SessionTasks components
to pass decorateUrl through navigateOnSetActive
Context:
The decorateUrl may return an external URL (https://...) when ITP fix is needed,
requiring window.location.href instead of client-side navigation. This pattern
is documented in the type definitions.
Why:
The Safari ITP fix (decorateUrl in setActive) was added without integration
test coverage. These tests ensure the touch endpoint navigation works correctly
when the client cookie is close to expiration.
What changed:
- Added 4 tests covering the Safari ITP workaround flow
- Tests verify touch endpoint is called when cookie expires within 8 days
- Tests verify decorateUrl behavior with mocked isEligibleForTouch
@changeset-bot

changeset-botBot commented Jan 20, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 32bf70a

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 20 packages
NameType
@clerk/clerk-jsMinor
@clerk/sharedMinor
@clerk/uiMinor
@clerk/chrome-extensionPatch
@clerk/expoPatch
@clerk/agent-toolkitPatch
@clerk/astroPatch
@clerk/backendPatch
@clerk/expo-passkeysPatch
@clerk/expressPatch
@clerk/fastifyPatch
@clerk/localizationsPatch
@clerk/mswPatch
@clerk/nextjsPatch
@clerk/nuxtPatch
@clerk/react-routerPatch
@clerk/reactPatch
@clerk/tanstack-react-startPatch
@clerk/testingPatch
@clerk/vuePatch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel

vercelBot commented Jan 20, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentReviewUpdated (UTC)
clerk-js-sandboxReadyReadyPreview, CommentJan 29, 2026 2:33pm

Request Review

@coderabbitai

coderabbitaiBot commented Jan 20, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Adds a DecorateUrl callback to the setActive navigation flow and exports a DecorateUrl type. Propagates decorateUrl through core clerk logic, shared types, SignIn/SignUp/SessionTasks contexts, and numerous UI components so navigation handlers receive it. At runtime, decorateUrl may wrap redirect URLs to route eligible navigations through the /v1/client/touch endpoint (used for Safari ITP cookie refresh) and can trigger full-page navigation when the decorated URL is absolute. Includes unit tests for decorateUrl behavior and a Playwright integration test suite covering Safari ITP scenarios.

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 20.00% which is insufficient. The required threshold is 80.00%.Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe PR title accurately describes the main change: adding Safari ITP decorateUrl workaround to setActive. It is specific, concise, and clearly summarizes the primary objective.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

@pkg-pr-new

pkg-pr-newBot commented Jan 20, 2026

Copy link
Copy Markdown

Open in StackBlitz

@clerk/agent-toolkit

npm i https://pkg.pr.new/@clerk/agent-toolkit@7623

@clerk/astro

npm i https://pkg.pr.new/@clerk/astro@7623

@clerk/backend

npm i https://pkg.pr.new/@clerk/backend@7623

@clerk/chrome-extension

npm i https://pkg.pr.new/@clerk/chrome-extension@7623

@clerk/clerk-js

npm i https://pkg.pr.new/@clerk/clerk-js@7623

@clerk/dev-cli

npm i https://pkg.pr.new/@clerk/dev-cli@7623

@clerk/expo

npm i https://pkg.pr.new/@clerk/expo@7623

@clerk/expo-passkeys

npm i https://pkg.pr.new/@clerk/expo-passkeys@7623

@clerk/express

npm i https://pkg.pr.new/@clerk/express@7623

@clerk/fastify

npm i https://pkg.pr.new/@clerk/fastify@7623

@clerk/localizations

npm i https://pkg.pr.new/@clerk/localizations@7623

@clerk/nextjs

npm i https://pkg.pr.new/@clerk/nextjs@7623

@clerk/nuxt

npm i https://pkg.pr.new/@clerk/nuxt@7623

@clerk/react

npm i https://pkg.pr.new/@clerk/react@7623

@clerk/react-router

npm i https://pkg.pr.new/@clerk/react-router@7623

@clerk/shared

npm i https://pkg.pr.new/@clerk/shared@7623

@clerk/tanstack-react-start

npm i https://pkg.pr.new/@clerk/tanstack-react-start@7623

@clerk/testing

npm i https://pkg.pr.new/@clerk/testing@7623

@clerk/ui

npm i https://pkg.pr.new/@clerk/ui@7623

@clerk/upgrade

npm i https://pkg.pr.new/@clerk/upgrade@7623

@clerk/vue

npm i https://pkg.pr.new/@clerk/vue@7623

commit: 32bf70a

@brkalowbrkalow left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Implementation looks good! Does the warning fire reliably? I suppose yes, we're mostly safe because Clerk doesn't unmount / get cleaned up on navigations, unless it's a full navigation.

'Clerk: The navigate callback in setActive() did not call decorateUrl(). ' +
'In Safari, sessions may be limited to 7 days due to Intelligent Tracking Prevention (ITP). ' +
'Use decorateUrl() to wrap your destination URL to enable the ITP workaround. ' +
'Learn more: https://clerk.com/docs/troubleshooting/safari-itp',

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.

🙃 this link leads to 404

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

fixed the link and opened clerk/clerk-docs#3013, thanks Alex!

# Conflicts:
#	packages/ui/src/components/SignIn/handleCombinedFlowTransfer.ts
Why:
The previous check `decoratedUrl.startsWith('https://')` incorrectly triggered full page navigation for any absolute https:// redirect URL, even when decorateUrl didn't modify it. This caused unnecessary full page navigations in non-ITP scenarios.
What changed:
Now checks if decorateUrl actually modified the URL (`decoratedUrl !== redirectUrl`) AND that the result is an absolute http/https URL. This ensures full page navigation only happens when Safari ITP decoration is applied.
The buildTouchUrl mock wasn't URL-encoding the redirect URL, but the test
expected %2Fdashboard in the result. The real implementation uses fapiClient
which handles encoding, so the mock should too.
The setActive mock was calling navigate({ session }) but the actual code
now expects navigate({ session, decorateUrl }). Added a mock decorateUrl
function to fix the test.
The route pattern '**/v1/client?**' required a query string to match,
so it was missing client fetches without query params. Changed to
'**/v1/client**' and added explicit skip for touch endpoint to avoid
intercepting that separately.
…sponses
Intercepting /v1/client responses breaks JWT signature validation since
we can't re-sign the handshake token. The decorateUrl functionality is
still tested in the remaining tests which call setActive directly after
successful sign-in.
@nikosdouvlis
nikosdouvlis merged commit 1fc95e2 into mainJan 29, 2026
40 checks passed
@nikosdouvlis
nikosdouvlis deleted the nikos/safari-itp branch January 29, 2026 14:47
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@nikosdouvlis@alexcarpenter@brkalow@bratsos
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
feat(clerk-js,ui,shared): Add Safari ITP `decorateUrl` workaround to setActive by nikosdouvlis · Pull Request #7623 · clerk/javascript · GitHub
Skip to content

feat(clerk-js,ui,shared): Add Safari ITP decorateUrl workaround to setActive - #7623

Merged
nikosdouvlis merged 10 commits into
mainfrom
nikos/safari-itp
Jan 29, 2026
Merged

feat(clerk-js,ui,shared): Add Safari ITP decorateUrl workaround to setActive#7623
nikosdouvlis merged 10 commits into
mainfrom
nikos/safari-itp

Conversation

@nikosdouvlis

@nikosdouvlisnikosdouvlis commented Jan 20, 2026

Copy link
Copy Markdown
Member

Description

Why:
Safari's Intelligent Tracking Prevention (ITP) caps cookies set via fetch/XHR
to 7 days. When users switched from redirectUrl to the navigate callback pattern,
the existing ITP workaround (via /v1/client/touch endpoint) stopped working
because the touch endpoint logic only ran in the redirectUrl branch.

What changed:

  • Added decorateUrl function to the navigate callback that wraps URLs with the
    touch endpoint when Safari ITP fix is needed (client.isEligibleForTouch())
  • Updated SetActiveNavigate type signature to include decorateUrl parameter
  • Added dev-mode warning when decorateUrl is not called but ITP fix is needed
  • Updated all internal usages in SignIn, SignUp, and SessionTasks components
    to pass decorateUrl through navigateOnSetActive

Context:
The decorateUrl may return an external URL (https://...) when ITP fix is needed,
requiring window.location.href instead of client-side navigation. This pattern
is documented in the type definitions.

Checklist

  • pnpm test runs as expected.
  • pnpm build runs as expected.
  • (If applicable) JSDoc comments have been added or updated for any package exports
  • (If applicable) Documentation has been updated

Type of change

  • 🐛 Bug fix
  • 🌟 New feature
  • 🔨 Breaking change
  • 📖 Refactoring / dependency upgrade / documentation
  • other:

Summary by CodeRabbit

  • New Features

    • Post-auth URL decoration: navigate callbacks now receive a decorateUrl(url) to wrap destinations. Decorated external URLs may trigger full-page navigation to refresh session cookies for Safari ITP.
  • Tests

    • New integration tests covering Safari ITP cookie-refresh and touch-based navigation flows.
    • Added unit tests verifying decorateUrl behavior and navigation wrapping across sign-in and set-active flows.

✏️ Tip: You can customize this high-level summary in your review settings.

…ack for Safari ITP fix
Why:
Safari's Intelligent Tracking Prevention (ITP) caps cookies set via fetch/XHR
to 7 days. When users switched from redirectUrl to the navigate callback pattern,
the existing ITP workaround (via /v1/client/touch endpoint) stopped working
because the touch endpoint logic only ran in the redirectUrl branch.
What changed:
- Added decorateUrl function to the navigate callback that wraps URLs with the
touch endpoint when Safari ITP fix is needed (client.isEligibleForTouch())
- Updated SetActiveNavigate type signature to include decorateUrl parameter
- Added dev-mode warning when decorateUrl is not called but ITP fix is needed
- Updated all internal usages in SignIn, SignUp, and SessionTasks components
to pass decorateUrl through navigateOnSetActive
Context:
The decorateUrl may return an external URL (https://...) when ITP fix is needed,
requiring window.location.href instead of client-side navigation. This pattern
is documented in the type definitions.
Why:
The Safari ITP fix (decorateUrl in setActive) was added without integration
test coverage. These tests ensure the touch endpoint navigation works correctly
when the client cookie is close to expiration.
What changed:
- Added 4 tests covering the Safari ITP workaround flow
- Tests verify touch endpoint is called when cookie expires within 8 days
- Tests verify decorateUrl behavior with mocked isEligibleForTouch
@changeset-bot

changeset-botBot commented Jan 20, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 32bf70a

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 20 packages
NameType
@clerk/clerk-jsMinor
@clerk/sharedMinor
@clerk/uiMinor
@clerk/chrome-extensionPatch
@clerk/expoPatch
@clerk/agent-toolkitPatch
@clerk/astroPatch
@clerk/backendPatch
@clerk/expo-passkeysPatch
@clerk/expressPatch
@clerk/fastifyPatch
@clerk/localizationsPatch
@clerk/mswPatch
@clerk/nextjsPatch
@clerk/nuxtPatch
@clerk/react-routerPatch
@clerk/reactPatch
@clerk/tanstack-react-startPatch
@clerk/testingPatch
@clerk/vuePatch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel

vercelBot commented Jan 20, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentReviewUpdated (UTC)
clerk-js-sandboxReadyReadyPreview, CommentJan 29, 2026 2:33pm

Request Review

@coderabbitai

coderabbitaiBot commented Jan 20, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Adds a DecorateUrl callback to the setActive navigation flow and exports a DecorateUrl type. Propagates decorateUrl through core clerk logic, shared types, SignIn/SignUp/SessionTasks contexts, and numerous UI components so navigation handlers receive it. At runtime, decorateUrl may wrap redirect URLs to route eligible navigations through the /v1/client/touch endpoint (used for Safari ITP cookie refresh) and can trigger full-page navigation when the decorated URL is absolute. Includes unit tests for decorateUrl behavior and a Playwright integration test suite covering Safari ITP scenarios.

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 20.00% which is insufficient. The required threshold is 80.00%.Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe PR title accurately describes the main change: adding Safari ITP decorateUrl workaround to setActive. It is specific, concise, and clearly summarizes the primary objective.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

@pkg-pr-new

pkg-pr-newBot commented Jan 20, 2026

Copy link
Copy Markdown

Open in StackBlitz

@clerk/agent-toolkit

npm i https://pkg.pr.new/@clerk/agent-toolkit@7623

@clerk/astro

npm i https://pkg.pr.new/@clerk/astro@7623

@clerk/backend

npm i https://pkg.pr.new/@clerk/backend@7623

@clerk/chrome-extension

npm i https://pkg.pr.new/@clerk/chrome-extension@7623

@clerk/clerk-js

npm i https://pkg.pr.new/@clerk/clerk-js@7623

@clerk/dev-cli

npm i https://pkg.pr.new/@clerk/dev-cli@7623

@clerk/expo

npm i https://pkg.pr.new/@clerk/expo@7623

@clerk/expo-passkeys

npm i https://pkg.pr.new/@clerk/expo-passkeys@7623

@clerk/express

npm i https://pkg.pr.new/@clerk/express@7623

@clerk/fastify

npm i https://pkg.pr.new/@clerk/fastify@7623

@clerk/localizations

npm i https://pkg.pr.new/@clerk/localizations@7623

@clerk/nextjs

npm i https://pkg.pr.new/@clerk/nextjs@7623

@clerk/nuxt

npm i https://pkg.pr.new/@clerk/nuxt@7623

@clerk/react

npm i https://pkg.pr.new/@clerk/react@7623

@clerk/react-router

npm i https://pkg.pr.new/@clerk/react-router@7623

@clerk/shared

npm i https://pkg.pr.new/@clerk/shared@7623

@clerk/tanstack-react-start

npm i https://pkg.pr.new/@clerk/tanstack-react-start@7623

@clerk/testing

npm i https://pkg.pr.new/@clerk/testing@7623

@clerk/ui

npm i https://pkg.pr.new/@clerk/ui@7623

@clerk/upgrade

npm i https://pkg.pr.new/@clerk/upgrade@7623

@clerk/vue

npm i https://pkg.pr.new/@clerk/vue@7623

commit: 32bf70a

@brkalowbrkalow left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Implementation looks good! Does the warning fire reliably? I suppose yes, we're mostly safe because Clerk doesn't unmount / get cleaned up on navigations, unless it's a full navigation.

'Clerk: The navigate callback in setActive() did not call decorateUrl(). ' +
'In Safari, sessions may be limited to 7 days due to Intelligent Tracking Prevention (ITP). ' +
'Use decorateUrl() to wrap your destination URL to enable the ITP workaround. ' +
'Learn more: https://clerk.com/docs/troubleshooting/safari-itp',

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.

🙃 this link leads to 404

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

fixed the link and opened clerk/clerk-docs#3013, thanks Alex!

# Conflicts:
#	packages/ui/src/components/SignIn/handleCombinedFlowTransfer.ts
Why:
The previous check `decoratedUrl.startsWith('https://')` incorrectly triggered full page navigation for any absolute https:// redirect URL, even when decorateUrl didn't modify it. This caused unnecessary full page navigations in non-ITP scenarios.
What changed:
Now checks if decorateUrl actually modified the URL (`decoratedUrl !== redirectUrl`) AND that the result is an absolute http/https URL. This ensures full page navigation only happens when Safari ITP decoration is applied.
The buildTouchUrl mock wasn't URL-encoding the redirect URL, but the test
expected %2Fdashboard in the result. The real implementation uses fapiClient
which handles encoding, so the mock should too.
The setActive mock was calling navigate({ session }) but the actual code
now expects navigate({ session, decorateUrl }). Added a mock decorateUrl
function to fix the test.
The route pattern '**/v1/client?**' required a query string to match,
so it was missing client fetches without query params. Changed to
'**/v1/client**' and added explicit skip for touch endpoint to avoid
intercepting that separately.
…sponses
Intercepting /v1/client responses breaks JWT signature validation since
we can't re-sign the handshake token. The decorateUrl functionality is
still tested in the remaining tests which call setActive directly after
successful sign-in.
@nikosdouvlis
nikosdouvlis merged commit 1fc95e2 into mainJan 29, 2026
40 checks passed
@nikosdouvlis
nikosdouvlis deleted the nikos/safari-itp branch January 29, 2026 14:47
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@nikosdouvlis@alexcarpenter@brkalow@bratsos
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' feat(clerk-js,ui,shared): Add Safari ITP `decorateUrl` workaround to setActive by nikosdouvlis · Pull Request #7623 · clerk/javascript · GitHub
Skip to content

feat(clerk-js,ui,shared): Add Safari ITP decorateUrl workaround to setActive - #7623

Merged
nikosdouvlis merged 10 commits into
mainfrom
nikos/safari-itp
Jan 29, 2026
Merged

feat(clerk-js,ui,shared): Add Safari ITP decorateUrl workaround to setActive#7623
nikosdouvlis merged 10 commits into
mainfrom
nikos/safari-itp

Conversation

@nikosdouvlis

@nikosdouvlisnikosdouvlis commented Jan 20, 2026

Copy link
Copy Markdown
Member

Description

Why:
Safari's Intelligent Tracking Prevention (ITP) caps cookies set via fetch/XHR
to 7 days. When users switched from redirectUrl to the navigate callback pattern,
the existing ITP workaround (via /v1/client/touch endpoint) stopped working
because the touch endpoint logic only ran in the redirectUrl branch.

What changed:

  • Added decorateUrl function to the navigate callback that wraps URLs with the
    touch endpoint when Safari ITP fix is needed (client.isEligibleForTouch())
  • Updated SetActiveNavigate type signature to include decorateUrl parameter
  • Added dev-mode warning when decorateUrl is not called but ITP fix is needed
  • Updated all internal usages in SignIn, SignUp, and SessionTasks components
    to pass decorateUrl through navigateOnSetActive

Context:
The decorateUrl may return an external URL (https://...) when ITP fix is needed,
requiring window.location.href instead of client-side navigation. This pattern
is documented in the type definitions.

Checklist

  • pnpm test runs as expected.
  • pnpm build runs as expected.
  • (If applicable) JSDoc comments have been added or updated for any package exports
  • (If applicable) Documentation has been updated

Type of change

  • 🐛 Bug fix
  • 🌟 New feature
  • 🔨 Breaking change
  • 📖 Refactoring / dependency upgrade / documentation
  • other:

Summary by CodeRabbit

  • New Features

    • Post-auth URL decoration: navigate callbacks now receive a decorateUrl(url) to wrap destinations. Decorated external URLs may trigger full-page navigation to refresh session cookies for Safari ITP.
  • Tests

    • New integration tests covering Safari ITP cookie-refresh and touch-based navigation flows.
    • Added unit tests verifying decorateUrl behavior and navigation wrapping across sign-in and set-active flows.

✏️ Tip: You can customize this high-level summary in your review settings.

…ack for Safari ITP fix
Why:
Safari's Intelligent Tracking Prevention (ITP) caps cookies set via fetch/XHR
to 7 days. When users switched from redirectUrl to the navigate callback pattern,
the existing ITP workaround (via /v1/client/touch endpoint) stopped working
because the touch endpoint logic only ran in the redirectUrl branch.
What changed:
- Added decorateUrl function to the navigate callback that wraps URLs with the
touch endpoint when Safari ITP fix is needed (client.isEligibleForTouch())
- Updated SetActiveNavigate type signature to include decorateUrl parameter
- Added dev-mode warning when decorateUrl is not called but ITP fix is needed
- Updated all internal usages in SignIn, SignUp, and SessionTasks components
to pass decorateUrl through navigateOnSetActive
Context:
The decorateUrl may return an external URL (https://...) when ITP fix is needed,
requiring window.location.href instead of client-side navigation. This pattern
is documented in the type definitions.
Why:
The Safari ITP fix (decorateUrl in setActive) was added without integration
test coverage. These tests ensure the touch endpoint navigation works correctly
when the client cookie is close to expiration.
What changed:
- Added 4 tests covering the Safari ITP workaround flow
- Tests verify touch endpoint is called when cookie expires within 8 days
- Tests verify decorateUrl behavior with mocked isEligibleForTouch
@changeset-bot

changeset-botBot commented Jan 20, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 32bf70a

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 20 packages
NameType
@clerk/clerk-jsMinor
@clerk/sharedMinor
@clerk/uiMinor
@clerk/chrome-extensionPatch
@clerk/expoPatch
@clerk/agent-toolkitPatch
@clerk/astroPatch
@clerk/backendPatch
@clerk/expo-passkeysPatch
@clerk/expressPatch
@clerk/fastifyPatch
@clerk/localizationsPatch
@clerk/mswPatch
@clerk/nextjsPatch
@clerk/nuxtPatch
@clerk/react-routerPatch
@clerk/reactPatch
@clerk/tanstack-react-startPatch
@clerk/testingPatch
@clerk/vuePatch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel

vercelBot commented Jan 20, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentReviewUpdated (UTC)
clerk-js-sandboxReadyReadyPreview, CommentJan 29, 2026 2:33pm

Request Review

@coderabbitai

coderabbitaiBot commented Jan 20, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Adds a DecorateUrl callback to the setActive navigation flow and exports a DecorateUrl type. Propagates decorateUrl through core clerk logic, shared types, SignIn/SignUp/SessionTasks contexts, and numerous UI components so navigation handlers receive it. At runtime, decorateUrl may wrap redirect URLs to route eligible navigations through the /v1/client/touch endpoint (used for Safari ITP cookie refresh) and can trigger full-page navigation when the decorated URL is absolute. Includes unit tests for decorateUrl behavior and a Playwright integration test suite covering Safari ITP scenarios.

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 20.00% which is insufficient. The required threshold is 80.00%.Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe PR title accurately describes the main change: adding Safari ITP decorateUrl workaround to setActive. It is specific, concise, and clearly summarizes the primary objective.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

@pkg-pr-new

pkg-pr-newBot commented Jan 20, 2026

Copy link
Copy Markdown

Open in StackBlitz

@clerk/agent-toolkit

npm i https://pkg.pr.new/@clerk/agent-toolkit@7623

@clerk/astro

npm i https://pkg.pr.new/@clerk/astro@7623

@clerk/backend

npm i https://pkg.pr.new/@clerk/backend@7623

@clerk/chrome-extension

npm i https://pkg.pr.new/@clerk/chrome-extension@7623

@clerk/clerk-js

npm i https://pkg.pr.new/@clerk/clerk-js@7623

@clerk/dev-cli

npm i https://pkg.pr.new/@clerk/dev-cli@7623

@clerk/expo

npm i https://pkg.pr.new/@clerk/expo@7623

@clerk/expo-passkeys

npm i https://pkg.pr.new/@clerk/expo-passkeys@7623

@clerk/express

npm i https://pkg.pr.new/@clerk/express@7623

@clerk/fastify

npm i https://pkg.pr.new/@clerk/fastify@7623

@clerk/localizations

npm i https://pkg.pr.new/@clerk/localizations@7623

@clerk/nextjs

npm i https://pkg.pr.new/@clerk/nextjs@7623

@clerk/nuxt

npm i https://pkg.pr.new/@clerk/nuxt@7623

@clerk/react

npm i https://pkg.pr.new/@clerk/react@7623

@clerk/react-router

npm i https://pkg.pr.new/@clerk/react-router@7623

@clerk/shared

npm i https://pkg.pr.new/@clerk/shared@7623

@clerk/tanstack-react-start

npm i https://pkg.pr.new/@clerk/tanstack-react-start@7623

@clerk/testing

npm i https://pkg.pr.new/@clerk/testing@7623

@clerk/ui

npm i https://pkg.pr.new/@clerk/ui@7623

@clerk/upgrade

npm i https://pkg.pr.new/@clerk/upgrade@7623

@clerk/vue

npm i https://pkg.pr.new/@clerk/vue@7623

commit: 32bf70a

@brkalowbrkalow left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Implementation looks good! Does the warning fire reliably? I suppose yes, we're mostly safe because Clerk doesn't unmount / get cleaned up on navigations, unless it's a full navigation.

'Clerk: The navigate callback in setActive() did not call decorateUrl(). ' +
'In Safari, sessions may be limited to 7 days due to Intelligent Tracking Prevention (ITP). ' +
'Use decorateUrl() to wrap your destination URL to enable the ITP workaround. ' +
'Learn more: https://clerk.com/docs/troubleshooting/safari-itp',

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.

🙃 this link leads to 404

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

fixed the link and opened clerk/clerk-docs#3013, thanks Alex!

# Conflicts:
#	packages/ui/src/components/SignIn/handleCombinedFlowTransfer.ts
Why:
The previous check `decoratedUrl.startsWith('https://')` incorrectly triggered full page navigation for any absolute https:// redirect URL, even when decorateUrl didn't modify it. This caused unnecessary full page navigations in non-ITP scenarios.
What changed:
Now checks if decorateUrl actually modified the URL (`decoratedUrl !== redirectUrl`) AND that the result is an absolute http/https URL. This ensures full page navigation only happens when Safari ITP decoration is applied.
The buildTouchUrl mock wasn't URL-encoding the redirect URL, but the test
expected %2Fdashboard in the result. The real implementation uses fapiClient
which handles encoding, so the mock should too.
The setActive mock was calling navigate({ session }) but the actual code
now expects navigate({ session, decorateUrl }). Added a mock decorateUrl
function to fix the test.
The route pattern '**/v1/client?**' required a query string to match,
so it was missing client fetches without query params. Changed to
'**/v1/client**' and added explicit skip for touch endpoint to avoid
intercepting that separately.
…sponses
Intercepting /v1/client responses breaks JWT signature validation since
we can't re-sign the handshake token. The decorateUrl functionality is
still tested in the remaining tests which call setActive directly after
successful sign-in.
@nikosdouvlis
nikosdouvlis merged commit 1fc95e2 into mainJan 29, 2026
40 checks passed
@nikosdouvlis
nikosdouvlis deleted the nikos/safari-itp branch January 29, 2026 14:47
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@nikosdouvlis@alexcarpenter@brkalow@bratsos
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' feat(clerk-js,ui,shared): Add Safari ITP `decorateUrl` workaround to setActive by nikosdouvlis · Pull Request #7623 · clerk/javascript · GitHub
Skip to content

feat(clerk-js,ui,shared): Add Safari ITP decorateUrl workaround to setActive - #7623

Merged
nikosdouvlis merged 10 commits into
mainfrom
nikos/safari-itp
Jan 29, 2026
Merged

feat(clerk-js,ui,shared): Add Safari ITP decorateUrl workaround to setActive#7623
nikosdouvlis merged 10 commits into
mainfrom
nikos/safari-itp

Conversation

@nikosdouvlis

@nikosdouvlisnikosdouvlis commented Jan 20, 2026

Copy link
Copy Markdown
Member

Description

Why:
Safari's Intelligent Tracking Prevention (ITP) caps cookies set via fetch/XHR
to 7 days. When users switched from redirectUrl to the navigate callback pattern,
the existing ITP workaround (via /v1/client/touch endpoint) stopped working
because the touch endpoint logic only ran in the redirectUrl branch.

What changed:

  • Added decorateUrl function to the navigate callback that wraps URLs with the
    touch endpoint when Safari ITP fix is needed (client.isEligibleForTouch())
  • Updated SetActiveNavigate type signature to include decorateUrl parameter
  • Added dev-mode warning when decorateUrl is not called but ITP fix is needed
  • Updated all internal usages in SignIn, SignUp, and SessionTasks components
    to pass decorateUrl through navigateOnSetActive

Context:
The decorateUrl may return an external URL (https://...) when ITP fix is needed,
requiring window.location.href instead of client-side navigation. This pattern
is documented in the type definitions.

Checklist

  • pnpm test runs as expected.
  • pnpm build runs as expected.
  • (If applicable) JSDoc comments have been added or updated for any package exports
  • (If applicable) Documentation has been updated

Type of change

  • 🐛 Bug fix
  • 🌟 New feature
  • 🔨 Breaking change
  • 📖 Refactoring / dependency upgrade / documentation
  • other:

Summary by CodeRabbit

  • New Features

    • Post-auth URL decoration: navigate callbacks now receive a decorateUrl(url) to wrap destinations. Decorated external URLs may trigger full-page navigation to refresh session cookies for Safari ITP.
  • Tests

    • New integration tests covering Safari ITP cookie-refresh and touch-based navigation flows.
    • Added unit tests verifying decorateUrl behavior and navigation wrapping across sign-in and set-active flows.

✏️ Tip: You can customize this high-level summary in your review settings.

…ack for Safari ITP fix
Why:
Safari's Intelligent Tracking Prevention (ITP) caps cookies set via fetch/XHR
to 7 days. When users switched from redirectUrl to the navigate callback pattern,
the existing ITP workaround (via /v1/client/touch endpoint) stopped working
because the touch endpoint logic only ran in the redirectUrl branch.
What changed:
- Added decorateUrl function to the navigate callback that wraps URLs with the
touch endpoint when Safari ITP fix is needed (client.isEligibleForTouch())
- Updated SetActiveNavigate type signature to include decorateUrl parameter
- Added dev-mode warning when decorateUrl is not called but ITP fix is needed
- Updated all internal usages in SignIn, SignUp, and SessionTasks components
to pass decorateUrl through navigateOnSetActive
Context:
The decorateUrl may return an external URL (https://...) when ITP fix is needed,
requiring window.location.href instead of client-side navigation. This pattern
is documented in the type definitions.
Why:
The Safari ITP fix (decorateUrl in setActive) was added without integration
test coverage. These tests ensure the touch endpoint navigation works correctly
when the client cookie is close to expiration.
What changed:
- Added 4 tests covering the Safari ITP workaround flow
- Tests verify touch endpoint is called when cookie expires within 8 days
- Tests verify decorateUrl behavior with mocked isEligibleForTouch
@changeset-bot

changeset-botBot commented Jan 20, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 32bf70a

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 20 packages
NameType
@clerk/clerk-jsMinor
@clerk/sharedMinor
@clerk/uiMinor
@clerk/chrome-extensionPatch
@clerk/expoPatch
@clerk/agent-toolkitPatch
@clerk/astroPatch
@clerk/backendPatch
@clerk/expo-passkeysPatch
@clerk/expressPatch
@clerk/fastifyPatch
@clerk/localizationsPatch
@clerk/mswPatch
@clerk/nextjsPatch
@clerk/nuxtPatch
@clerk/react-routerPatch
@clerk/reactPatch
@clerk/tanstack-react-startPatch
@clerk/testingPatch
@clerk/vuePatch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel

vercelBot commented Jan 20, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentReviewUpdated (UTC)
clerk-js-sandboxReadyReadyPreview, CommentJan 29, 2026 2:33pm

Request Review

@coderabbitai

coderabbitaiBot commented Jan 20, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Adds a DecorateUrl callback to the setActive navigation flow and exports a DecorateUrl type. Propagates decorateUrl through core clerk logic, shared types, SignIn/SignUp/SessionTasks contexts, and numerous UI components so navigation handlers receive it. At runtime, decorateUrl may wrap redirect URLs to route eligible navigations through the /v1/client/touch endpoint (used for Safari ITP cookie refresh) and can trigger full-page navigation when the decorated URL is absolute. Includes unit tests for decorateUrl behavior and a Playwright integration test suite covering Safari ITP scenarios.

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 20.00% which is insufficient. The required threshold is 80.00%.Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe PR title accurately describes the main change: adding Safari ITP decorateUrl workaround to setActive. It is specific, concise, and clearly summarizes the primary objective.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

@pkg-pr-new

pkg-pr-newBot commented Jan 20, 2026

Copy link
Copy Markdown

Open in StackBlitz

@clerk/agent-toolkit

npm i https://pkg.pr.new/@clerk/agent-toolkit@7623

@clerk/astro

npm i https://pkg.pr.new/@clerk/astro@7623

@clerk/backend

npm i https://pkg.pr.new/@clerk/backend@7623

@clerk/chrome-extension

npm i https://pkg.pr.new/@clerk/chrome-extension@7623

@clerk/clerk-js

npm i https://pkg.pr.new/@clerk/clerk-js@7623

@clerk/dev-cli

npm i https://pkg.pr.new/@clerk/dev-cli@7623

@clerk/expo

npm i https://pkg.pr.new/@clerk/expo@7623

@clerk/expo-passkeys

npm i https://pkg.pr.new/@clerk/expo-passkeys@7623

@clerk/express

npm i https://pkg.pr.new/@clerk/express@7623

@clerk/fastify

npm i https://pkg.pr.new/@clerk/fastify@7623

@clerk/localizations

npm i https://pkg.pr.new/@clerk/localizations@7623

@clerk/nextjs

npm i https://pkg.pr.new/@clerk/nextjs@7623

@clerk/nuxt

npm i https://pkg.pr.new/@clerk/nuxt@7623

@clerk/react

npm i https://pkg.pr.new/@clerk/react@7623

@clerk/react-router

npm i https://pkg.pr.new/@clerk/react-router@7623

@clerk/shared

npm i https://pkg.pr.new/@clerk/shared@7623

@clerk/tanstack-react-start

npm i https://pkg.pr.new/@clerk/tanstack-react-start@7623

@clerk/testing

npm i https://pkg.pr.new/@clerk/testing@7623

@clerk/ui

npm i https://pkg.pr.new/@clerk/ui@7623

@clerk/upgrade

npm i https://pkg.pr.new/@clerk/upgrade@7623

@clerk/vue

npm i https://pkg.pr.new/@clerk/vue@7623

commit: 32bf70a

@brkalowbrkalow left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Implementation looks good! Does the warning fire reliably? I suppose yes, we're mostly safe because Clerk doesn't unmount / get cleaned up on navigations, unless it's a full navigation.

'Clerk: The navigate callback in setActive() did not call decorateUrl(). ' +
'In Safari, sessions may be limited to 7 days due to Intelligent Tracking Prevention (ITP). ' +
'Use decorateUrl() to wrap your destination URL to enable the ITP workaround. ' +
'Learn more: https://clerk.com/docs/troubleshooting/safari-itp',

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.

🙃 this link leads to 404

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

fixed the link and opened clerk/clerk-docs#3013, thanks Alex!

# Conflicts:
#	packages/ui/src/components/SignIn/handleCombinedFlowTransfer.ts
Why:
The previous check `decoratedUrl.startsWith('https://')` incorrectly triggered full page navigation for any absolute https:// redirect URL, even when decorateUrl didn't modify it. This caused unnecessary full page navigations in non-ITP scenarios.
What changed:
Now checks if decorateUrl actually modified the URL (`decoratedUrl !== redirectUrl`) AND that the result is an absolute http/https URL. This ensures full page navigation only happens when Safari ITP decoration is applied.
The buildTouchUrl mock wasn't URL-encoding the redirect URL, but the test
expected %2Fdashboard in the result. The real implementation uses fapiClient
which handles encoding, so the mock should too.
The setActive mock was calling navigate({ session }) but the actual code
now expects navigate({ session, decorateUrl }). Added a mock decorateUrl
function to fix the test.
The route pattern '**/v1/client?**' required a query string to match,
so it was missing client fetches without query params. Changed to
'**/v1/client**' and added explicit skip for touch endpoint to avoid
intercepting that separately.
…sponses
Intercepting /v1/client responses breaks JWT signature validation since
we can't re-sign the handshake token. The decorateUrl functionality is
still tested in the remaining tests which call setActive directly after
successful sign-in.
@nikosdouvlis
nikosdouvlis merged commit 1fc95e2 into mainJan 29, 2026
40 checks passed
@nikosdouvlis
nikosdouvlis deleted the nikos/safari-itp branch January 29, 2026 14:47
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@nikosdouvlis@alexcarpenter@brkalow@bratsos
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' feat(clerk-js,ui,shared): Add Safari ITP `decorateUrl` workaround to setActive by nikosdouvlis · Pull Request #7623 · clerk/javascript · GitHub
Skip to content

feat(clerk-js,ui,shared): Add Safari ITP decorateUrl workaround to setActive - #7623

Merged
nikosdouvlis merged 10 commits into
mainfrom
nikos/safari-itp
Jan 29, 2026
Merged

feat(clerk-js,ui,shared): Add Safari ITP decorateUrl workaround to setActive#7623
nikosdouvlis merged 10 commits into
mainfrom
nikos/safari-itp

Conversation

@nikosdouvlis

@nikosdouvlisnikosdouvlis commented Jan 20, 2026

Copy link
Copy Markdown
Member

Description

Why:
Safari's Intelligent Tracking Prevention (ITP) caps cookies set via fetch/XHR
to 7 days. When users switched from redirectUrl to the navigate callback pattern,
the existing ITP workaround (via /v1/client/touch endpoint) stopped working
because the touch endpoint logic only ran in the redirectUrl branch.

What changed:

  • Added decorateUrl function to the navigate callback that wraps URLs with the
    touch endpoint when Safari ITP fix is needed (client.isEligibleForTouch())
  • Updated SetActiveNavigate type signature to include decorateUrl parameter
  • Added dev-mode warning when decorateUrl is not called but ITP fix is needed
  • Updated all internal usages in SignIn, SignUp, and SessionTasks components
    to pass decorateUrl through navigateOnSetActive

Context:
The decorateUrl may return an external URL (https://...) when ITP fix is needed,
requiring window.location.href instead of client-side navigation. This pattern
is documented in the type definitions.

Checklist

  • pnpm test runs as expected.
  • pnpm build runs as expected.
  • (If applicable) JSDoc comments have been added or updated for any package exports
  • (If applicable) Documentation has been updated

Type of change

  • 🐛 Bug fix
  • 🌟 New feature
  • 🔨 Breaking change
  • 📖 Refactoring / dependency upgrade / documentation
  • other:

Summary by CodeRabbit

  • New Features

    • Post-auth URL decoration: navigate callbacks now receive a decorateUrl(url) to wrap destinations. Decorated external URLs may trigger full-page navigation to refresh session cookies for Safari ITP.
  • Tests

    • New integration tests covering Safari ITP cookie-refresh and touch-based navigation flows.
    • Added unit tests verifying decorateUrl behavior and navigation wrapping across sign-in and set-active flows.

✏️ Tip: You can customize this high-level summary in your review settings.

…ack for Safari ITP fix
Why:
Safari's Intelligent Tracking Prevention (ITP) caps cookies set via fetch/XHR
to 7 days. When users switched from redirectUrl to the navigate callback pattern,
the existing ITP workaround (via /v1/client/touch endpoint) stopped working
because the touch endpoint logic only ran in the redirectUrl branch.
What changed:
- Added decorateUrl function to the navigate callback that wraps URLs with the
touch endpoint when Safari ITP fix is needed (client.isEligibleForTouch())
- Updated SetActiveNavigate type signature to include decorateUrl parameter
- Added dev-mode warning when decorateUrl is not called but ITP fix is needed
- Updated all internal usages in SignIn, SignUp, and SessionTasks components
to pass decorateUrl through navigateOnSetActive
Context:
The decorateUrl may return an external URL (https://...) when ITP fix is needed,
requiring window.location.href instead of client-side navigation. This pattern
is documented in the type definitions.
Why:
The Safari ITP fix (decorateUrl in setActive) was added without integration
test coverage. These tests ensure the touch endpoint navigation works correctly
when the client cookie is close to expiration.
What changed:
- Added 4 tests covering the Safari ITP workaround flow
- Tests verify touch endpoint is called when cookie expires within 8 days
- Tests verify decorateUrl behavior with mocked isEligibleForTouch
@changeset-bot

changeset-botBot commented Jan 20, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 32bf70a

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 20 packages
NameType
@clerk/clerk-jsMinor
@clerk/sharedMinor
@clerk/uiMinor
@clerk/chrome-extensionPatch
@clerk/expoPatch
@clerk/agent-toolkitPatch
@clerk/astroPatch
@clerk/backendPatch
@clerk/expo-passkeysPatch
@clerk/expressPatch
@clerk/fastifyPatch
@clerk/localizationsPatch
@clerk/mswPatch
@clerk/nextjsPatch
@clerk/nuxtPatch
@clerk/react-routerPatch
@clerk/reactPatch
@clerk/tanstack-react-startPatch
@clerk/testingPatch
@clerk/vuePatch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel

vercelBot commented Jan 20, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentReviewUpdated (UTC)
clerk-js-sandboxReadyReadyPreview, CommentJan 29, 2026 2:33pm

Request Review

@coderabbitai

coderabbitaiBot commented Jan 20, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Adds a DecorateUrl callback to the setActive navigation flow and exports a DecorateUrl type. Propagates decorateUrl through core clerk logic, shared types, SignIn/SignUp/SessionTasks contexts, and numerous UI components so navigation handlers receive it. At runtime, decorateUrl may wrap redirect URLs to route eligible navigations through the /v1/client/touch endpoint (used for Safari ITP cookie refresh) and can trigger full-page navigation when the decorated URL is absolute. Includes unit tests for decorateUrl behavior and a Playwright integration test suite covering Safari ITP scenarios.

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 20.00% which is insufficient. The required threshold is 80.00%.Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe PR title accurately describes the main change: adding Safari ITP decorateUrl workaround to setActive. It is specific, concise, and clearly summarizes the primary objective.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

@pkg-pr-new

pkg-pr-newBot commented Jan 20, 2026

Copy link
Copy Markdown

Open in StackBlitz

@clerk/agent-toolkit

npm i https://pkg.pr.new/@clerk/agent-toolkit@7623

@clerk/astro

npm i https://pkg.pr.new/@clerk/astro@7623

@clerk/backend

npm i https://pkg.pr.new/@clerk/backend@7623

@clerk/chrome-extension

npm i https://pkg.pr.new/@clerk/chrome-extension@7623

@clerk/clerk-js

npm i https://pkg.pr.new/@clerk/clerk-js@7623

@clerk/dev-cli

npm i https://pkg.pr.new/@clerk/dev-cli@7623

@clerk/expo

npm i https://pkg.pr.new/@clerk/expo@7623

@clerk/expo-passkeys

npm i https://pkg.pr.new/@clerk/expo-passkeys@7623

@clerk/express

npm i https://pkg.pr.new/@clerk/express@7623

@clerk/fastify

npm i https://pkg.pr.new/@clerk/fastify@7623

@clerk/localizations

npm i https://pkg.pr.new/@clerk/localizations@7623

@clerk/nextjs

npm i https://pkg.pr.new/@clerk/nextjs@7623

@clerk/nuxt

npm i https://pkg.pr.new/@clerk/nuxt@7623

@clerk/react

npm i https://pkg.pr.new/@clerk/react@7623

@clerk/react-router

npm i https://pkg.pr.new/@clerk/react-router@7623

@clerk/shared

npm i https://pkg.pr.new/@clerk/shared@7623

@clerk/tanstack-react-start

npm i https://pkg.pr.new/@clerk/tanstack-react-start@7623

@clerk/testing

npm i https://pkg.pr.new/@clerk/testing@7623

@clerk/ui

npm i https://pkg.pr.new/@clerk/ui@7623

@clerk/upgrade

npm i https://pkg.pr.new/@clerk/upgrade@7623

@clerk/vue

npm i https://pkg.pr.new/@clerk/vue@7623

commit: 32bf70a

@brkalowbrkalow left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Implementation looks good! Does the warning fire reliably? I suppose yes, we're mostly safe because Clerk doesn't unmount / get cleaned up on navigations, unless it's a full navigation.

'Clerk: The navigate callback in setActive() did not call decorateUrl(). ' +
'In Safari, sessions may be limited to 7 days due to Intelligent Tracking Prevention (ITP). ' +
'Use decorateUrl() to wrap your destination URL to enable the ITP workaround. ' +
'Learn more: https://clerk.com/docs/troubleshooting/safari-itp',

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.

🙃 this link leads to 404

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

fixed the link and opened clerk/clerk-docs#3013, thanks Alex!

# Conflicts:
#	packages/ui/src/components/SignIn/handleCombinedFlowTransfer.ts
Why:
The previous check `decoratedUrl.startsWith('https://')` incorrectly triggered full page navigation for any absolute https:// redirect URL, even when decorateUrl didn't modify it. This caused unnecessary full page navigations in non-ITP scenarios.
What changed:
Now checks if decorateUrl actually modified the URL (`decoratedUrl !== redirectUrl`) AND that the result is an absolute http/https URL. This ensures full page navigation only happens when Safari ITP decoration is applied.
The buildTouchUrl mock wasn't URL-encoding the redirect URL, but the test
expected %2Fdashboard in the result. The real implementation uses fapiClient
which handles encoding, so the mock should too.
The setActive mock was calling navigate({ session }) but the actual code
now expects navigate({ session, decorateUrl }). Added a mock decorateUrl
function to fix the test.
The route pattern '**/v1/client?**' required a query string to match,
so it was missing client fetches without query params. Changed to
'**/v1/client**' and added explicit skip for touch endpoint to avoid
intercepting that separately.
…sponses
Intercepting /v1/client responses breaks JWT signature validation since
we can't re-sign the handshake token. The decorateUrl functionality is
still tested in the remaining tests which call setActive directly after
successful sign-in.
@nikosdouvlis
nikosdouvlis merged commit 1fc95e2 into mainJan 29, 2026
40 checks passed
@nikosdouvlis
nikosdouvlis deleted the nikos/safari-itp branch January 29, 2026 14:47
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@nikosdouvlis@alexcarpenter@brkalow@bratsos
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' feat(clerk-js,ui,shared): Add Safari ITP `decorateUrl` workaround to setActive by nikosdouvlis · Pull Request #7623 · clerk/javascript · GitHub
Skip to content

feat(clerk-js,ui,shared): Add Safari ITP decorateUrl workaround to setActive - #7623

Merged
nikosdouvlis merged 10 commits into
mainfrom
nikos/safari-itp
Jan 29, 2026
Merged

feat(clerk-js,ui,shared): Add Safari ITP decorateUrl workaround to setActive#7623
nikosdouvlis merged 10 commits into
mainfrom
nikos/safari-itp

Conversation

@nikosdouvlis

@nikosdouvlisnikosdouvlis commented Jan 20, 2026

Copy link
Copy Markdown
Member

Description

Why:
Safari's Intelligent Tracking Prevention (ITP) caps cookies set via fetch/XHR
to 7 days. When users switched from redirectUrl to the navigate callback pattern,
the existing ITP workaround (via /v1/client/touch endpoint) stopped working
because the touch endpoint logic only ran in the redirectUrl branch.

What changed:

  • Added decorateUrl function to the navigate callback that wraps URLs with the
    touch endpoint when Safari ITP fix is needed (client.isEligibleForTouch())
  • Updated SetActiveNavigate type signature to include decorateUrl parameter
  • Added dev-mode warning when decorateUrl is not called but ITP fix is needed
  • Updated all internal usages in SignIn, SignUp, and SessionTasks components
    to pass decorateUrl through navigateOnSetActive

Context:
The decorateUrl may return an external URL (https://...) when ITP fix is needed,
requiring window.location.href instead of client-side navigation. This pattern
is documented in the type definitions.

Checklist

  • pnpm test runs as expected.
  • pnpm build runs as expected.
  • (If applicable) JSDoc comments have been added or updated for any package exports
  • (If applicable) Documentation has been updated

Type of change

  • 🐛 Bug fix
  • 🌟 New feature
  • 🔨 Breaking change
  • 📖 Refactoring / dependency upgrade / documentation
  • other:

Summary by CodeRabbit

  • New Features

    • Post-auth URL decoration: navigate callbacks now receive a decorateUrl(url) to wrap destinations. Decorated external URLs may trigger full-page navigation to refresh session cookies for Safari ITP.
  • Tests

    • New integration tests covering Safari ITP cookie-refresh and touch-based navigation flows.
    • Added unit tests verifying decorateUrl behavior and navigation wrapping across sign-in and set-active flows.

✏️ Tip: You can customize this high-level summary in your review settings.

…ack for Safari ITP fix
Why:
Safari's Intelligent Tracking Prevention (ITP) caps cookies set via fetch/XHR
to 7 days. When users switched from redirectUrl to the navigate callback pattern,
the existing ITP workaround (via /v1/client/touch endpoint) stopped working
because the touch endpoint logic only ran in the redirectUrl branch.
What changed:
- Added decorateUrl function to the navigate callback that wraps URLs with the
touch endpoint when Safari ITP fix is needed (client.isEligibleForTouch())
- Updated SetActiveNavigate type signature to include decorateUrl parameter
- Added dev-mode warning when decorateUrl is not called but ITP fix is needed
- Updated all internal usages in SignIn, SignUp, and SessionTasks components
to pass decorateUrl through navigateOnSetActive
Context:
The decorateUrl may return an external URL (https://...) when ITP fix is needed,
requiring window.location.href instead of client-side navigation. This pattern
is documented in the type definitions.
Why:
The Safari ITP fix (decorateUrl in setActive) was added without integration
test coverage. These tests ensure the touch endpoint navigation works correctly
when the client cookie is close to expiration.
What changed:
- Added 4 tests covering the Safari ITP workaround flow
- Tests verify touch endpoint is called when cookie expires within 8 days
- Tests verify decorateUrl behavior with mocked isEligibleForTouch
@changeset-bot

changeset-botBot commented Jan 20, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 32bf70a

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 20 packages
NameType
@clerk/clerk-jsMinor
@clerk/sharedMinor
@clerk/uiMinor
@clerk/chrome-extensionPatch
@clerk/expoPatch
@clerk/agent-toolkitPatch
@clerk/astroPatch
@clerk/backendPatch
@clerk/expo-passkeysPatch
@clerk/expressPatch
@clerk/fastifyPatch
@clerk/localizationsPatch
@clerk/mswPatch
@clerk/nextjsPatch
@clerk/nuxtPatch
@clerk/react-routerPatch
@clerk/reactPatch
@clerk/tanstack-react-startPatch
@clerk/testingPatch
@clerk/vuePatch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel

vercelBot commented Jan 20, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentReviewUpdated (UTC)
clerk-js-sandboxReadyReadyPreview, CommentJan 29, 2026 2:33pm

Request Review

@coderabbitai

coderabbitaiBot commented Jan 20, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Adds a DecorateUrl callback to the setActive navigation flow and exports a DecorateUrl type. Propagates decorateUrl through core clerk logic, shared types, SignIn/SignUp/SessionTasks contexts, and numerous UI components so navigation handlers receive it. At runtime, decorateUrl may wrap redirect URLs to route eligible navigations through the /v1/client/touch endpoint (used for Safari ITP cookie refresh) and can trigger full-page navigation when the decorated URL is absolute. Includes unit tests for decorateUrl behavior and a Playwright integration test suite covering Safari ITP scenarios.

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 20.00% which is insufficient. The required threshold is 80.00%.Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe PR title accurately describes the main change: adding Safari ITP decorateUrl workaround to setActive. It is specific, concise, and clearly summarizes the primary objective.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

@pkg-pr-new

pkg-pr-newBot commented Jan 20, 2026

Copy link
Copy Markdown

Open in StackBlitz

@clerk/agent-toolkit

npm i https://pkg.pr.new/@clerk/agent-toolkit@7623

@clerk/astro

npm i https://pkg.pr.new/@clerk/astro@7623

@clerk/backend

npm i https://pkg.pr.new/@clerk/backend@7623

@clerk/chrome-extension

npm i https://pkg.pr.new/@clerk/chrome-extension@7623

@clerk/clerk-js

npm i https://pkg.pr.new/@clerk/clerk-js@7623

@clerk/dev-cli

npm i https://pkg.pr.new/@clerk/dev-cli@7623

@clerk/expo

npm i https://pkg.pr.new/@clerk/expo@7623

@clerk/expo-passkeys

npm i https://pkg.pr.new/@clerk/expo-passkeys@7623

@clerk/express

npm i https://pkg.pr.new/@clerk/express@7623

@clerk/fastify

npm i https://pkg.pr.new/@clerk/fastify@7623

@clerk/localizations

npm i https://pkg.pr.new/@clerk/localizations@7623

@clerk/nextjs

npm i https://pkg.pr.new/@clerk/nextjs@7623

@clerk/nuxt

npm i https://pkg.pr.new/@clerk/nuxt@7623

@clerk/react

npm i https://pkg.pr.new/@clerk/react@7623

@clerk/react-router

npm i https://pkg.pr.new/@clerk/react-router@7623

@clerk/shared

npm i https://pkg.pr.new/@clerk/shared@7623

@clerk/tanstack-react-start

npm i https://pkg.pr.new/@clerk/tanstack-react-start@7623

@clerk/testing

npm i https://pkg.pr.new/@clerk/testing@7623

@clerk/ui

npm i https://pkg.pr.new/@clerk/ui@7623

@clerk/upgrade

npm i https://pkg.pr.new/@clerk/upgrade@7623

@clerk/vue

npm i https://pkg.pr.new/@clerk/vue@7623

commit: 32bf70a

@brkalowbrkalow left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Implementation looks good! Does the warning fire reliably? I suppose yes, we're mostly safe because Clerk doesn't unmount / get cleaned up on navigations, unless it's a full navigation.

'Clerk: The navigate callback in setActive() did not call decorateUrl(). ' +
'In Safari, sessions may be limited to 7 days due to Intelligent Tracking Prevention (ITP). ' +
'Use decorateUrl() to wrap your destination URL to enable the ITP workaround. ' +
'Learn more: https://clerk.com/docs/troubleshooting/safari-itp',

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.

🙃 this link leads to 404

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

fixed the link and opened clerk/clerk-docs#3013, thanks Alex!

# Conflicts:
#	packages/ui/src/components/SignIn/handleCombinedFlowTransfer.ts
Why:
The previous check `decoratedUrl.startsWith('https://')` incorrectly triggered full page navigation for any absolute https:// redirect URL, even when decorateUrl didn't modify it. This caused unnecessary full page navigations in non-ITP scenarios.
What changed:
Now checks if decorateUrl actually modified the URL (`decoratedUrl !== redirectUrl`) AND that the result is an absolute http/https URL. This ensures full page navigation only happens when Safari ITP decoration is applied.
The buildTouchUrl mock wasn't URL-encoding the redirect URL, but the test
expected %2Fdashboard in the result. The real implementation uses fapiClient
which handles encoding, so the mock should too.
The setActive mock was calling navigate({ session }) but the actual code
now expects navigate({ session, decorateUrl }). Added a mock decorateUrl
function to fix the test.
The route pattern '**/v1/client?**' required a query string to match,
so it was missing client fetches without query params. Changed to
'**/v1/client**' and added explicit skip for touch endpoint to avoid
intercepting that separately.
…sponses
Intercepting /v1/client responses breaks JWT signature validation since
we can't re-sign the handshake token. The decorateUrl functionality is
still tested in the remaining tests which call setActive directly after
successful sign-in.
@nikosdouvlis
nikosdouvlis merged commit 1fc95e2 into mainJan 29, 2026
40 checks passed
@nikosdouvlis
nikosdouvlis deleted the nikos/safari-itp branch January 29, 2026 14:47
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@nikosdouvlis@alexcarpenter@brkalow@bratsos
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' feat(clerk-js,ui,shared): Add Safari ITP `decorateUrl` workaround to setActive by nikosdouvlis · Pull Request #7623 · clerk/javascript · GitHub
Skip to content

feat(clerk-js,ui,shared): Add Safari ITP decorateUrl workaround to setActive - #7623

Merged
nikosdouvlis merged 10 commits into
mainfrom
nikos/safari-itp
Jan 29, 2026
Merged

feat(clerk-js,ui,shared): Add Safari ITP decorateUrl workaround to setActive#7623
nikosdouvlis merged 10 commits into
mainfrom
nikos/safari-itp

Conversation

@nikosdouvlis

@nikosdouvlisnikosdouvlis commented Jan 20, 2026

Copy link
Copy Markdown
Member

Description

Why:
Safari's Intelligent Tracking Prevention (ITP) caps cookies set via fetch/XHR
to 7 days. When users switched from redirectUrl to the navigate callback pattern,
the existing ITP workaround (via /v1/client/touch endpoint) stopped working
because the touch endpoint logic only ran in the redirectUrl branch.

What changed:

  • Added decorateUrl function to the navigate callback that wraps URLs with the
    touch endpoint when Safari ITP fix is needed (client.isEligibleForTouch())
  • Updated SetActiveNavigate type signature to include decorateUrl parameter
  • Added dev-mode warning when decorateUrl is not called but ITP fix is needed
  • Updated all internal usages in SignIn, SignUp, and SessionTasks components
    to pass decorateUrl through navigateOnSetActive

Context:
The decorateUrl may return an external URL (https://...) when ITP fix is needed,
requiring window.location.href instead of client-side navigation. This pattern
is documented in the type definitions.

Checklist

  • pnpm test runs as expected.
  • pnpm build runs as expected.
  • (If applicable) JSDoc comments have been added or updated for any package exports
  • (If applicable) Documentation has been updated

Type of change

  • 🐛 Bug fix
  • 🌟 New feature
  • 🔨 Breaking change
  • 📖 Refactoring / dependency upgrade / documentation
  • other:

Summary by CodeRabbit

  • New Features

    • Post-auth URL decoration: navigate callbacks now receive a decorateUrl(url) to wrap destinations. Decorated external URLs may trigger full-page navigation to refresh session cookies for Safari ITP.
  • Tests

    • New integration tests covering Safari ITP cookie-refresh and touch-based navigation flows.
    • Added unit tests verifying decorateUrl behavior and navigation wrapping across sign-in and set-active flows.

✏️ Tip: You can customize this high-level summary in your review settings.

…ack for Safari ITP fix
Why:
Safari's Intelligent Tracking Prevention (ITP) caps cookies set via fetch/XHR
to 7 days. When users switched from redirectUrl to the navigate callback pattern,
the existing ITP workaround (via /v1/client/touch endpoint) stopped working
because the touch endpoint logic only ran in the redirectUrl branch.
What changed:
- Added decorateUrl function to the navigate callback that wraps URLs with the
touch endpoint when Safari ITP fix is needed (client.isEligibleForTouch())
- Updated SetActiveNavigate type signature to include decorateUrl parameter
- Added dev-mode warning when decorateUrl is not called but ITP fix is needed
- Updated all internal usages in SignIn, SignUp, and SessionTasks components
to pass decorateUrl through navigateOnSetActive
Context:
The decorateUrl may return an external URL (https://...) when ITP fix is needed,
requiring window.location.href instead of client-side navigation. This pattern
is documented in the type definitions.
Why:
The Safari ITP fix (decorateUrl in setActive) was added without integration
test coverage. These tests ensure the touch endpoint navigation works correctly
when the client cookie is close to expiration.
What changed:
- Added 4 tests covering the Safari ITP workaround flow
- Tests verify touch endpoint is called when cookie expires within 8 days
- Tests verify decorateUrl behavior with mocked isEligibleForTouch
@changeset-bot

changeset-botBot commented Jan 20, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 32bf70a

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 20 packages
NameType
@clerk/clerk-jsMinor
@clerk/sharedMinor
@clerk/uiMinor
@clerk/chrome-extensionPatch
@clerk/expoPatch
@clerk/agent-toolkitPatch
@clerk/astroPatch
@clerk/backendPatch
@clerk/expo-passkeysPatch
@clerk/expressPatch
@clerk/fastifyPatch
@clerk/localizationsPatch
@clerk/mswPatch
@clerk/nextjsPatch
@clerk/nuxtPatch
@clerk/react-routerPatch
@clerk/reactPatch
@clerk/tanstack-react-startPatch
@clerk/testingPatch
@clerk/vuePatch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel

vercelBot commented Jan 20, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentReviewUpdated (UTC)
clerk-js-sandboxReadyReadyPreview, CommentJan 29, 2026 2:33pm

Request Review

@coderabbitai

coderabbitaiBot commented Jan 20, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Adds a DecorateUrl callback to the setActive navigation flow and exports a DecorateUrl type. Propagates decorateUrl through core clerk logic, shared types, SignIn/SignUp/SessionTasks contexts, and numerous UI components so navigation handlers receive it. At runtime, decorateUrl may wrap redirect URLs to route eligible navigations through the /v1/client/touch endpoint (used for Safari ITP cookie refresh) and can trigger full-page navigation when the decorated URL is absolute. Includes unit tests for decorateUrl behavior and a Playwright integration test suite covering Safari ITP scenarios.

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 20.00% which is insufficient. The required threshold is 80.00%.Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe PR title accurately describes the main change: adding Safari ITP decorateUrl workaround to setActive. It is specific, concise, and clearly summarizes the primary objective.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

@pkg-pr-new

pkg-pr-newBot commented Jan 20, 2026

Copy link
Copy Markdown

Open in StackBlitz

@clerk/agent-toolkit

npm i https://pkg.pr.new/@clerk/agent-toolkit@7623

@clerk/astro

npm i https://pkg.pr.new/@clerk/astro@7623

@clerk/backend

npm i https://pkg.pr.new/@clerk/backend@7623

@clerk/chrome-extension

npm i https://pkg.pr.new/@clerk/chrome-extension@7623

@clerk/clerk-js

npm i https://pkg.pr.new/@clerk/clerk-js@7623

@clerk/dev-cli

npm i https://pkg.pr.new/@clerk/dev-cli@7623

@clerk/expo

npm i https://pkg.pr.new/@clerk/expo@7623

@clerk/expo-passkeys

npm i https://pkg.pr.new/@clerk/expo-passkeys@7623

@clerk/express

npm i https://pkg.pr.new/@clerk/express@7623

@clerk/fastify

npm i https://pkg.pr.new/@clerk/fastify@7623

@clerk/localizations

npm i https://pkg.pr.new/@clerk/localizations@7623

@clerk/nextjs

npm i https://pkg.pr.new/@clerk/nextjs@7623

@clerk/nuxt

npm i https://pkg.pr.new/@clerk/nuxt@7623

@clerk/react

npm i https://pkg.pr.new/@clerk/react@7623

@clerk/react-router

npm i https://pkg.pr.new/@clerk/react-router@7623

@clerk/shared

npm i https://pkg.pr.new/@clerk/shared@7623

@clerk/tanstack-react-start

npm i https://pkg.pr.new/@clerk/tanstack-react-start@7623

@clerk/testing

npm i https://pkg.pr.new/@clerk/testing@7623

@clerk/ui

npm i https://pkg.pr.new/@clerk/ui@7623

@clerk/upgrade

npm i https://pkg.pr.new/@clerk/upgrade@7623

@clerk/vue

npm i https://pkg.pr.new/@clerk/vue@7623

commit: 32bf70a

@brkalowbrkalow left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Implementation looks good! Does the warning fire reliably? I suppose yes, we're mostly safe because Clerk doesn't unmount / get cleaned up on navigations, unless it's a full navigation.

'Clerk: The navigate callback in setActive() did not call decorateUrl(). ' +
'In Safari, sessions may be limited to 7 days due to Intelligent Tracking Prevention (ITP). ' +
'Use decorateUrl() to wrap your destination URL to enable the ITP workaround. ' +
'Learn more: https://clerk.com/docs/troubleshooting/safari-itp',

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.

🙃 this link leads to 404

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

fixed the link and opened clerk/clerk-docs#3013, thanks Alex!

# Conflicts:
#	packages/ui/src/components/SignIn/handleCombinedFlowTransfer.ts
Why:
The previous check `decoratedUrl.startsWith('https://')` incorrectly triggered full page navigation for any absolute https:// redirect URL, even when decorateUrl didn't modify it. This caused unnecessary full page navigations in non-ITP scenarios.
What changed:
Now checks if decorateUrl actually modified the URL (`decoratedUrl !== redirectUrl`) AND that the result is an absolute http/https URL. This ensures full page navigation only happens when Safari ITP decoration is applied.
The buildTouchUrl mock wasn't URL-encoding the redirect URL, but the test
expected %2Fdashboard in the result. The real implementation uses fapiClient
which handles encoding, so the mock should too.
The setActive mock was calling navigate({ session }) but the actual code
now expects navigate({ session, decorateUrl }). Added a mock decorateUrl
function to fix the test.
The route pattern '**/v1/client?**' required a query string to match,
so it was missing client fetches without query params. Changed to
'**/v1/client**' and added explicit skip for touch endpoint to avoid
intercepting that separately.
…sponses
Intercepting /v1/client responses breaks JWT signature validation since
we can't re-sign the handshake token. The decorateUrl functionality is
still tested in the remaining tests which call setActive directly after
successful sign-in.
@nikosdouvlis
nikosdouvlis merged commit 1fc95e2 into mainJan 29, 2026
40 checks passed
@nikosdouvlis
nikosdouvlis deleted the nikos/safari-itp branch January 29, 2026 14:47
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@nikosdouvlis@alexcarpenter@brkalow@bratsos
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); feat(clerk-js,ui,shared): Add Safari ITP `decorateUrl` workaround to setActive by nikosdouvlis · Pull Request #7623 · clerk/javascript · GitHub
Skip to content

feat(clerk-js,ui,shared): Add Safari ITP decorateUrl workaround to setActive - #7623

Merged
nikosdouvlis merged 10 commits into
mainfrom
nikos/safari-itp
Jan 29, 2026
Merged

feat(clerk-js,ui,shared): Add Safari ITP decorateUrl workaround to setActive#7623
nikosdouvlis merged 10 commits into
mainfrom
nikos/safari-itp

Conversation

@nikosdouvlis

@nikosdouvlisnikosdouvlis commented Jan 20, 2026

Copy link
Copy Markdown
Member

Description

Why:
Safari's Intelligent Tracking Prevention (ITP) caps cookies set via fetch/XHR
to 7 days. When users switched from redirectUrl to the navigate callback pattern,
the existing ITP workaround (via /v1/client/touch endpoint) stopped working
because the touch endpoint logic only ran in the redirectUrl branch.

What changed:

  • Added decorateUrl function to the navigate callback that wraps URLs with the
    touch endpoint when Safari ITP fix is needed (client.isEligibleForTouch())
  • Updated SetActiveNavigate type signature to include decorateUrl parameter
  • Added dev-mode warning when decorateUrl is not called but ITP fix is needed
  • Updated all internal usages in SignIn, SignUp, and SessionTasks components
    to pass decorateUrl through navigateOnSetActive

Context:
The decorateUrl may return an external URL (https://...) when ITP fix is needed,
requiring window.location.href instead of client-side navigation. This pattern
is documented in the type definitions.

Checklist

  • pnpm test runs as expected.
  • pnpm build runs as expected.
  • (If applicable) JSDoc comments have been added or updated for any package exports
  • (If applicable) Documentation has been updated

Type of change

  • 🐛 Bug fix
  • 🌟 New feature
  • 🔨 Breaking change
  • 📖 Refactoring / dependency upgrade / documentation
  • other:

Summary by CodeRabbit

  • New Features

    • Post-auth URL decoration: navigate callbacks now receive a decorateUrl(url) to wrap destinations. Decorated external URLs may trigger full-page navigation to refresh session cookies for Safari ITP.
  • Tests

    • New integration tests covering Safari ITP cookie-refresh and touch-based navigation flows.
    • Added unit tests verifying decorateUrl behavior and navigation wrapping across sign-in and set-active flows.

✏️ Tip: You can customize this high-level summary in your review settings.

…ack for Safari ITP fix
Why:
Safari's Intelligent Tracking Prevention (ITP) caps cookies set via fetch/XHR
to 7 days. When users switched from redirectUrl to the navigate callback pattern,
the existing ITP workaround (via /v1/client/touch endpoint) stopped working
because the touch endpoint logic only ran in the redirectUrl branch.
What changed:
- Added decorateUrl function to the navigate callback that wraps URLs with the
touch endpoint when Safari ITP fix is needed (client.isEligibleForTouch())
- Updated SetActiveNavigate type signature to include decorateUrl parameter
- Added dev-mode warning when decorateUrl is not called but ITP fix is needed
- Updated all internal usages in SignIn, SignUp, and SessionTasks components
to pass decorateUrl through navigateOnSetActive
Context:
The decorateUrl may return an external URL (https://...) when ITP fix is needed,
requiring window.location.href instead of client-side navigation. This pattern
is documented in the type definitions.
Why:
The Safari ITP fix (decorateUrl in setActive) was added without integration
test coverage. These tests ensure the touch endpoint navigation works correctly
when the client cookie is close to expiration.
What changed:
- Added 4 tests covering the Safari ITP workaround flow
- Tests verify touch endpoint is called when cookie expires within 8 days
- Tests verify decorateUrl behavior with mocked isEligibleForTouch
@changeset-bot

changeset-botBot commented Jan 20, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 32bf70a

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 20 packages
NameType
@clerk/clerk-jsMinor
@clerk/sharedMinor
@clerk/uiMinor
@clerk/chrome-extensionPatch
@clerk/expoPatch
@clerk/agent-toolkitPatch
@clerk/astroPatch
@clerk/backendPatch
@clerk/expo-passkeysPatch
@clerk/expressPatch
@clerk/fastifyPatch
@clerk/localizationsPatch
@clerk/mswPatch
@clerk/nextjsPatch
@clerk/nuxtPatch
@clerk/react-routerPatch
@clerk/reactPatch
@clerk/tanstack-react-startPatch
@clerk/testingPatch
@clerk/vuePatch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel

vercelBot commented Jan 20, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

ProjectDeploymentReviewUpdated (UTC)
clerk-js-sandboxReadyReadyPreview, CommentJan 29, 2026 2:33pm

Request Review

@coderabbitai

coderabbitaiBot commented Jan 20, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Adds a DecorateUrl callback to the setActive navigation flow and exports a DecorateUrl type. Propagates decorateUrl through core clerk logic, shared types, SignIn/SignUp/SessionTasks contexts, and numerous UI components so navigation handlers receive it. At runtime, decorateUrl may wrap redirect URLs to route eligible navigations through the /v1/client/touch endpoint (used for Safari ITP cookie refresh) and can trigger full-page navigation when the decorated URL is absolute. Includes unit tests for decorateUrl behavior and a Playwright integration test suite covering Safari ITP scenarios.

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 20.00% which is insufficient. The required threshold is 80.00%.Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe PR title accurately describes the main change: adding Safari ITP decorateUrl workaround to setActive. It is specific, concise, and clearly summarizes the primary objective.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

@pkg-pr-new

pkg-pr-newBot commented Jan 20, 2026

Copy link
Copy Markdown

Open in StackBlitz

@clerk/agent-toolkit

npm i https://pkg.pr.new/@clerk/agent-toolkit@7623

@clerk/astro

npm i https://pkg.pr.new/@clerk/astro@7623

@clerk/backend

npm i https://pkg.pr.new/@clerk/backend@7623

@clerk/chrome-extension

npm i https://pkg.pr.new/@clerk/chrome-extension@7623

@clerk/clerk-js

npm i https://pkg.pr.new/@clerk/clerk-js@7623

@clerk/dev-cli

npm i https://pkg.pr.new/@clerk/dev-cli@7623

@clerk/expo

npm i https://pkg.pr.new/@clerk/expo@7623

@clerk/expo-passkeys

npm i https://pkg.pr.new/@clerk/expo-passkeys@7623

@clerk/express

npm i https://pkg.pr.new/@clerk/express@7623

@clerk/fastify

npm i https://pkg.pr.new/@clerk/fastify@7623

@clerk/localizations

npm i https://pkg.pr.new/@clerk/localizations@7623

@clerk/nextjs

npm i https://pkg.pr.new/@clerk/nextjs@7623

@clerk/nuxt

npm i https://pkg.pr.new/@clerk/nuxt@7623

@clerk/react

npm i https://pkg.pr.new/@clerk/react@7623

@clerk/react-router

npm i https://pkg.pr.new/@clerk/react-router@7623

@clerk/shared

npm i https://pkg.pr.new/@clerk/shared@7623

@clerk/tanstack-react-start

npm i https://pkg.pr.new/@clerk/tanstack-react-start@7623

@clerk/testing

npm i https://pkg.pr.new/@clerk/testing@7623

@clerk/ui

npm i https://pkg.pr.new/@clerk/ui@7623

@clerk/upgrade

npm i https://pkg.pr.new/@clerk/upgrade@7623

@clerk/vue

npm i https://pkg.pr.new/@clerk/vue@7623

commit: 32bf70a

@brkalowbrkalow left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Implementation looks good! Does the warning fire reliably? I suppose yes, we're mostly safe because Clerk doesn't unmount / get cleaned up on navigations, unless it's a full navigation.

'Clerk: The navigate callback in setActive() did not call decorateUrl(). ' +
'In Safari, sessions may be limited to 7 days due to Intelligent Tracking Prevention (ITP). ' +
'Use decorateUrl() to wrap your destination URL to enable the ITP workaround. ' +
'Learn more: https://clerk.com/docs/troubleshooting/safari-itp',

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.

🙃 this link leads to 404

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

fixed the link and opened clerk/clerk-docs#3013, thanks Alex!

# Conflicts:
#	packages/ui/src/components/SignIn/handleCombinedFlowTransfer.ts
Why:
The previous check `decoratedUrl.startsWith('https://')` incorrectly triggered full page navigation for any absolute https:// redirect URL, even when decorateUrl didn't modify it. This caused unnecessary full page navigations in non-ITP scenarios.
What changed:
Now checks if decorateUrl actually modified the URL (`decoratedUrl !== redirectUrl`) AND that the result is an absolute http/https URL. This ensures full page navigation only happens when Safari ITP decoration is applied.
The buildTouchUrl mock wasn't URL-encoding the redirect URL, but the test
expected %2Fdashboard in the result. The real implementation uses fapiClient
which handles encoding, so the mock should too.
The setActive mock was calling navigate({ session }) but the actual code
now expects navigate({ session, decorateUrl }). Added a mock decorateUrl
function to fix the test.
The route pattern '**/v1/client?**' required a query string to match,
so it was missing client fetches without query params. Changed to
'**/v1/client**' and added explicit skip for touch endpoint to avoid
intercepting that separately.
…sponses
Intercepting /v1/client responses breaks JWT signature validation since
we can't re-sign the handshake token. The decorateUrl functionality is
still tested in the remaining tests which call setActive directly after
successful sign-in.
@nikosdouvlis
nikosdouvlis merged commit 1fc95e2 into mainJan 29, 2026
40 checks passed
@nikosdouvlis
nikosdouvlis deleted the nikos/safari-itp branch January 29, 2026 14:47
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@nikosdouvlis@alexcarpenter@brkalow@bratsos