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/guides/configure/auth-strategies/social-connections/overview.mdx b/docs/guides/configure/auth-strategies/social-connections/overview.mdx index cee32f922c..57195e8823 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/references/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/references/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/references/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/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/secure/session-tasks.mdx b/docs/guides/secure/session-tasks.mdx index 3d1ff322c0..2f762c6ae0 100644 --- a/docs/guides/secure/session-tasks.mdx +++ b/docs/guides/secure/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,40 +70,25 @@ 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/references/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 @@ -130,34 +113,9 @@ export default function Layout({ children }: { children: React.ReactNode }) { #### 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' - +```tsx const isProtectedRoute = createRouteMatcher(['/dashboard(.*)', '/forum(.*)']) export default clerkMiddleware(async (auth, req) => { @@ -169,17 +127,33 @@ export default clerkMiddleware(async (auth, req) => { 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, 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)(.*)', + ], + } + ``` + + ### 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: diff --git a/docs/guides/sessions/customize-session-tokens.mdx b/docs/guides/sessions/customize-session-tokens.mdx index 0a17776b8e..3c7ddae0a7 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/references/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/references/backend/types/auth-object) for more information. + The [`Auth`](/docs/references/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/references/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 9e9ffff828..c2cbc28670 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/references/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/references/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 the same logic applies for 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 8c51641027..764bfc5504 100644 --- a/docs/guides/sessions/session-tokens.mdx +++ b/docs/guides/sessions/session-tokens.mdx @@ -150,6 +150,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/references/backend/user/get-user) method to access the current user's [Backend `User` object](/docs/references/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.** + @@ -157,7 +159,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/references/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 @@ -165,9 +169,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 @@ -184,7 +191,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/references/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 @@ -192,7 +201,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 @@ -210,7 +222,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/references/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 @@ -218,7 +232,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 @@ -235,7 +252,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/references/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 @@ -243,7 +262,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, ) @@ -264,15 +286,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/references/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, ) @@ -288,24 +315,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/references/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) } } ``` @@ -320,7 +349,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/references/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 @@ -328,10 +359,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 5383a5835a..8ca11044b7 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/references/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/references/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/references/backend/types/auth-object#how-to-access-the-auth-object). Here are some examples: +The [`Auth`](/docs/references/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/references/backend/types/auth-object#how-to-access-the-auth-object).** Here are some examples: @@ -136,7 +136,9 @@ The [`Auth`](/docs/references/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/references/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 40162df613..1395c17b10 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 7c98ee5404..b151e0f878 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/references/backend/t 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/references/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 0eacbac95f..6afc55cc6d 100644 --- a/docs/guides/users/reading.remix.mdx +++ b/docs/guides/users/reading.remix.mdx @@ -14,7 +14,7 @@ Clerk provides a set of [hooks and helpers](/docs/references/remix/overview) tha The [`getAuth()`](/docs/references/remix/overview#get-auth) helper allows you to access the [`Auth` object](/docs/references/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. -In the following example, the `userId` is passed to the JS Backend SDK's [`getUser()`](/docs/references/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/references/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 SDK documentation](/docs/js-backend/getting-started/quickstart){{ target: '_blank' }}. diff --git a/docs/references/astro/clerk-middleware.mdx b/docs/references/astro/clerk-middleware.mdx index 1131111ba4..74d4b5c7f9 100644 --- a/docs/references/astro/clerk-middleware.mdx +++ b/docs/references/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/references/backend/authenticate-request.mdx b/docs/references/backend/authenticate-request.mdx index 2aebc1e1be..71ab44ad47 100644 --- a/docs/references/backend/authenticate-request.mdx +++ b/docs/references/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 the same logic applies for 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 the same logic applies for other SDKs. You can use the comments in the example to help you adapt it to your SDK. -{/* 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.