feat: add Descope#7756
Conversation
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
|
Warning Review the following alerts detected in dependencies. According to your organization's Security Policy, it is recommended to resolve "Warn" alerts. Learn more about Socket for GitHub.
|
📝 WalkthroughWalkthroughThis PR adds a new TanStack Start React example ( ChangesDescope Example App
Estimated code review effort: 3 (Moderate) | ~30 minutes Sequence Diagram(s)sequenceDiagram
participant Browser
participant descopeMiddleware
participant resolveSessionFromRequest
participant DescopeClient
Browser->>descopeMiddleware: Request with session cookie
descopeMiddleware->>resolveSessionFromRequest: resolve session
resolveSessionFromRequest->>DescopeClient: validateAndRefreshSession(token)
DescopeClient-->>resolveSessionFromRequest: authInfo/claims
resolveSessionFromRequest-->>descopeMiddleware: SessionUser or null
descopeMiddleware-->>Browser: request continues with user context
sequenceDiagram
participant User
participant LoginRoute
participant DescopeWebComponent
participant Router
participant LogoutRoute
User->>LoginRoute: Visit /login
LoginRoute->>DescopeWebComponent: render sign-up-or-in flow
DescopeWebComponent-->>LoginRoute: onSuccess
LoginRoute->>Router: invalidate() and navigate to /
User->>LogoutRoute: Visit /logout
LogoutRoute->>DescopeWebComponent: sdk.logout()
LogoutRoute->>LogoutRoute: clearServerSession()
LogoutRoute->>Router: invalidate() and navigate to /
Possibly related PRs
Suggested labels: Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@examples/react/start-descope/.gitignore`:
- Around line 15-16: The .gitignore entry is malformed because the Sentry
comment is attached to the /public/build ignore pattern, so the pattern is not
applied correctly. Update the ignore rules in the .gitignore file for the react
start-descope example so /public/build stands alone and the Sentry Config File
note is placed on its own separate comment line before .env.sentry-build-plugin.
In `@examples/react/start-descope/package.json`:
- Around line 18-19: The dependency versions for `@tanstack/react-router` and
`@tanstack/react-router-devtools` are out of sync, which can lead to
incompatibilities. Update the `@tanstack/react-router-devtools` entry in
package.json to match the same minor version as `@tanstack/react-router`, and keep
the versions aligned so both packages resolve together consistently.
In `@examples/react/start-descope/src/integrations/descope/session.server.ts`:
- Around line 49-55: The rotated session cookie set in session.server.ts via the
SESSION_COOKIE write should be marked secure because it stores a JWT in a
browser cookie. Update the cookie options in the authInfo.jwt rotation path to
include the secure flag alongside the existing httpOnly, sameSite, and path
settings so it is only sent over HTTPS.
In `@examples/react/start-descope/src/routes/logout.tsx`:
- Around line 15-30: The logout flow in doLogout only catches errors from
sdk.logout(), so failures in clearServerSession(), router.invalidate(), or
router.navigate() can reject unhandled and leave the user stuck on the
signing-out screen. Wrap the post-logout cleanup/navigation steps in the same
try/catch (or a second one around the remaining awaits) and ensure errors are
logged while still allowing the UI to recover. Keep the existing
useEffect/doLogout structure, but make the full logout sequence resilient to any
thrown promise from clearServerSession, router.invalidate, and router.navigate.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 0352abff-733f-405d-86cc-fe8b4b73ce7a
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (30)
docs/start/config.jsondocs/start/framework/react/getting-started.mdexamples/react/start-descope/.devcontainer/devcontainer.jsonexamples/react/start-descope/.env.exampleexamples/react/start-descope/.gitignoreexamples/react/start-descope/.prettierignoreexamples/react/start-descope/.vscode/settings.jsonexamples/react/start-descope/README.mdexamples/react/start-descope/package.jsonexamples/react/start-descope/src/components/DefaultCatchBoundary.tsxexamples/react/start-descope/src/components/DescopeLogo.tsxexamples/react/start-descope/src/components/NotFound.tsxexamples/react/start-descope/src/integrations/descope/middleware.tsexamples/react/start-descope/src/integrations/descope/provider.tsxexamples/react/start-descope/src/integrations/descope/server.tsexamples/react/start-descope/src/integrations/descope/session.server.tsexamples/react/start-descope/src/routeTree.gen.tsexamples/react/start-descope/src/router.tsxexamples/react/start-descope/src/routes/__root.tsxexamples/react/start-descope/src/routes/_authed.tsxexamples/react/start-descope/src/routes/_authed/profile.tsxexamples/react/start-descope/src/routes/index.tsxexamples/react/start-descope/src/routes/login.tsxexamples/react/start-descope/src/routes/logout.tsxexamples/react/start-descope/src/start.tsexamples/react/start-descope/src/styles/app.cssexamples/react/start-descope/src/utils/seo.tsexamples/react/start-descope/tsconfig.jsonexamples/react/start-descope/vite.config.tspnpm-workspace.yaml
| /public/build# Sentry Config File | ||
| .env.sentry-build-plugin |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
Fix the malformed ignore entry.
/public/build# Sentry Config File is parsed as a literal pattern, so /public/build is never ignored. Put the comment on its own line.
Proposed fix
-/public/build# Sentry Config File
+/public/build
+# Sentry Config File📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| /public/build# Sentry Config File | |
| .env.sentry-build-plugin | |
| /public/build | |
| # Sentry Config File | |
| .env.sentry-build-plugin |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@examples/react/start-descope/.gitignore` around lines 15 - 16, The .gitignore
entry is malformed because the Sentry comment is attached to the /public/build
ignore pattern, so the pattern is not applied correctly. Update the ignore rules
in the .gitignore file for the react start-descope example so /public/build
stands alone and the Sentry Config File note is placed on its own separate
comment line before .env.sentry-build-plugin.
| "@tanstack/react-router": "^1.170.17", | ||
| "@tanstack/react-router-devtools": "^1.167.0", |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
Version mismatch between @tanstack/react-router and @tanstack/react-router-devtools.
@tanstack/react-router is at ^1.170.17 while @tanstack/react-router-devtools is at ^1.167.0. The devtools package should track the same minor version as the router to avoid API incompatibilities. With ^ ranges, the devtools could resolve to a version several minors behind the router.
🔧 Proposed fix
- "`@tanstack/react-router-devtools`": "^1.167.0",
+ "`@tanstack/react-router-devtools`": "^1.170.0",📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| "@tanstack/react-router": "^1.170.17", | |
| "@tanstack/react-router-devtools": "^1.167.0", | |
| "`@tanstack/react-router`": "^1.170.17", | |
| "`@tanstack/react-router-devtools`": "^1.170.0", |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@examples/react/start-descope/package.json` around lines 18 - 19, The
dependency versions for `@tanstack/react-router` and
`@tanstack/react-router-devtools` are out of sync, which can lead to
incompatibilities. Update the `@tanstack/react-router-devtools` entry in
package.json to match the same minor version as `@tanstack/react-router`, and keep
the versions aligned so both packages resolve together consistently.
| if (authInfo.jwt && authInfo.jwt !== sessionToken) { | ||
| setCookie(SESSION_COOKIE, authInfo.jwt, { | ||
| httpOnly: false, | ||
| sameSite: 'lax', | ||
| path: '/', | ||
| }) | ||
| } |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n== Target file ==\n'
git ls-files 'examples/react/start-descope/src/integrations/descope/session.server.ts'
printf '\n== File outline ==\n'
ast-grep outline examples/react/start-descope/src/integrations/descope/session.server.ts --view expanded || true
printf '\n== Relevant lines ==\n'
nl -ba examples/react/start-descope/src/integrations/descope/session.server.ts | sed -n '1,140p'
printf '\n== Search for SESSION_COOKIE and setCookie usage ==\n'
rg -n "SESSION_COOKIE|setCookie\\(" examples/react/start-descope/src/integrations/descope -S
printf '\n== Search for cookie options / secure / maxAge nearby ==\n'
rg -n "secure:|maxAge:|expires:|sameSite:|httpOnly:" examples/react/start-descope/src/integrations/descope -SRepository: TanStack/router
Length of output: 741
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n== session.server.ts (numbered) ==\n'
sed -n '1,140p' examples/react/start-descope/src/integrations/descope/session.server.ts | awk '{printf "%4d %s\n", NR, $0}'
printf '\n== setCookie definition / cookie helper usage ==\n'
rg -n "export function setCookie|function setCookie|const setCookie|setCookie\\s*=|SESSION_COOKIE" examples/react/start-descope/src -S
printf '\n== Descope cookie lifetime hints ==\n'
rg -n "SessionTokenCookieName|RefreshTokenCookieName|maxAge|expires|secure" examples/react/start-descope/src -SRepository: TanStack/router
Length of output: 4197
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n== Search for React Start cookie helper docs/usages in repo ==\n'
rg -n "`@tanstack/react-start/server`|setCookie\\(" . -S
printf '\n== Package versions ==\n'
rg -n '"`@tanstack/react-start`"|`@descope/node-sdk`' package.json examples -S
printf '\n== Search for secure cookie assumptions ==\n'
rg -n "sameSite: 'lax'|sameSite: 'none'|secure: true|httpOnly: false|maxAge:" examples packages .github -SRepository: TanStack/router
Length of output: 29301
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n== setCookie implementation ==\n'
sed -n '300,380p' packages/start-server-core/src/request-response.ts | awk '{printf "%4d %s\n", NR+299, $0}'
printf '\n== cookie helper docs in repo ==\n'
rg -n "setCookie\\(.*secure|cookie options|httpOnly|sameSite|maxAge|expires" packages/start-server-core docs examples -S
printf '\n== Descope example README lines around session handling ==\n'
sed -n '50,95p' examples/react/start-descope/README.md | awk '{printf "%4d %s\n", NR+49, $0}'Repository: TanStack/router
Length of output: 10725
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n== provider.tsx ==\n'
sed -n '1,120p' examples/react/start-descope/src/integrations/descope/provider.tsx | awk '{printf "%4d %s\n", NR, $0}'
printf '\n== Descope sessionTokenViaCookie occurrences ==\n'
rg -n "sessionTokenViaCookie|sameSite: 'Lax'|sameSite: 'lax'" examples/react/start-descope docs -S
printf '\n== CookieSerializeOptions definition ==\n'
rg -n "interface CookieSerializeOptions|type CookieSerializeOptions" packages/start-server-core packages -SRepository: TanStack/router
Length of output: 2145
🌐 Web query:
h3 setCookie default secure maxAge CookieSerializeOptions sameSite Descope sessionTokenViaCookie cookie lifetime
💡 Result:
In the H3 framework, the setCookie utility uses CookieSerializeOptions to define cookie behavior [1][2][3]. By default, H3 sets the cookie path to '/' [2][4], but it does not impose global defaults for attributes like secure, maxAge, or sameSite unless specified in the options object passed to setCookie [3]. Developers should explicitly define these in the options parameter when calling setCookie [3]. For Descope session management, the sessionTokenViaCookie configuration controls whether session tokens are stored in a cookie [5]. When enabled, Descope automatically sets the session token in a cookie (default name: DS) with Secure and HttpOnly flags [6][7][8]. Regarding Descope's specific cookie defaults: - Secure: Defaults to true (the cookie will only be sent over HTTPS connections) [6][7]. - SameSite: Defaults to Strict in the standard web JS SDK [6][7], but defaults to Lax in the @descope/nextjs-sdk to ensure compatibility with middleware [9]. - Cookie Lifetime: The session lifetime is generally managed by the Descope platform's session settings rather than an explicit maxAge set on the client side during creation [8]. However, customization of these attributes (sameSite, secure, cookieName) is supported by passing an object to sessionTokenViaCookie [6][7][9]. If you are customizing these, note that if you provide a configuration object and only specify sameSite, the secure flag will typically default to true [6][7][9].
Citations:
- 1: https://h3.dev/utils/cookie
- 2: https://github.com/unjs/h3/blob/main/src/utils/cookie.ts
- 3: https://www.h3.dev/examples/handle-cookie
- 4: https://raw.githubusercontent.com/unjs/h3/main/src/utils/cookie.ts
- 5: https://docs.descope.com/authorization/session-management/session-validation/client
- 6: https://github.com/descope/descope-js/tree/main/packages/sdks/react-sdk
- 7: https://registry.npmjs.org/%40descope%2Fweb-js-sdk
- 8: https://docs.descope.com/security-best-practices/session-token-storage
- 9: https://registry.npmjs.org/@descope/nextjs-sdk
Mark the rotated session cookie as secure. This JWT is stored in a browser cookie, so it should not be sent over plain HTTP.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@examples/react/start-descope/src/integrations/descope/session.server.ts`
around lines 49 - 55, The rotated session cookie set in session.server.ts via
the SESSION_COOKIE write should be marked secure because it stores a JWT in a
browser cookie. Update the cookie options in the authInfo.jwt rotation path to
include the secure flag alongside the existing httpOnly, sameSite, and path
settings so it is only sent over HTTPS.
| React.useEffect(() => { | ||
| async function doLogout() { | ||
| try { | ||
| // Revoke the session with Descope and clear the client-side tokens. | ||
| await sdk.logout() | ||
| } catch (err) { | ||
| console.error('Descope logout error', err) | ||
| } | ||
| // Clear the server-readable cookies, then refresh and go home. | ||
| await clearServerSession() | ||
| await router.invalidate() | ||
| await router.navigate({ to: '/' }) | ||
| } | ||
| doLogout() | ||
| // eslint-disable-next-line react-hooks/exhaustive-deps | ||
| }, []) |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win
Unhandled rejection leaves user stuck on "Signing out…" if clearServerSession() or router methods throw.
sdk.logout() is wrapped in try/catch, but clearServerSession(), router.invalidate(), and router.navigate() are not. If the server function fails, the promise rejects unhandled and the user has no way to recover — they're left on a perpetual loading screen.
🛡️ Proposed fix: wrap post-logout operations in try/catch
React.useEffect(() => {
async function doLogout() {
try {
// Revoke the session with Descope and clear the client-side tokens.
await sdk.logout()
} catch (err) {
console.error('Descope logout error', err)
}
- // Clear the server-readable cookies, then refresh and go home.
- await clearServerSession()
- await router.invalidate()
- await router.navigate({ to: '/' })
+ try {
+ // Clear the server-readable cookies, then refresh and go home.
+ await clearServerSession()
+ await router.invalidate()
+ await router.navigate({ to: '/' })
+ } catch (err) {
+ console.error('Logout cleanup error', err)
+ await router.navigate({ to: '/' })
+ }
}
doLogout()
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [])📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| React.useEffect(() => { | |
| async function doLogout() { | |
| try { | |
| // Revoke the session with Descope and clear the client-side tokens. | |
| await sdk.logout() | |
| } catch (err) { | |
| console.error('Descope logout error', err) | |
| } | |
| // Clear the server-readable cookies, then refresh and go home. | |
| await clearServerSession() | |
| await router.invalidate() | |
| await router.navigate({ to: '/' }) | |
| } | |
| doLogout() | |
| // eslint-disable-next-line react-hooks/exhaustive-deps | |
| }, []) | |
| React.useEffect(() => { | |
| async function doLogout() { | |
| try { | |
| // Revoke the session with Descope and clear the client-side tokens. | |
| await sdk.logout() | |
| } catch (err) { | |
| console.error('Descope logout error', err) | |
| } | |
| try { | |
| // Clear the server-readable cookies, then refresh and go home. | |
| await clearServerSession() | |
| await router.invalidate() | |
| await router.navigate({ to: '/' }) | |
| } catch (err) { | |
| console.error('Logout cleanup error', err) | |
| await router.navigate({ to: '/' }) | |
| } | |
| } | |
| doLogout() | |
| // eslint-disable-next-line react-hooks/exhaustive-deps | |
| }, []) |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@examples/react/start-descope/src/routes/logout.tsx` around lines 15 - 30, The
logout flow in doLogout only catches errors from sdk.logout(), so failures in
clearServerSession(), router.invalidate(), or router.navigate() can reject
unhandled and leave the user stuck on the signing-out screen. Wrap the
post-logout cleanup/navigation steps in the same try/catch (or a second one
around the remaining awaits) and ensure errors are logged while still allowing
the UI to recover. Keep the existing useEffect/doLogout structure, but make the
full logout sequence resilient to any thrown promise from clearServerSession,
router.invalidate, and router.navigate.
This PR introduces a TanStack Start sample app showcasing Descope authentication and adds it to the documentation.
Cap.2026-07-08.at.14.47.43.mp4
Summary by CodeRabbit
New Features
Documentation