diff --git a/docs/_partials/authenticate-req.mdx b/docs/_partials/authenticate-req.mdx index b3135e8205..0777f2ffd3 100644 --- a/docs/_partials/authenticate-req.mdx +++ b/docs/_partials/authenticate-req.mdx @@ -2,17 +2,22 @@ import { createClerkClient } from '@clerk/backend' export async function GET(req: Request) { + // Initialize the JS Backend SDK + // This varies depending on the SDK you're using + // https://clerk.com/docs/js-backend/getting-started/quickstart const clerkClient = createClerkClient({ secretKey: process.env.CLERK_SECRET_KEY, publishableKey: process.env.CLERK_PUBLISHABLE_KEY, }) - const { isSignedIn } = await clerkClient.authenticateRequest(req, { - jwtKey: process.env.CLERK_JWT_KEY, + // Use the `authenticateRequest()` method to verify the token + const { isAuthenticated } = await clerkClient.authenticateRequest(req, { authorizedParties: ['https://example.com'], + jwtKey: process.env.CLERK_JWT_KEY, }) - if (!isSignedIn) { + // Protect the route from unauthenticated users + if (!isAuthenticated) { return Response.json({ status: 401 }) } diff --git a/docs/_partials/backend/usage.mdx b/docs/_partials/backend/usage.mdx index 262c3136dd..6294086b10 100644 --- a/docs/_partials/backend/usage.mdx +++ b/docs/_partials/backend/usage.mdx @@ -1,2 +1,2 @@ > [!NOTE] -> Importing `clerkClient` varies based on your framework. Refer to the [JS Backend SDK overview](/docs/js-backend/getting-started/quickstart) for usage details, including guidance on [how to access the `userId` and other properties](/docs/js-backend/getting-started/quickstart#get-the-user-id-and-other-properties). +> Using `clerkClient` varies based on your framework. Refer to the [JS Backend SDK overview](/docs/js-backend/getting-started/quickstart) for usage details, including guidance on [how to access the `userId` and other properties](/docs/js-backend/getting-started/quickstart#get-the-user-id-and-other-properties). diff --git a/docs/getting-started/quickstart.js-backend.mdx b/docs/getting-started/quickstart.js-backend.mdx index 4c7be4fd79..f34c5956fc 100644 --- a/docs/getting-started/quickstart.js-backend.mdx +++ b/docs/getting-started/quickstart.js-backend.mdx @@ -65,7 +65,9 @@ To access a resource, you must first instantiate a `clerkClient` instance. To use the default `clerkClient` instance, set your `CLERK_SECRET_KEY` [environment variable](/docs/guides/development/clerk-environment-variables#clerk-publishable-and-secret-keys) and then import the `clerkClient` instance from the SDK as shown in the following example: - + ```jsx import { clerkClient } from '@clerk/nextjs/server' @@ -73,7 +75,15 @@ To access a resource, you must first instantiate a `clerkClient` instance. - If you are using Remix, see the following section for how to instantiate `clerkClient`. + ```js + import { clerkClient } from '@clerk/astro/server' + ``` + + + + ```js + import { clerkClient } from '@clerk/express' + ``` @@ -84,19 +94,21 @@ To access a resource, you must first instantiate a `clerkClient` instance. ```js - import { clerkClient } from '@clerk/astro/server' + import { clerkClient } from '@clerk/nuxt/server' ``` - ```js - import { clerkClient } from '@clerk/express' - ``` + If you are using React Router, see the following section for how to instantiate `clerkClient`. + + + + If you are using Remix, see the following section for how to instantiate `clerkClient`. ```js - import { clerkClient } from '@clerk/nuxt/server' + import { clerkClient } from '@clerk/tanstack-react-start/server' ``` @@ -105,7 +117,9 @@ To access a resource, you must first instantiate a `clerkClient` instance. If you would like to customize the behavior of the JS Backend SDK, you can instantiate a `clerkClient` instance yourself by calling `createClerkClient()` and passing in [`options`](#create-clerk-client-options). - + ```jsx import { createClerkClient } from '@clerk/nextjs/server' @@ -118,6 +132,87 @@ To access a resource, you must first instantiate a `clerkClient` instance. ``` + + If you are using Astro, you must pass the [endpoint context](https://docs.astro.build/en/reference/api-reference/#endpoint-context) when invoking the `clerkClient` function. + + ```jsx + import { clerkClient } from '@clerk/astro/server' + + export async function GET(context) { + const { isAuthenticated, userId, redirectToSignIn } = context.locals.auth() + + if (!isAuthenticated) { + return redirectToSignIn() + } + + const user = await clerkClient(context).users.getUser(userId) + + return new Response(JSON.stringify({ user })) + } + ``` + + + + ```js + import { createClerkClient } from '@clerk/express' + + const clerkClient = createClerkClient({ secretKey: process.env.CLERK_SECRET_KEY }) + + const userList = await clerkClient.users.getUserList() + ``` + + + + ```jsx + import { createClerkClient } from '@clerk/fastify' + + const clerkClient = createClerkClient({ secretKey: process.env.CLERK_SECRET_KEY }) + + const userList = await clerkClient.users.getUserList() + ``` + + + + ```tsx {{ filename: 'server/api/users/index.ts' }} + import { createClerkClient } from '@clerk/nuxt/server' + + export default defineEventHandler(async () => { + const config = useRuntimeConfig() + const clerkClient = createClerkClient({ secretKey: config.clerk.secretKey }) + const userList = await clerkClient.users.getUserList() + + return { userList } + }) + ``` + + + + ```tsx {{ filename: 'app/routes/example.tsx' }} + import { createClerkClient } from '@clerk/react-router/api.server' + + export async function loader(args: Route.LoaderArgs) { + const userList = await createClerkClient({ + secretKey: process.env.CLERK_SECRET_KEY, + }).users.getUserList() + + return { + userList: JSON.stringify(userList), + } + } + + export default function Users({ loaderData }: Route.ComponentProps) { + return ( +
+

List of users

+
+                {JSON.stringify(loaderData, null, 2)}
+              
+
+ ) + } + ``` +
+ If you are using Remix, you must instantiate `clerkClient` by calling the `createClerkClient()` function and passing in [`options`](#create-clerk-client-options). @@ -183,90 +278,23 @@ To access a resource, you must first instantiate a `clerkClient` instance.
- - ```jsx - import { createClerkClient } from '@clerk/fastify' - - const clerkClient = createClerkClient({ secretKey: process.env.CLERK_SECRET_KEY }) - - const userList = await clerkClient.users.getUserList() - ``` - - - - If you are using Astro, you must pass the [endpoint context](https://docs.astro.build/en/reference/api-reference/#endpoint-context) when invoking the `clerkClient` function. - - ```jsx - import { clerkClient } from '@clerk/astro/server' - - export async function GET(context) { - const { isAuthenticated, userId, redirectToSignIn } = context.locals.auth() - - if (!isAuthenticated) { - return redirectToSignIn() - } - - const user = await clerkClient(context).users.getUser(userId) - - return new Response(JSON.stringify({ user })) - } - ``` - - ```tsx {{ filename: 'app/routes/api/example.tsx' }} - import { createClerkClient } from '@clerk/backend' + import { clerkClient } from '@clerk/tanstack-react-start/server' import { json } from '@tanstack/react-start' import { createServerFileRoute } from '@tanstack/react-start/server' export const ServerRoute = createServerFileRoute().methods({ GET: async ({ request, params }) => { - const clerkClient = createClerkClient({ secretKey: import.meta.env.CLERK_SECRET_KEY }) - - const userList = await clerkClient.users.getUserList() + const userList = await clerkClient({ + secretKey: import.meta.env.CLERK_SECRET_KEY, + }).users.getUserList() return json({ userList }) }, }) ``` - - - - ```js - import { createClerkClient } from '@clerk/express' - - const clerkClient = createClerkClient({ secretKey: process.env.CLERK_SECRET_KEY }) - - const userList = await clerkClient.users.getUserList() - ``` - - ```js - const Clerk = require('@clerk/express') - - const clerkClient = Clerk.createClerkClient({ secretKey: process.env.CLERK_SECRET_KEY }) - - clerkClient.sessions - .getSessionList() - .then((sessions) => console.log(sessions)) - .catch((error) => console.error(error)) - ``` - - - - - ```tsx {{ filename: 'server/api/users/index.ts' }} - import { createClerkClient } from '@clerk/nuxt/server' - - export default defineEventHandler(async () => { - const config = useRuntimeConfig() - const clerkClient = createClerkClient({ secretKey: config.clerk.secretKey }) - const userList = await clerkClient.users.getUserList() - - return { userList } - }) - ``` -
@@ -327,6 +355,8 @@ The [`Auth`](/docs/reference/backend/types/auth-object) object contains importan The following examples demonstrate how to retrieve the authenticated user's ID using framework-specific auth helpers and how to use the JS Backend SDK's [`getUser()`](/docs/reference/backend/user/get-user) method to get the [Backend `User` object](/docs/reference/backend/types/backend-user). + **If your SDK isn't listed, you can use the comments in the example to help you adapt it to your SDK.** + {/* TODO: The following Tabs example is duplicated in the guides/how-clerk-works/session-tokens.mdx file. It cannot be a partial to be reused across both files because this example includes a partial and partials cannot include partials. Also, the text in each of these tabs is removed in the other file as its not relevant to that file's example. So keep these two Tabs examples in sync please. */} @@ -340,7 +370,9 @@ The [`Auth`](/docs/reference/backend/types/auth-object) object contains importan import { auth, clerkClient } from '@clerk/nextjs/server' export async function GET() { - // Use `auth()` to access `isAuthenticated` and the user's ID + // The `Auth` object gives you access to properties like `isAuthenticated` and `userId` + // Accessing the `Auth` object differs depending on the SDK you're using + // https://clerk.com/docs/reference/backend/types/auth-object#how-to-access-the-auth-object const { isAuthenticated, userId } = await auth() // Protect the route by checking if the user is signed in @@ -350,7 +382,9 @@ The [`Auth`](/docs/reference/backend/types/auth-object) object contains importan const client = await clerkClient() - // Use the JS Backend SDK's `getUser()` method to get the Backend User object + // Initialize the JS Backend SDK + // This varies depending on the SDK you're using + // https://clerk.com/docs/js-backend/getting-started/quickstart const user = await client.users.getUser(userId) // Return the Backend User object @@ -369,7 +403,9 @@ The [`Auth`](/docs/reference/backend/types/auth-object) object contains importan import { clerkClient } from '@clerk/astro/server' export async function GET(context) { - // Use `locals.auth()` to access `isAuthenticated` and the user's ID + // The `Auth` object gives you access to properties like `isAuthenticated` and `userId` + // Accessing the `Auth` object differs depending on the SDK you're using + // https://clerk.com/docs/reference/backend/types/auth-object#how-to-access-the-auth-object const { isAuthenticated, userId } = context.locals.auth() // Protect the route by checking if the user is signed in @@ -377,7 +413,9 @@ The [`Auth`](/docs/reference/backend/types/auth-object) object contains importan return new Response('Unauthorized', { status: 401 }) } - // Use the JS Backend SDK's `getUser()` method to get the Backend User object + // Initialize the JS Backend SDK + // This varies depending on the SDK you're using + // https://clerk.com/docs/js-backend/getting-started/quickstart const user = await clerkClient(context).users.getUser(userId) // Return the Backend User object @@ -397,7 +435,9 @@ The [`Auth`](/docs/reference/backend/types/auth-object) object contains importan const clerkClient = createClerkClient({ secretKey: process.env.CLERK_SECRET_KEY }) app.get('/user', async (req, res) => { - // Use `getAuth()` to access `isAuthenticated` and the user's ID + // The `Auth` object gives you access to properties like `isAuthenticated` and `userId` + // Accessing the `Auth` object differs depending on the SDK you're using + // https://clerk.com/docs/reference/backend/types/auth-object#how-to-access-the-auth-object const { isAuthenticated, userId } = getAuth(req) // Protect the route by checking if the user is signed in @@ -405,7 +445,10 @@ The [`Auth`](/docs/reference/backend/types/auth-object) object contains importan res.status(401).json({ error: 'User not authenticated' }) } - // Use the JS Backend SDK's `getUser()` method to get the Backend User object + // Initialize the JS Backend SDK + // This varies depending on the SDK you're using + // https://clerk.com/docs/js-backend/getting-started/quickstart + // Use the `getUser()` method to get the Backend User object const user = await clerkClient.users.getUser(userId) // Return the Backend User object @@ -424,7 +467,9 @@ The [`Auth`](/docs/reference/backend/types/auth-object) object contains importan import type { Route } from './+types/profile' export async function loader(args: Route.LoaderArgs) { - // Use `getAuth()` to access `isAuthenticated` and the user's ID + // The `Auth` object gives you access to properties like `isAuthenticated` and `userId` + // Accessing the `Auth` object differs depending on the SDK you're using + // https://clerk.com/docs/reference/backend/types/auth-object#how-to-access-the-auth-object const { isAuthenticated, userId } = await getAuth(args) // Protect the route by checking if the user is signed in @@ -432,7 +477,10 @@ The [`Auth`](/docs/reference/backend/types/auth-object) object contains importan return redirect('/sign-in?redirect_url=' + args.request.url) } - // Use the JS Backend SDK's `getUser()` method to get the Backend User object + // Initialize the JS Backend SDK + // This varies depending on the SDK you're using + // https://clerk.com/docs/js-backend/getting-started/quickstart + // Use the `getUser()` method to get the Backend User object const user = await createClerkClient({ secretKey: process.env.CLERK_SECRET_KEY }).users.getUser( userId, ) @@ -455,7 +503,9 @@ The [`Auth`](/docs/reference/backend/types/auth-object) object contains importan import { createClerkClient } from '@clerk/remix/api.server' export const loader: LoaderFunction = async (args) => { - // Use `getAuth()` to access `isAuthenticated` and the user's ID + // The `Auth` object gives you access to properties like `isAuthenticated` and `userId` + // Accessing the `Auth` object differs depending on the SDK you're using + // https://clerk.com/docs/reference/backend/types/auth-object#how-to-access-the-auth-object const { isAuthenticated, userId } = await getAuth(args) // If there is no userId, then redirect to sign-in route @@ -463,7 +513,10 @@ The [`Auth`](/docs/reference/backend/types/auth-object) object contains importan return redirect('/sign-in?redirect_url=' + args.request.url) } - // Use the JS Backend SDK's `getUser()` method to get the Backend User object + // Initialize the JS Backend SDK + // This varies depending on the SDK you're using + // https://clerk.com/docs/js-backend/getting-started/quickstart + // Use the `getUser()` method to get the Backend User object const user = await createClerkClient({ secretKey: process.env.CLERK_SECRET_KEY }).users.getUser( userId, ) @@ -479,7 +532,9 @@ The [`Auth`](/docs/reference/backend/types/auth-object) object contains importan import { createClerkClient } from '@clerk/remix/api.server' export const action: ActionFunction = async (args) => { - // Use `getAuth()` to access `isAuthenticated` and the user's ID + // The `Auth` object gives you access to properties like `isAuthenticated` and `userId` + // Accessing the `Auth` object differs depending on the SDK you're using + // https://clerk.com/docs/reference/backend/types/auth-object#how-to-access-the-auth-object const { isAuthenticated, userId } = await getAuth(args) // If there is no userId, then redirect to sign-in route @@ -487,6 +542,10 @@ The [`Auth`](/docs/reference/backend/types/auth-object) object contains importan return redirect('/sign-in?redirect_url=' + args.request.url) } + // Initialize the JS Backend SDK + // This varies depending on the SDK you're using + // https://clerk.com/docs/js-backend/getting-started/quickstart + // Use the `getUser()` method to get the Backend User object const user = await createClerkClient({ secretKey: process.env.CLERK_SECRET_KEY }).users.getUser( userId, ) @@ -509,7 +568,9 @@ The [`Auth`](/docs/reference/backend/types/auth-object) object contains importan export const Route = createAPIFileRoute('/api/example')({ GET: async ({ request, params }) => { - // Use `getAuth()` to access `isAuthenticated` and the user's ID + // The `Auth` object gives you access to properties like `isAuthenticated` and `userId` + // Accessing the `Auth` object differs depending on the SDK you're using + // https://clerk.com/docs/reference/backend/types/auth-object#how-to-access-the-auth-object const { isAuthenticated, userId } = await getAuth(req) // Protect the route by checking if the user is signed in @@ -520,7 +581,10 @@ The [`Auth`](/docs/reference/backend/types/auth-object) object contains importan // Instantiate the JS Backend SDK const clerkClient = createClerkClient({ secretKey: import.meta.env.CLERK_SECRET_KEY }) - // Use the JS Backend SDK's `getUser()` method to get the Backend User object + // Initialize the JS Backend SDK + // This varies depending on the SDK you're using + // https://clerk.com/docs/js-backend/getting-started/quickstart + // Use the `getUser()` method to get the Backend User object const user = await clerkClient.users.getUser(userId) // Return the Backend User object diff --git a/docs/guides/configure/auth-strategies/social-connections/overview.mdx b/docs/guides/configure/auth-strategies/social-connections/overview.mdx index 166c19a541..67536492d1 100644 --- a/docs/guides/configure/auth-strategies/social-connections/overview.mdx +++ b/docs/guides/configure/auth-strategies/social-connections/overview.mdx @@ -74,7 +74,7 @@ Use the following tabs to see how to add additional OAuth scopes to the ` + + ```tsx {{ filename: 'app/api/notion/route.tsx' }} + import { auth, clerkClient } from '@clerk/nextjs/server' + import { NextResponse } from 'next/server' + + export async function GET() { + // The `Auth` object gives you access to properties like `isAuthenticated` and `userId` + // Accessing the `Auth` object differs depending on the SDK you're using + // https://clerk.com/docs/reference/backend/types/auth-object#how-to-access-the-auth-object + const { isAuthenticated, userId } = await auth() + + // Protect the route from unauthenticated users + if (!isAuthenticated) { + return NextResponse.json({ message: 'User not found' }) + } + + // Use the JS Backend SDK to get the OAuth access token for the user + const provider = 'notion' + + // Initialize the JS Backend SDK + // This varies depending on the SDK you're using + // https://clerk.com/docs/js-backend/getting-started/quickstart + const client = await clerkClient() + + // Use the JS Backend SDK to get the user's OAuth access token + const clerkResponse = await client.users.getUserOauthAccessToken(userId, provider) + const accessToken = clerkResponse.data[0].token || '' + if (!accessToken) { + return NextResponse.json({ message: 'Access token not found' }, { status: 401 }) + } + + // Fetch the user data from the Notion API + // This endpoint fetches a list of users + // https://developers.notion.com/reference/get-users + const notionUrl = 'https://api.notion.com/v1/users' + + const notionResponse = await fetch(notionUrl, { + headers: { + Authorization: `Bearer ${accessToken}`, + 'Notion-Version': '2022-06-28', + }, + }) + + // Handle the response from the Notion API + const notionData = await notionResponse.json() + + return NextResponse.json({ message: notionData }) + } + ``` + + + + ```js {{ filename: 'notion.js' }} + import { createClerkClient, getAuth } from '@clerk/express' + import express from 'express' + + const app = express() + // Initialize the JS Backend SDK + // This varies depending on the SDK you're using + // https://clerk.com/docs/js-backend/getting-started/quickstart + const clerkClient = createClerkClient({ secretKey: process.env.CLERK_SECRET_KEY }) + + app.get('/user', async (req, res) => { + // The `Auth` object gives you access to properties like `isAuthenticated` and `userId` + // Accessing the `Auth` object differs depending on the SDK you're using + // https://clerk.com/docs/reference/backend/types/auth-object#how-to-access-the-auth-object + const { isAuthenticated, userId } = getAuth(req) + + // Protect the route from unauthenticated users + if (!isAuthenticated) { + res.status(401).json({ error: 'User not authenticated' }) + } + + // Use the JS Backend SDK to get the user's OAuth access token + const provider = 'notion' + const clerkResponse = await clerkClient.users.getUserOauthAccessToken(userId, provider) + const accessToken = clerkResponse.data[0].token || '' + + if (!accessToken) { + res.status(401).json({ error: 'Access token not found' }) + } + + // Fetch the user data from the Notion API + // This endpoint fetches a list of users + // https://developers.notion.com/reference/get-users + const notionUrl = 'https://api.notion.com/v1/users' + + const notionResponse = await fetch(notionUrl, { + headers: { + Authorization: `Bearer ${accessToken}`, + 'Notion-Version': '2022-06-28', + }, + }) + + // Handle the response from the Notion API + const notionData = await notionResponse.json() + + res.json(notionData) + }) + ``` + + + + ```js + import { createClerkClient } from '@clerk/backend' + + // Initialize the JS Backend SDK + // This varies depending on the SDK you're using + // https://clerk.com/docs/js-backend/getting-started/quickstart + const clerkClient = createClerkClient({ secretKey: process.env.CLERK_SECRET_KEY }) + + async function getNotionData(request) { + // The `Auth` object gives you access to properties like `isAuthenticated` and `userId` + // Accessing the `Auth` object differs depending on the SDK you're using + // https://clerk.com/docs/reference/backend/types/auth-object#how-to-access-the-auth-object + const { isAuthenticated, userId } = request.auth + + // Protect the route from unauthenticated users + if (!isAuthenticated) { + return null + } + + // Use the JS Backend SDK to get the user's OAuth access token + const provider = 'notion' + const clerkResponse = await clerkClient.users.getUserOauthAccessToken(userId, provider) + const accessToken = clerkResponse.data[0].token || '' + if (!accessToken) { + return null + } + + // Fetch the user data from the Notion API + // This endpoint fetches a list of users + // https://developers.notion.com/reference/get-users + const notionUrl = 'https://api.notion.com/v1/users' + + const notionResponse = await fetch(notionUrl, { + headers: { + Authorization: `Bearer ${accessToken}`, + 'Notion-Version': '2022-06-28', + }, + }) + + // Handle the response from the Notion API + const notionData = await notionResponse.json() + + // Return the Notion data + return notionData + } + ``` + + ## Add a social connection after sign-up diff --git a/docs/guides/configure/session-tasks.mdx b/docs/guides/configure/session-tasks.mdx index 935bc800e0..3aeb2849b2 100644 --- a/docs/guides/configure/session-tasks.mdx +++ b/docs/guides/configure/session-tasks.mdx @@ -40,12 +40,10 @@ The following table lists the available tasks and their corresponding components > [!IMPORTANT] > Personal accounts being disabled by default was released on 08-22-2025. Applications created before this date will not be able to see the **Allow personal accounts** setting, because personal accounts were enabled by default. -If the prebuilt components don't meet your specific needs or if you require more control over the logic, you can also build your own UI using the `Session.currentTask` property to check if the user has pending session tasks. Refer to the [custom flows documentation](/docs/guides/development/custom-flows/overview) for specific implementation guides. +If the prebuilt components don't meet your specific needs or if you require more control over the logic, you can also build your own UI using the `Session.currentTask` property to check if the user has pending session tasks. To access the `Session.currentTask` property, you can use either the `useSession()` hook for React-based applications or `window.Clerk` for other frameworks. - + ```jsx - import { useSession } from '@clerk/clerk-react' - const { session } = useSession() if (session?.currentTask) { @@ -72,42 +70,27 @@ When users have pending session tasks, you can redirect them to specific pages o The `taskUrls` option allows you to specify custom URL paths where users are redirected after sign-up or sign-in when specific session tasks need to be completed. This allows you to still use `` and `` but have tasks with custom pages. - - - Configure the `taskUrls` option in your root layout to specify where users should be redirected for different session tasks. - - ```tsx {{ filename: 'app/layout.tsx' }} - import { ClerkProvider } from '@clerk/nextjs' - - export default function RootLayout({ children }: { children: React.ReactNode }) { - return ( - - {children} - - ) - } - ``` - +The `taskUrls` option is available wherever you initialize the Clerk integration. For most SDKs, it's ``. - - Create a custom page that imports the `TaskChooseOrganization` component to handle the task. +```tsx + + {children} + +``` - ```tsx {{ filename: 'app/onboarding/choose-organization/page.tsx' }} - import { TaskChooseOrganization } from '@clerk/nextjs' +Then, create a page at that URL path that imports the [``](/docs/reference/components/authentication/task-choose-organization) component to handle the task. - export default function ChooseOrganizationPage() { - return - } - ``` - - +```tsx {{ filename: 'app/onboarding/choose-organization/page.tsx' }} +export default function Page() { + return +} +``` -#### Using the `RedirectToTasks` control component +#### Using the `` control component The `` control component redirects users to the appropriate task page when they have pending session tasks. @@ -126,60 +109,52 @@ export default function Layout({ children }: { children: React.ReactNode }) { } ``` -{/* TODO: Add examples for other sdk's that support middleware */} - #### Middleware-based redirects -For `auth.protect()`, signed-out users will be redirected to the sign-in page. In the following example, `pending` users will be redirected to the sign-in page, where the `` component will prompt them to fulfill the session tasks, which in this case is selecting or creating an organization. Once finished, their session will move from `pending` to an `active` (signed-in) state. - -```tsx {{ filename: 'middleware.ts', mark: [[6, 8]] }} -import { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server' - -const isProtectedRoute = createRouteMatcher(['/dashboard(.*)', '/forum(.*)']) - -export default clerkMiddleware(async (auth, req) => { - // pending users won't be able to access protected routes - // and will be redirected to the sign-in page - if (isProtectedRoute(req)) await auth.protect() -}) - -export const config = { - matcher: [ - // Skip Next.js internals and all static files, unless found in search params - '/((?!_next|[^?]*\\.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest)).*)', - // Always run for API routes - '/(api|trpc)(.*)', - ], -} -``` - -For `auth().isAuthenticated`, it would return `false` if the user has a `pending` session. Pending users will be redirected to the sign-in page, where the `` component will prompt them to fulfill the session tasks. Once finished, their session will move from `pending` to a `signed-in` state. - -```tsx {{ filename: 'app/middleware.ts', mark: [[6, 12]] }} -import { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server' +You can use the `isAuthenticated` property in middleware to protect routes. By default, it will return `false` if the user has a `pending` session. Then, you can handle how to respond to pending users, such as redirecting them to the sign-in page using the `redirectToSignIn()` method. +```tsx const isProtectedRoute = createRouteMatcher(['/dashboard(.*)', '/forum(.*)']) export default clerkMiddleware(async (auth, req) => { const { isAuthenticated, redirectToSignIn } = await auth() // `isAuthenticated` will be `false` for pending users - // and they will be redirected to the sign-in page + // and pending users won't be able to access protected routes if (!isAuthenticated && isProtectedRoute(req)) { + // Add logic to handle pending users + // This example redirects pending users to the sign-in page + // so they can fulfill the session tasks return redirectToSignIn() } }) - -export const config = { - matcher: [ - // Skip Next.js internals and all static files, unless found in search params - '/((?!_next|[^?]*\\.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest)).*)', - // Always run for API routes - '/(api|trpc)(.*)', - ], -} ``` + + For `auth.protect()`, signed-out users will be redirected to the sign-in page. In the following example, `pending` users will be redirected to the sign-in page, where the `` component will prompt them to fulfill the session tasks. Once finished, their session will move from `pending` to an `active` (signed-in) state. + + ```tsx {{ filename: 'middleware.ts', mark: [[6, 8]] }} + import { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server' + + const isProtectedRoute = createRouteMatcher(['/dashboard(.*)', '/forum(.*)']) + + export default clerkMiddleware(async (auth, req) => { + // pending users won't be able to access protected routes + // and will be redirected to the sign-in page + if (isProtectedRoute(req)) await auth.protect() + }) + + export const config = { + matcher: [ + // Skip Next.js internals and all static files, unless found in search params + '/((?!_next|[^?]*\\.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest)).*)', + // Always run for API routes + '/(api|trpc)(.*)', + ], + } + ``` + + ### Session handling By default, `pending` sessions are treated as signed-out across Clerk's authentication context. Some control components and authentication utilities accept a `treatPendingAsSignedOut` prop to control how `pending` sessions are handled: @@ -280,7 +255,7 @@ By default, `pending` sessions are treated as signed-out across Clerk's authenti #### Authentication utilities -The `useAuth()` hook and helpers that access the [`auth` object](/docs/reference/backend/types/auth-object), such as `getAuth()` or `request.auth`, will return `null` if the user has a `pending` session. Most utilities accept a `treatPendingAsSignedOut` option that defaults to `true`. You can pass `false` to treat `pending` sessions as signed-in. +The `useAuth()` hook and helpers that access the [`Auth` object](/docs/reference/backend/types/auth-object), such as `getAuth()` or `request.auth`, will return `null` if the user has a `pending` session. Most utilities accept a `treatPendingAsSignedOut` option that defaults to `true`. You can pass `false` to treat `pending` sessions as signed-in. ##### Example: Personal accounts disabled @@ -309,57 +284,62 @@ export default function Dashboard() { } ``` - - For `auth()`, `isAuthenticated` would return `false` and `userId` and `orgId` would return `null` if the user has a `pending` session. - - ```tsx {{ filename: 'app/page.tsx' }} - import { auth } from '@clerk/nextjs/server' +For helpers that access the [`Auth` object](/docs/reference/backend/types/auth-object), `isAuthenticated` would return `false` and `userId` and `orgId` would return `null` if the user has a `pending` session. This example uses the Next.js-specific `auth()` helper, but can be adapted to other SDKs. - export default async function Page() { - const { isAuthenticated, userId, orgId } = await auth() +```tsx {{ filename: 'app/page.tsx' }} +import { auth } from '@clerk/nextjs/server' - if (!isAuthenticated) { - return ( -

