Skip to content

Commit c13bee6

Browse files
committed
feat(docs): add decorateUrl to navigate callbacks for Safari ITP support
Why: Safari's Intelligent Tracking Prevention (ITP) limits cookies set via API responses from CNAME-cloaked subdomains to 7 days. This causes unexpected session expiration for Safari users who don't visit frequently. The new decorateUrl function in setActive/finalize navigate callbacks enables automatic cookie refresh when needed. What changed: - Updated 25 doc files with decorateUrl pattern in navigate callbacks - Pattern wraps destination URLs and checks if result is absolute (http) to determine whether to use window.location.href or router.push() - Covers all custom flows: auth, legacy auth, Expo partials - Skipped billing checkout finalize() - different API, not affected Files: oauth-connections, sign-in-or-up, email-password, email-password-mfa, email-sms-otp, passkeys, enterprise-connections, legal-acceptance, embedded-email-links, multi-session-applications, session-tasks, error-handling, forgot-password, application-invitations, expo partials
1 parent af3823e commit c13bee6

25 files changed

+422
-115
lines changed

docs/_partials/expo/email-pass-sign-in.mdx

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,13 @@ export default function Page() {
2727

2828
if (signIn.status === 'complete') {
2929
await signIn.finalize({
30-
navigate: () => {
31-
router.push('/')
30+
navigate: ({ decorateUrl }) => {
31+
const url = decorateUrl('/')
32+
if (url.startsWith('http')) {
33+
window.location.href = url
34+
} else {
35+
router.push(url)
36+
}
3237
},
3338
})
3439
}
@@ -44,8 +49,13 @@ export default function Page() {
4449

4550
if (signIn.status === 'complete') {
4651
await signIn.finalize({
47-
navigate: () => {
48-
router.push('/')
52+
navigate: ({ decorateUrl }) => {
53+
const url = decorateUrl('/')
54+
if (url.startsWith('http')) {
55+
window.location.href = url
56+
} else {
57+
router.push(url)
58+
}
4959
},
5060
})
5161
}

docs/_partials/expo/email-pass-sign-up.mdx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,13 @@ export default function Page() {
3535

3636
if (signUp.status === 'complete') {
3737
await signUp.finalize({
38-
navigate: () => {
39-
router.push('/')
38+
navigate: ({ decorateUrl }) => {
39+
const url = decorateUrl('/')
40+
if (url.startsWith('http')) {
41+
window.location.href = url
42+
} else {
43+
router.push(url)
44+
}
4045
},
4146
})
4247
}

docs/guides/development/custom-flows/account-updates/forgot-password.mdx

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,15 +92,20 @@ This guide demonstrates how to use Clerk's API to build a custom flow for resett
9292
// the newly created session (user is now signed in)
9393
setActive({
9494
session: result.createdSessionId,
95-
navigate: async ({ session }) => {
95+
navigate: async ({ session, decorateUrl }) => {
9696
if (session?.currentTask) {
9797
// Check for tasks and navigate to custom UI to help users resolve them
9898
// See https://clerk.com/docs/guides/development/custom-flows/authentication/session-tasks
9999
console.log(session?.currentTask)
100100
return
101101
}
102102

103-
router.push('/')
103+
const url = decorateUrl('/')
104+
if (url.startsWith('http')) {
105+
window.location.href = url
106+
} else {
107+
router.push(url)
108+
}
104109
},
105110
})
106111
setError('')
@@ -502,15 +507,20 @@ In this case, you can prompt the user to reset their password using the exact sa
502507
// the newly created session (user is now signed in)
503508
setActive({
504509
session: result.createdSessionId,
505-
navigate: async ({ session }) => {
510+
navigate: async ({ session, decorateUrl }) => {
506511
if (session?.currentTask) {
507512
// Check for tasks and navigate to custom UI to help users resolve them
508513
// See https://clerk.com/docs/guides/development/custom-flows/authentication/session-tasks
509514
console.log(session?.currentTask)
510515
return
511516
}
512517

513-
router.push('/')
518+
const url = decorateUrl('/')
519+
if (url.startsWith('http')) {
520+
window.location.href = url
521+
} else {
522+
router.push(url)
523+
}
514524
},
515525
})
516526
setError('')

docs/guides/development/custom-flows/authentication/application-invitations.mdx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,13 @@ To create a sign-up flow using the invitation token, you need to call the [`sign
6060
})
6161
if (signUp.status === 'complete') {
6262
await signUp.finalize({
63-
navigate: () => {
64-
router.push('/')
63+
navigate: (decorateUrl) => {
64+
const url = decorateUrl('/')
65+
if (url.startsWith('http')) {
66+
window.location.href = url
67+
} else {
68+
router.push(url)
69+
}
6570
},
6671
})
6772
}

docs/guides/development/custom-flows/authentication/email-password-mfa.mdx

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,13 @@ This guide will walk you through how to build a custom email/password sign-in fl
8282
})
8383
if (signIn.status === 'complete') {
8484
await signIn.finalize({
85-
navigate: () => {
86-
router.push('/')
85+
navigate: (decorateUrl) => {
86+
const url = decorateUrl('/')
87+
if (url.startsWith('http')) {
88+
window.location.href = url
89+
} else {
90+
router.push(url)
91+
}
8792
},
8893
})
8994
}
@@ -101,8 +106,13 @@ This guide will walk you through how to build a custom email/password sign-in fl
101106

102107
if (signIn.status === 'complete') {
103108
await signIn.finalize({
104-
navigate: () => {
105-
router.push('/')
109+
navigate: (decorateUrl) => {
110+
const url = decorateUrl('/')
111+
if (url.startsWith('http')) {
112+
window.location.href = url
113+
} else {
114+
router.push(url)
115+
}
106116
},
107117
})
108118
}
@@ -204,8 +214,13 @@ This guide will walk you through how to build a custom email/password sign-in fl
204214

205215
if (signIn.status === 'complete') {
206216
await signIn.finalize({
207-
navigate: () => {
208-
router.push('/')
217+
navigate: (decorateUrl) => {
218+
const url = decorateUrl('/')
219+
if (url.startsWith('http')) {
220+
window.location.href = url
221+
} else {
222+
router.push(url)
223+
}
209224
},
210225
})
211226
}

docs/guides/development/custom-flows/authentication/email-password.mdx

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,13 @@ This guide will walk you through how to build a custom email/password sign-up an
7676
})
7777
if (signUp.status === 'complete') {
7878
await signUp.finalize({
79-
navigate: () => {
80-
router.push('/dashboard')
79+
navigate: (decorateUrl) => {
80+
const url = decorateUrl('/dashboard')
81+
if (url.startsWith('http')) {
82+
window.location.href = url
83+
} else {
84+
router.push(url)
85+
}
8186
},
8287
})
8388
}
@@ -395,8 +400,13 @@ This guide will walk you through how to build a custom email/password sign-up an
395400
})
396401
if (signIn.status === 'complete') {
397402
await signIn.finalize({
398-
navigate: () => {
399-
router.push('/')
403+
navigate: (decorateUrl) => {
404+
const url = decorateUrl('/')
405+
if (url.startsWith('http')) {
406+
window.location.href = url
407+
} else {
408+
router.push(url)
409+
}
400410
},
401411
})
402412
}
@@ -414,8 +424,13 @@ This guide will walk you through how to build a custom email/password sign-up an
414424

415425
if (signIn.status === 'complete') {
416426
await signIn.finalize({
417-
navigate: () => {
418-
router.push('/')
427+
navigate: (decorateUrl) => {
428+
const url = decorateUrl('/')
429+
if (url.startsWith('http')) {
430+
window.location.href = url
431+
} else {
432+
router.push(url)
433+
}
419434
},
420435
})
421436
}

docs/guides/development/custom-flows/authentication/email-sms-otp.mdx

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,13 @@ This guide will walk you through how to build a custom SMS OTP sign-up and sign-
7171
await signUp.verifications.verifyPhoneCode({ code })
7272
if (signUp.status === 'complete') {
7373
await signUp.finalize({
74-
navigate: () => {
75-
router.push('/dashboard')
74+
navigate: (decorateUrl) => {
75+
const url = decorateUrl('/dashboard')
76+
if (url.startsWith('http')) {
77+
window.location.href = url
78+
} else {
79+
router.push(url)
80+
}
7681
},
7782
})
7883
}
@@ -388,8 +393,13 @@ This guide will walk you through how to build a custom SMS OTP sign-up and sign-
388393
await signIn.phoneCode.verifyCode({ code })
389394
if (signIn.status === 'complete') {
390395
await signIn.finalize({
391-
navigate: () => {
392-
router.push('/')
396+
navigate: (decorateUrl) => {
397+
const url = decorateUrl('/')
398+
if (url.startsWith('http')) {
399+
window.location.href = url
400+
} else {
401+
router.push(url)
402+
}
393403
},
394404
})
395405
}

docs/guides/development/custom-flows/authentication/embedded-email-links.mdx

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -88,13 +88,18 @@ This guide will demonstrate how to generate a sign-in token and use it to sign i
8888
// If the sign-in was successful, set the session to active
8989
if (signIn.status === 'complete') {
9090
signIn.finalize({
91-
navigate: async ({ session }) => {
91+
navigate: async ({ session, decorateUrl }) => {
9292
if (session?.currentTask) {
9393
console.log(session?.currentTask)
9494
return
9595
}
9696

97-
router.push('/')
97+
const url = decorateUrl('/')
98+
if (url.startsWith('http')) {
99+
window.location.href = url
100+
} else {
101+
router.push(url)
102+
}
98103
},
99104
})
100105
} else {
@@ -170,13 +175,18 @@ This guide will demonstrate how to generate a sign-in token and use it to sign i
170175
// If the sign-in was successful, set the session to active
171176
if (signIn.status === 'complete') {
172177
signIn.finalize({
173-
navigate: async ({ session }) => {
178+
navigate: async ({ session, decorateUrl }) => {
174179
if (session?.currentTask) {
175180
console.log(session?.currentTask)
176181
return
177182
}
178183

179-
router.push('/')
184+
const url = decorateUrl('/')
185+
if (url.startsWith('http')) {
186+
window.location.href = url
187+
} else {
188+
router.push(url)
189+
}
180190
},
181191
})
182192
}

docs/guides/development/custom-flows/authentication/enterprise-connections.mdx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -118,15 +118,20 @@ You must configure your application instance through the Clerk Dashboard for the
118118
if (createdSessionId) {
119119
setActive!({
120120
session: createdSessionId,
121-
navigate: async ({ session }) => {
121+
navigate: async ({ session, decorateUrl }) => {
122122
if (session?.currentTask) {
123123
// Check for tasks and navigate to custom UI to help users resolve them
124124
// See https://clerk.com/docs/guides/development/custom-flows/authentication/session-tasks
125125
console.log(session?.currentTask)
126126
return
127127
}
128128

129-
router.push('/')
129+
const url = decorateUrl('/')
130+
if (url.startsWith('http')) {
131+
window.location.href = url
132+
} else {
133+
router.push(url)
134+
}
130135
},
131136
})
132137
} else {

docs/guides/development/custom-flows/authentication/legacy/application-invitations.mdx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -225,15 +225,20 @@ To create a sign-up flow using the invitation token, you need to extract the tok
225225
if (signUpAttempt.status === 'complete') {
226226
await clerk.setActive({
227227
session: signUpAttempt.createdSessionId,
228-
navigate: async ({ session }) => {
228+
navigate: async ({ session, decorateUrl }) => {
229229
if (session?.currentTask) {
230230
// Check for tasks and navigate to custom UI to help users resolve them
231231
// See https://clerk.com/docs/guides/development/custom-flows/authentication#session-tasks
232232
console.log(session?.currentTask)
233233
return
234234
}
235235

236-
await router.push('/')
236+
const url = decorateUrl('/')
237+
if (url.startsWith('http')) {
238+
window.location.href = url
239+
} else {
240+
window.location.href = '/'
241+
}
237242
},
238243
})
239244
} else {

0 commit comments

Comments
 (0)