From c985e9c62d7d0ab0d23dae27fdec3081427903f6 Mon Sep 17 00:00:00 2001 From: Gyanesh Gouraw Date: Mon, 27 Jul 2026 20:40:57 +0530 Subject: [PATCH 1/4] feat: add 'use client' directive to bundles for RSC support --- .github/workflows/test.yml | 22 +++++++ EXAMPLES.md | 69 ++++++++++++++++++++++ __tests__/use-client-directive.test.tsx | 76 +++++++++++++++++++++++++ package.json | 1 + rollup.config.mjs | 7 +++ src/auth0-provider.tsx | 5 ++ 6 files changed, 180 insertions(+) create mode 100644 __tests__/use-client-directive.test.tsx diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 79cc01ae..4b5c9b76 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -63,3 +63,25 @@ jobs: uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # pin@7.0.0 with: token: ${{ secrets.CODECOV_TOKEN }} + + rsc-directive: + needs: build # Require build to complete before running tests + + name: Verify 'use client' directive + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + + - name: Setup Node + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 + with: + node-version: ${{ env.NODE_VERSION }} + cache: npm + + - name: Install dependencies + run: npm ci + + - name: Build bundles and assert 'use client' directive + run: npm run test:dist diff --git a/EXAMPLES.md b/EXAMPLES.md index e9255a97..e3978d97 100644 --- a/EXAMPLES.md +++ b/EXAMPLES.md @@ -7,6 +7,7 @@ - [Protecting a route in a `react-router-dom v6` app](#protecting-a-route-in-a-react-router-dom-v6-app) - [Protecting a route in a Gatsby app](#protecting-a-route-in-a-gatsby-app) - [Protecting a route in a Next.js app (in SPA mode)](#protecting-a-route-in-a-nextjs-app-in-spa-mode) +- [Using with the Next.js App Router (Server Components)](#using-with-the-nextjs-app-router-server-components) - [Use with Auth0 organizations](#use-with-auth0-organizations) - [Protecting a route with a claims check](#protecting-a-route-with-a-claims-check) - [Device-bound tokens with DPoP](#device-bound-tokens-with-dpop) @@ -460,6 +461,74 @@ export default withAuthenticationRequired(Profile); See [Next.js example app](./examples/nextjs-app) +## Using with the Next.js App Router (Server Components) + +In the Next.js App Router every module is a React Server Component by default. `@auth0/auth0-react` is a client-only library (it relies on React hooks and browser APIs), and its published ESM and CommonJS bundles ship the `'use client'` directive baked in. That means you can import `Auth0Provider` **directly** into a Server Component such as your root `app/layout.tsx`, without writing your own `'use client'` wrapper. + +The `redirect_uri` value is evaluated where the JSX is authored — the Server Component — where `window` is not available. So pass an explicit `redirect_uri` from an environment variable (or another value known at build/server time) rather than `window.location.origin`: + +```tsx +// app/layout.tsx (Server Component, no 'use client' directive needed) +import { Auth0Provider } from '@auth0/auth0-react'; + +export default function RootLayout({ + children, +}: { + children: React.ReactNode; +}) { + return ( + + + + {children} + + + + ); +} +``` + +Any component that **calls** a hook such as `useAuth0()` runs on the client, so that component must be a Client Component. This is a standard React Server Components rule (hooks cannot execute during server render), not something the SDK can remove: mark the file with `'use client'`. + +```tsx +// app/page.tsx +'use client'; + +import { useAuth0 } from '@auth0/auth0-react'; + +export default function Home() { + const { isAuthenticated, isLoading, loginWithRedirect, logout, user } = + useAuth0(); + + if (isLoading) return

Loading...

; + + return isAuthenticated ? ( + <> +

Signed in as {user?.name}

+ + + ) : ( + + ); +} +``` + +Reading `window.location.origin` is safe here precisely because `app/page.tsx` is a Client Component (marked with `'use client'`), so `window` exists at runtime — unlike in the Server Component above. + +In short: the provider can live in a Server Component, while components that consume the hooks opt into the client, exactly as with any other client-only React library. + ## Use with Auth0 organizations [Organizations](https://auth0.com/docs/organizations) is a set of features that provide better support for developers who build and maintain SaaS and Business-to-Business (B2B) applications. Note that Organizations is currently only available to customers on our Enterprise and Startup subscription plans. diff --git a/__tests__/use-client-directive.test.tsx b/__tests__/use-client-directive.test.tsx new file mode 100644 index 00000000..19e43412 --- /dev/null +++ b/__tests__/use-client-directive.test.tsx @@ -0,0 +1,76 @@ +/** + * @jest-environment node + * + * React Server Components support. + * + * These assertions run against the BUILT bundles in dist/, not src/. The entry + * (src/index.tsx) is a re-export barrel with no directive of its own, and the + * 'use client' directives in the imported leaf modules are dropped when Rollup + * concatenates them into a single file, so the directive is injected at the + * bundle top via rollup's output.banner instead. The RSC-consumed entry points + * are the CJS (main) and ESM (module) outputs; the UMD