- User has no session, or has a pending session. They either need to sign in, or they need to - complete pending session tasks by selecting or creating an organization. -

- ) - } +export default async function Page() { + // The `Auth` object gives you access to properties like `isAuthenticated` and `userId` + // Accessing the `Auth` object differs depending on the SDK you're using + // https://clerk.com/docs/reference/backend/types/auth-object#how-to-access-the-auth-object + const { isAuthenticated, userId, orgId } = await auth() + if (!isAuthenticated) { return (

- User {userId} has a valid session and {orgId} is defined + User has no session, or has a pending session. They either need to sign in, or they need to + complete pending session tasks by selecting or creating an organization.

) } - ``` - By default, users with a `pending` session are treated as signed-out, and their `userId` will not be available. However, in some cases, you may want to access the user's ID even if their session is still `pending`. In these cases, you can set `treatPendingAsSignedOut` to `false`, which will treat `pending` sessions as signed-in and allow you to access the `userId`. + return ( +

+ User {userId} has a valid session and {orgId} is defined +

+ ) +} +``` - ```tsx {{ filename: 'app/api/get-teams/route.tsx' }} - import { auth } from '@clerk/nextjs/server' +##### Example: Accessing the `userId` for pending sessions - export const POST = async () => { - // `treatPendingAsSignedOut` is set to `false` to allow access to the `userId` for pending sessions - const { isAuthenticated, userId, has } = await auth({ treatPendingAsSignedOut: false }) +By default, users with a `pending` session are treated as signed-out, and their `userId` will not be available. However, in some cases, you may want to access the user's ID even if their session is still `pending`. In these cases, you can set `treatPendingAsSignedOut` to `false`, which will treat `pending` sessions as signed-in and allow you to access the `userId`. - // Check if the user is signed-out - if (!isAuthenticated) { - return Response.json({ error: 'User is signed-out' }, { status: 401 }) - } +```tsx {{ filename: 'app/api/get-teams/route.tsx' }} +import { auth } from '@clerk/nextjs/server' - // Now the pending user's `userId` can be used for your use case - // This is a basic example of creating a resource using the `userId` - try { - const newResource = await resources.create({ - userId, - }) +export const POST = async () => { + // `treatPendingAsSignedOut` is set to `false` to allow access to the `userId` for pending sessions + // Accessing the `Auth` object differs depending on the SDK you're using + // https://clerk.com/docs/reference/backend/types/auth-object#how-to-access-the-auth-object + const { isAuthenticated, userId, has } = await auth({ treatPendingAsSignedOut: false }) - return Response.json({ data: newResource }, { status: 201 }) - } catch (error) { - return Response.json({ error: 'Failed to create resource' }, { status: 500 }) - } + // Check if the user is signed-out + if (!isAuthenticated) { + return Response.json({ error: 'User is signed-out' }, { status: 401 }) } - ``` -
+ + // Now the pending user's `userId` can be used for your use case + // This is a basic example of creating a resource using the `userId` + try { + const newResource = await resources.create({ + userId, + }) + + return Response.json({ data: newResource }, { status: 201 }) + } catch (error) { + return Response.json({ error: 'Failed to create resource' }, { status: 500 }) + } +} +``` diff --git a/docs/guides/organizations/metadata.mdx b/docs/guides/organizations/metadata.mdx index d6c2d78db0..24f185ef12 100644 --- a/docs/guides/organizations/metadata.mdx +++ b/docs/guides/organizations/metadata.mdx @@ -32,6 +32,6 @@ There are two ways to set organization metadata: ### Using the JS Backend SDK -To ease the flow of setting metadata, Clerk provides the `updateOrganizationMetadata()` and `updateOrganizationMembershipMetadata()` methods from the [JS Backend](/docs/js-backend/getting-started/quickstart), which is a wrapper around the [Backend API](/docs/reference/backend-api){{ target: '_blank' }}. +To ease the flow of setting metadata, Clerk provides the `updateOrganizationMetadata()` and `updateOrganizationMembershipMetadata()` methods from the [JS Backend SDK](/docs/js-backend/getting-started/quickstart), which is a wrapper around the [Backend API](/docs/reference/backend-api){{ target: '_blank' }}. diff --git a/docs/guides/sessions/customize-session-tokens.mdx b/docs/guides/sessions/customize-session-tokens.mdx index 44165444b8..547f6ab058 100644 --- a/docs/guides/sessions/customize-session-tokens.mdx +++ b/docs/guides/sessions/customize-session-tokens.mdx @@ -23,7 +23,7 @@ This guide will show you how to customize a session token to include additional ## Use the custom claims in your application - The [`Auth`](/docs/reference/backend/types/auth-object) object includes a `sessionClaims` property that contains the custom claims you added to your session token. Accessing the `Auth` object differs depending on the framework you are using. See the [reference doc](/docs/reference/backend/types/auth-object) for more information. + The [`Auth`](/docs/reference/backend/types/auth-object) object includes a `sessionClaims` property that contains the custom claims you added to your session token. **Accessing the `Auth` object differs depending on the SDK you're using. See the [reference doc](/docs/reference/backend/types/auth-object) for more information.** The following example demonstrates how to access the `fullName` and `primaryEmail` claims that were added to the session token in the last step. @@ -37,7 +37,12 @@ This guide will show you how to customize a session token to include additional import { NextResponse } from 'next/server' export async function GET() { - const { sessionClaims } = await auth() + // Use `auth()` to access the user's session claims + const { isAuthenticated, sessionClaims } = await auth() + + if (!isAuthenticated) { + return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }) + } const fullName = sessionClaims.fullName @@ -52,8 +57,12 @@ This guide will show you how to customize a session token to include additional import type { NextApiRequest, NextApiResponse } from 'next' export default async function handler(req: NextApiRequest, res: NextApiResponse) { - // Use `getAuth()` to access `isAuthenticated` and the user's ID and session claims - const { sessionClaims } = getAuth(req) + // Use `getAuth()` to access the user's session claims + const { isAuthenticated, sessionClaims } = getAuth(req) + + if (!isAuthenticated) { + return res.status(401).json({ error: 'Unauthorized' }) + } const fullName = sessionClaims.fullName @@ -72,8 +81,8 @@ This guide will show you how to customize a session token to include additional import type { APIRoute } from 'astro' export const GET: APIRoute = async ({ locals }) => { - // Use `locals.auth()` to access `isAuthenticated` and the user's ID and session claims - const { isAuthenticated, userId, sessionClaims } = await locals.auth() + // Use `locals.auth()` to access the user's session claims + const { isAuthenticated, sessionClaims } = await locals.auth() // Protect the route by checking if the user is signed in if (!isAuthenticated) { @@ -102,9 +111,13 @@ This guide will show you how to customize a session token to include additional // Apply `clerkMiddleware()` to all routes app.use(clerkMiddleware()) - // Use `getAuth()` to get the session claims const getSessionClaims = (req, res, next) => { - const { sessionClaims } = getAuth(req) + // Use `getAuth()` to access the user's session claims + const { isAuthenticated, sessionClaims } = getAuth(req) + + if (!isAuthenticated) { + return res.status(401).json({ error: 'Unauthorized' }) + } const fullName = sessionClaims.fullName @@ -195,8 +208,8 @@ This guide will show you how to customize a session token to include additional import type { Route } from './+types/profile' export async function loader(args: Route.LoaderArgs) { - // Use `getAuth()` to access `isAuthenticated` and the user's ID and session claims - const { isAuthenticated, userId, sessionClaims } = await getAuth(args) + // Use `getAuth()` to access the user's session claims + const { isAuthenticated, sessionClaims } = await getAuth(args) // Protect the route by checking if the user is signed in if (!isAuthenticated) { @@ -233,8 +246,8 @@ This guide will show you how to customize a session token to include additional import { createClerkClient } from '@clerk/remix/api.server' export const loader: LoaderFunction = async (args) => { - // Use `getAuth()` to access `isAuthenticated` and the user's ID and session claims - const { isAuthenticated, userId, sessionClaims } = await getAuth(args) + // Use `getAuth()` to access the user's session claims + const { isAuthenticated, sessionClaims } = await getAuth(args) // Protect the route by checking if the user is signed in if (!isAuthenticated) { @@ -260,8 +273,8 @@ This guide will show you how to customize a session token to include additional export const ServerRoute = createServerFileRoute().methods({ GET: async ({ request, params }) => { - // Use `getAuth()` to access `isAuthenticated` and the user's ID and session claims - const { isAuthenticated, userId, sessionClaims } = await getAuth(request) + // Use `getAuth()` to access the user's session claims + const { isAuthenticated, sessionClaims } = await getAuth(request) // Protect the API route by checking if the user is signed in if (!isAuthenticated) { diff --git a/docs/guides/sessions/manual-jwt-verification.mdx b/docs/guides/sessions/manual-jwt-verification.mdx index dd017cf950..a16c3d8511 100644 --- a/docs/guides/sessions/manual-jwt-verification.mdx +++ b/docs/guides/sessions/manual-jwt-verification.mdx @@ -11,9 +11,45 @@ For every request, you must validate the token to ensure it hasn't expired or be The [`authenticateRequest()`](/docs/reference/backend/authenticate-request) method from the JS Backend SDK accepts the `request` object and authenticates the session token in it. -The following example uses the `authenticateRequest()` method to verify the session token. It also performs networkless authentication by passing `jwtKey`. This verifies if the user is signed into the application. For more information, including usage with higher-level SDKs, see the [`authenticateRequest()` reference](/docs/reference/backend/authenticate-request). +The following example uses the `authenticateRequest()` method to verify the session token. It also performs networkless authentication by passing `jwtKey`. This verifies if the user is signed into the application. - + + + If you are using the [JS Backend SDK](/docs/js-backend/getting-started/quickstart) on its own, you need to provide the `secretKey` and `publishableKey` to `createClerkClient()` so that it is passed to `authenticateRequest()`. You can set these values as [environment variables](/docs/guides/development/clerk-environment-variables#clerk-publishable-and-secret-keys) and then pass them to the function. + + + + + + `authenticateRequest()` requires `publishableKey` to be set. If you are importing `clerkClient` from a higher-level SDK, such as Next.js, then `clerkClient` infers the `publishableKey` from your [environment variables](/docs/guides/development/clerk-environment-variables#clerk-publishable-and-secret-keys). **The following example uses Next.js, but you can use the comments in the example to help you adapt it to other SDKs.** + + ```tsx + import { clerkClient } from '@clerk/nextjs/server' + + // Initialize the JS Backend SDK + // This varies depending on the SDK you're using + // https://clerk.com/docs/js-backend/getting-started/quickstart + const client = await clerkClient() + + export async function GET(req: Request) { + // Use the `authenticateRequest()` method to verify the token + const { isAuthenticated } = await client.authenticateRequest(req, { + authorizedParties: ['https://example.com'], + jwtKey: process.env.CLERK_JWT_KEY, + }) + + // Protect the route from unauthenticated users + if (!isAuthenticated) { + return Response.json({ status: 401 }) + } + + // Add logic to perform protected actions + + return Response.json({ message: 'This is a reply' }) + } + ``` + + ## Manually verify a session token diff --git a/docs/guides/sessions/session-tokens.mdx b/docs/guides/sessions/session-tokens.mdx index d5179e7cb2..cbf677f6eb 100644 --- a/docs/guides/sessions/session-tokens.mdx +++ b/docs/guides/sessions/session-tokens.mdx @@ -176,6 +176,8 @@ You could store only the necessary data in the session token - for example, just Then, when you need to access the other metadata fields, you can fetch them using a separate API call from your backend. The following example uses the [`getUser()`](/docs/reference/backend/user/get-user) method to access the current user's [Backend `User` object](/docs/reference/backend/types/backend-user), which includes the `publicMetadata` field. +**If your SDK isn't listed, you can use the comments in the example to help you adapt it to your SDK.** + @@ -183,7 +185,9 @@ Then, when you need to access the other metadata fields, you can fetch them usin import { auth, clerkClient } from '@clerk/nextjs/server' export async function GET() { - // Use `auth()` to access `isAuthenticated` and the user's ID + // The `Auth` object gives you access to properties like `isAuthenticated` and `userId` + // Accessing the `Auth` object differs depending on the SDK you're using + // https://clerk.com/docs/reference/backend/types/auth-object#how-to-access-the-auth-object const { isAuthenticated, userId } = await auth() // Protect the route by checking if the user is signed in @@ -191,9 +195,12 @@ Then, when you need to access the other metadata fields, you can fetch them usin return new NextResponse('Unauthorized', { status: 401 }) } + // Initialize the JS Backend SDK + // This varies depending on the SDK you're using + // https://clerk.com/docs/js-backend/getting-started/quickstart const client = await clerkClient() - // Use the JS Backend SDK's `getUser()` method to get the Backend User object + // Use the`getUser()` method to get the Backend User object const user = await client.users.getUser(userId) // Return the Backend User object @@ -210,7 +217,9 @@ Then, when you need to access the other metadata fields, you can fetch them usin import { clerkClient } from '@clerk/astro/server' export async function GET(context) { - // Use `locals.auth()` to access `isAuthenticated` and the user's ID + // The `Auth` object gives you access to properties like `isAuthenticated` and `userId` + // Accessing the `Auth` object differs depending on the SDK you're using + // https://clerk.com/docs/reference/backend/types/auth-object#how-to-access-the-auth-object const { isAuthenticated, userId } = context.locals.auth() // Protect the route by checking if the user is signed in @@ -218,7 +227,10 @@ Then, when you need to access the other metadata fields, you can fetch them usin return new Response('Unauthorized', { status: 401 }) } - // Use the JS Backend SDK's `getUser()` method to get the Backend User object + // Initialize the JS Backend SDK + // This varies depending on the SDK you're using + // https://clerk.com/docs/js-backend/getting-started/quickstart + // Use the `getUser()` method to get the Backend User object const user = await clerkClient(context).users.getUser(userId) // Return the Backend User object @@ -236,7 +248,9 @@ Then, when you need to access the other metadata fields, you can fetch them usin const clerkClient = createClerkClient({ secretKey: process.env.CLERK_SECRET_KEY }) app.get('/user', async (req, res) => { - // Use `getAuth()` to access `isAuthenticated` and the user's ID + // The `Auth` object gives you access to properties like `isAuthenticated` and `userId` + // Accessing the `Auth` object differs depending on the SDK you're using + // https://clerk.com/docs/reference/backend/types/auth-object#how-to-access-the-auth-object const { isAuthenticated, userId } = getAuth(req) // Protect the route by checking if the user is signed in @@ -244,7 +258,10 @@ Then, when you need to access the other metadata fields, you can fetch them usin res.status(401).json({ error: 'User not authenticated' }) } - // Use the JS Backend SDK's `getUser()` method to get the Backend User object + // Initialize the JS Backend SDK + // This varies depending on the SDK you're using + // https://clerk.com/docs/js-backend/getting-started/quickstart + // Use the `getUser()` method to get the Backend User object const user = await clerkClient.users.getUser(userId) // Return the Backend User object @@ -261,7 +278,9 @@ Then, when you need to access the other metadata fields, you can fetch them usin import type { Route } from './+types/profile' export async function loader(args: Route.LoaderArgs) { - // Use `getAuth()` to access `isAuthenticated` and the user's ID + // The `Auth` object gives you access to properties like `isAuthenticated` and `userId` + // Accessing the `Auth` object differs depending on the SDK you're using + // https://clerk.com/docs/reference/backend/types/auth-object#how-to-access-the-auth-object const { isAuthenticated, userId } = await getAuth(args) // Protect the route by checking if the user is signed in @@ -269,7 +288,10 @@ Then, when you need to access the other metadata fields, you can fetch them usin return redirect('/sign-in?redirect_url=' + args.request.url) } - // Use the JS Backend SDK's `getUser()` method to get the Backend User object + // Initialize the JS Backend SDK + // This varies depending on the SDK you're using + // https://clerk.com/docs/js-backend/getting-started/quickstart + // Use the `getUser()` method to get the Backend User object const user = await createClerkClient({ secretKey: process.env.CLERK_SECRET_KEY }).users.getUser( userId, ) @@ -290,15 +312,20 @@ Then, when you need to access the other metadata fields, you can fetch them usin import { createClerkClient } from '@clerk/remix/api.server' export const loader: LoaderFunction = async (args) => { - // Use `getAuth()` to access `isAuthenticated` and the user's ID + // The `Auth` object gives you access to properties like `isAuthenticated` and `userId` + // Accessing the `Auth` object differs depending on the SDK you're using + // https://clerk.com/docs/reference/backend/types/auth-object#how-to-access-the-auth-object const { isAuthenticated, userId } = await getAuth(args) - // If there is no userId, then redirect to sign-in route + // Protect the route from unauthenticated users if (!isAuthenticated) { return redirect('/sign-in?redirect_url=' + args.request.url) } - // Use the JS Backend SDK's `getUser()` method to get the Backend User object + // Initialize the JS Backend SDK + // This varies depending on the SDK you're using + // https://clerk.com/docs/js-backend/getting-started/quickstart + // Use the `getUser()` method to get the Backend User object const user = await createClerkClient({ secretKey: process.env.CLERK_SECRET_KEY }).users.getUser( userId, ) @@ -314,24 +341,26 @@ Then, when you need to access the other metadata fields, you can fetch them usin import { createClerkClient } from '@clerk/remix/api.server' export const action: ActionFunction = async (args) => { - // Use `getAuth()` to access `isAuthenticated` and the user's ID + // The `Auth` object gives you access to properties like `isAuthenticated` and `userId` + // Accessing the `Auth` object differs depending on the SDK you're using + // https://clerk.com/docs/reference/backend/types/auth-object#how-to-access-the-auth-object const { isAuthenticated, userId } = await getAuth(args) - // If there is no userId, then redirect to sign-in route + // Protect the route from unauthenticated users if (!isAuthenticated) { return redirect('/sign-in?redirect_url=' + args.request.url) } - // Prepare the data for the mutation - const params = { firstName: 'John', lastName: 'Wicker' } - - // // Use the JS Backend SDK's `updateUser()` method to update the Backend User object - const updatedUser = await createClerkClient({ + // Initialize the JS Backend SDK + // This varies depending on the SDK you're using + // https://clerk.com/docs/js-backend/getting-started/quickstart + // Use the `getUser()` method to get the Backend User object + const user = await createClerkClient({ secretKey: process.env.CLERK_SECRET_KEY, - }).users.updateUser(userId, params) + }).users.getUser(userId) - // Return the updated user - return { serialisedUser: JSON.stringify(updatedUser) } + // Return the Backend User object + return { serialisedUser: JSON.stringify(user) } } ``` @@ -346,7 +375,9 @@ Then, when you need to access the other metadata fields, you can fetch them usin export const Route = createAPIFileRoute('/api/example')({ GET: async ({ request, params }) => { - // Use `getAuth()` to access `isAuthenticated` and the user's ID + // The `Auth` object gives you access to properties like `isAuthenticated` and `userId` + // Accessing the `Auth` object differs depending on the SDK you're using + // https://clerk.com/docs/reference/backend/types/auth-object#how-to-access-the-auth-object const { isAuthenticated, userId } = await getAuth(req) // Protect the route by checking if the user is signed in @@ -354,10 +385,12 @@ Then, when you need to access the other metadata fields, you can fetch them usin return json({ error: 'Unauthorized' }, { status: 401 }) } - // Instantiate the JS Backend SDK + // Initialize the JS Backend SDK + // This varies depending on the SDK you're using + // https://clerk.com/docs/js-backend/getting-started/quickstart const clerkClient = createClerkClient({ secretKey: import.meta.env.CLERK_SECRET_KEY }) - // Use the JS Backend SDK's `getUser()` method to get the Backend User object + // Use the `getUser()` method to get the Backend User object const user = await clerkClient.users.getUser(userId) // Return the Backend User object diff --git a/docs/guides/users/impersonation.mdx b/docs/guides/users/impersonation.mdx index fdf668eac3..5c00f8a42e 100644 --- a/docs/guides/users/impersonation.mdx +++ b/docs/guides/users/impersonation.mdx @@ -79,7 +79,7 @@ Clerk also adds an `act` claim on the [Clerk session token](/docs/guides/session To detect impersonated sessions in the frontend, the `actor` object contains the `sub` claim of the impersonator. You can use this information to detect impersonated sessions. - + You can use the [`useAuth()`](/docs/reference/hooks/use-auth) hook to get access to the authentication context, which includes the `actor` object. @@ -126,7 +126,7 @@ To detect impersonated sessions in the frontend, the `actor` object contains the ### Detect impersonated sessions in the backend -The [`Auth`](/docs/reference/backend/types/auth-object) object is a server-side object that contains the `actor` object, as well as important information like the current user's session ID and user ID. Accessing the `Auth` object differs [depending on the SDK you're using](/docs/reference/backend/types/auth-object#how-to-access-the-auth-object). Here are some examples: +The [`Auth`](/docs/reference/backend/types/auth-object) object is a server-side object that contains the `actor` object, as well as important information like the current user's session ID and user ID. **Accessing the `Auth` object differs [depending on the SDK you're using](/docs/reference/backend/types/auth-object#how-to-access-the-auth-object).** Here are some examples: @@ -136,7 +136,9 @@ The [`Auth`](/docs/reference/backend/types/auth-object) object is a server-side import { auth } from '@clerk/nextjs/server' export default async function Page() { - // Use Clerk's `auth()` helper to access the `Auth` object + // The `Auth` object gives you access to properties like `userId` and `actor` + // Accessing the `Auth` object differs depending on the SDK you're using + // https://clerk.com/docs/reference/backend/types/auth-object#how-to-access-the-auth-object const { userId, actor } = await auth() return ( diff --git a/docs/guides/users/managing.mdx b/docs/guides/users/managing.mdx index e0cc38b290..9e5385f0a4 100644 --- a/docs/guides/users/managing.mdx +++ b/docs/guides/users/managing.mdx @@ -33,7 +33,7 @@ Depending on the level of abstraction you need, you can manage users in the fron The [JS Backend SDK](/docs/js-backend/getting-started/quickstart) exposes the [Backend API](/docs/reference/backend-api){{ target: '_blank' }} resources and low-level authentication utilities for JavaScript environments. -There are many operations available for managing users, such as `getUser()`, `createUser()`, and `deleteUser()`. For more information, see the [JS Backend reference docs](/docs/js-backend/getting-started/quickstart). +There are many operations available for managing users, such as `getUser()`, `createUser()`, and `deleteUser()`. For more information, see the [JS Backend SDK reference docs](/docs/js-backend/getting-started/quickstart). ## Create users diff --git a/docs/guides/users/reading.mdx b/docs/guides/users/reading.mdx index 445e9bb02b..3e0ee5c641 100644 --- a/docs/guides/users/reading.mdx +++ b/docs/guides/users/reading.mdx @@ -76,7 +76,7 @@ In some cases, you may need the full [`Backend User`](/docs/reference/backend/ty The `clerkClient()` helper returns an instance of the [JS Backend SDK](/docs/js-backend/getting-started/quickstart), which exposes Clerk's Backend API resources through methods such as the [`getUser()`](/docs/reference/backend/user/get-user){{ target: '_blank' }} method. This method returns the full `Backend User` object. -In the following example, the `userId` is passed to the Backend SDK's `getUser()` method to get the user's full `Backend User` object. +In the following example, the `userId` is passed to the JS Backend SDK's `getUser()` method to get the user's full `Backend User` object. diff --git a/docs/guides/users/reading.remix.mdx b/docs/guides/users/reading.remix.mdx index 70aeb974ab..0830c4d942 100644 --- a/docs/guides/users/reading.remix.mdx +++ b/docs/guides/users/reading.remix.mdx @@ -12,9 +12,9 @@ Clerk provides a set of [hooks and helpers](/docs/reference/remix/overview) that ### `getAuth()` -The [`getAuth()`](/docs/reference/remix/overview#get-auth) helper allows you to access the [`Auth` object](/docs/reference/backend/types/auth-object){{ target: '_blank' }}, which includes the current user's `userId` and the `isAuthenticated` property, which can be used to protect your routes. +The [`getAuth()`](/docs/reference/remix/overview#get-auth) helper allows you to access the [`Auth` object](/docs/reference/backend/types/auth-object), which includes the current user's `userId` and the `isAuthenticated` property, which can be used to protect your routes. -In the following example, the `userId` is passed to the JS Backend SDK's [`getUser()`](/docs/reference/backend/user/get-user){{ target: '_blank' }} method to get the user's full `User` object. For information on how to use the JS Backend SDK, see the [JS Backend documentation](/docs/js-backend/getting-started/quickstart){{ target: '_blank' }}. +In the following example, the `userId` is passed to the JS Backend SDK's [`getUser()`](/docs/reference/backend/user/get-user) method to get the user's full `User` object. For information on how to use the JS Backend SDK, see the [reference documentation](/docs/js-backend/getting-started/quickstart). diff --git a/docs/reference/astro/clerk-middleware.mdx b/docs/reference/astro/clerk-middleware.mdx index dc3b174e0e..262b6da935 100644 --- a/docs/reference/astro/clerk-middleware.mdx +++ b/docs/reference/astro/clerk-middleware.mdx @@ -45,7 +45,7 @@ import { clerkMiddleware, createRouteMatcher } from '@clerk/astro/server' const isProtectedRoute = createRouteMatcher(['/dashboard(.*)', '/forum(.*)']) export const onRequest = clerkMiddleware((auth, context) => { - const { isAuthenticated, redirectToSignIn, userId } = auth() + const { isAuthenticated, redirectToSignIn } = auth() if (!isAuthenticated && isProtectedRoute(context.request)) { // Add custom logic to run before redirecting diff --git a/docs/reference/backend/authenticate-request.mdx b/docs/reference/backend/authenticate-request.mdx index df4cad9353..dcbe92ecf0 100644 --- a/docs/reference/backend/authenticate-request.mdx +++ b/docs/reference/backend/authenticate-request.mdx @@ -109,7 +109,7 @@ It is recommended to set these options as [environment variables](/docs/guides/d ## Examples - + If you are using the [JS Backend SDK](/docs/js-backend/getting-started/quickstart) on its own, you need to provide the `secretKey` and `publishableKey` to `createClerkClient()` so that it is passed to `authenticateRequest()`. You can set these values as [environment variables](/docs/guides/development/clerk-environment-variables#clerk-publishable-and-secret-keys) and then pass them to the function. @@ -138,23 +138,27 @@ It is recommended to set these options as [environment variables](/docs/guides/d - `authenticateRequest()` requires `publishableKey` to be set. If you are importing `clerkClient` from a higher-level SDK, such as Next.js, then `clerkClient` infers the `publishableKey` from your [environment variables](/docs/guides/development/clerk-environment-variables#clerk-publishable-and-secret-keys). The following example uses Next.js, but the same logic applies for other frameworks. + `authenticateRequest()` requires `publishableKey` to be set. If you are importing `clerkClient` from a higher-level SDK, such as Next.js, then `clerkClient` infers the `publishableKey` from your [environment variables](/docs/guides/development/clerk-environment-variables#clerk-publishable-and-secret-keys). **The following example uses Next.js, but you can use the comments in the example to help you adapt it to other SDKs.** ```tsx import { clerkClient } from '@clerk/nextjs/server' + // Initialize the JS Backend SDK + // This varies depending on the SDK you're using + // https://clerk.com/docs/js-backend/getting-started/quickstart const client = await clerkClient() export async function GET(req: Request) { + // Use the `authenticateRequest()` method to verify the token const { isAuthenticated } = await client.authenticateRequest(req, { authorizedParties: ['https://example.com'], }) + // Protect the route from unauthenticated users if (!isAuthenticated) { return Response.json({ status: 401 }) } - // Perform protected actions // Add logic to perform protected actions return Response.json({ message: 'This is a reply' }) @@ -167,31 +171,68 @@ It is recommended to set these options as [environment variables](/docs/guides/d By default, `authenticateRequest()` will authenticate a session request. To authenticate a machine request, you need to set the `acceptsToken` option to a machine token type, such as `'api_key'`, `'oauth_token'` or `'m2m_token'`. -```tsx -import { createClerkClient } from '@clerk/backend' + + + ```tsx + import { createClerkClient } from '@clerk/backend' + + export async function GET(request: Request) { + // Initialize the JS Backend SDK + // This varies depending on the SDK you're using + // https://clerk.com/docs/js-backend/getting-started/quickstart + const clerkClient = createClerkClient({ + secretKey: process.env.CLERK_SECRET_KEY, + publishableKey: process.env.CLERK_PUBLISHABLE_KEY, + }) -export async function GET(request: Request) { - const clerkClient = createClerkClient({ - secretKey: process.env.CLERK_SECRET_KEY, - publishableKey: process.env.CLERK_PUBLISHABLE_KEY, - }) + // Use the `authenticateRequest()` method to verify the token + const { isAuthenticated } = await clerkClient.authenticateRequest(request, { + acceptsToken: 'oauth_token', + }) - const { isAuthenticated } = await clerkClient.authenticateRequest(request, { - acceptsToken: 'oauth_token', - }) + // Protect the route from unauthenticated users + if (!isAuthenticated) { + return Response.json({ status: 401 }) + } - if (!isAuthenticated) { - return Response.json({ status: 401 }) - } + // Add logic to perform protected actions - // Add logic to perform protected actions - return Response.json({ message: 'This is a machine-to-machine reply' }) -} -``` + return Response.json({ message: 'This is a machine-to-machine reply' }) + } + ``` + -### Networkless token verification + + **This example uses Next.js, but you can use the comments in the example to help you adapt it to other SDKs.** -{/* Note: this example is duped from /authenticate-request. Probably a good opportunity to use a partial here */} + ```tsx + import { clerkClient } from '@clerk/nextjs/server' + + // Initialize the JS Backend SDK + // This varies depending on the SDK you're using + // https://clerk.com/docs/js-backend/getting-started/quickstart + const client = await clerkClient() + + export async function GET(req: Request) { + // Use the `authenticateRequest()` method to verify the token + const { isAuthenticated } = await client.authenticateRequest(request, { + acceptsToken: 'oauth_token', + }) + + // Protect the route from unauthenticated users + if (!isAuthenticated) { + return Response.json({ status: 401 }) + } + + // Add logic to perform protected actions + + return Response.json({ message: 'This is a machine-to-machine reply' }) + } + ``` + + + +### Networkless token verification The following example uses the `authenticateRequest()` method with the [JS Backend SDK](/docs/js-backend/getting-started/quickstart) to verify the token passed by the frontend, and performs a networkless authentication by passing `jwtKey`. This will verify if the user is signed into the application or not.