From 0b04908d74f491c80edde6dc00d1ee68dafbfb4c Mon Sep 17 00:00:00 2001 From: Mike Wickett Date: Fri, 25 Oct 2024 15:59:30 -0400 Subject: [PATCH 1/7] codeowners: notify growth team on quickstart changes (#1657) --- .github/CODEOWNERS | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index c6be7d0c03..b75bc54b71 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1 +1,4 @@ * @clerk/docs + +# Help keep docs quickstart content in sync with Dashboard +docs/quickstarts/* @clerk/growth \ No newline at end of file From 99dbb01cc45c46f4e2c62b3c97b0b8d1d15ff702 Mon Sep 17 00:00:00 2001 From: victoria Date: Fri, 25 Oct 2024 21:59:58 +0200 Subject: [PATCH 2/7] add js backend sdk guide, deprecated warnings, comments to refactor code (#1654) --- .../handling/js-backend-sdks.mdx | 89 +++++++++++++++++++ docs/manifest.json | 8 +- .../references/backend/sessions/get-token.mdx | 5 ++ docs/references/backend/user/update-user.mdx | 5 ++ docs/upgrade-guides/core-2/backend.mdx | 3 + .../core-2/chrome-extension.mdx | 3 + docs/upgrade-guides/core-2/expo.mdx | 3 + docs/upgrade-guides/core-2/fastify.mdx | 3 + docs/upgrade-guides/core-2/javascript.mdx | 3 + docs/upgrade-guides/core-2/nextjs.mdx | 9 ++ docs/upgrade-guides/core-2/node.mdx | 5 +- docs/upgrade-guides/core-2/react.mdx | 3 + docs/upgrade-guides/core-2/remix.mdx | 3 + docs/users/creating-users.mdx | 5 ++ docs/users/deleting-users.mdx | 5 ++ docs/users/metadata.mdx | 20 +++++ docs/users/user-impersonation.mdx | 5 ++ 17 files changed, 174 insertions(+), 3 deletions(-) create mode 100644 docs/backend-requests/handling/js-backend-sdks.mdx diff --git a/docs/backend-requests/handling/js-backend-sdks.mdx b/docs/backend-requests/handling/js-backend-sdks.mdx new file mode 100644 index 0000000000..587430f4cf --- /dev/null +++ b/docs/backend-requests/handling/js-backend-sdks.mdx @@ -0,0 +1,89 @@ +--- +title: Handling requests with a JS Backend SDK +description: Learn how to handle authenticated requests with one of Clerk's JS Backend SDKs. +--- + +To handle authenticated requests, use one of the following JS Backend SDKs. + +## Clerk Express SDK + +The `clerkMiddleware()` function checks the request's cookies and headers for a session JWT. If the user has a valid session, the `clerkMiddleware()` function attaches the [properties](/docs/references/nextjs/auth-object#auth-object-properties) of the authenticated user to the request object. + +```js +import { clerkMiddleware } from '@clerk/express' + +const app = express() + +// Pass no parameters +app.use(clerkMiddleware()) + +// Pass options +app.use(clerkMiddleware(options)) +``` + +For more information on the Middleware functions and SDK features, see the [Express SDK](/docs/references/express/overview) page. + +## Clerk Fastify SDK + +The `clerkPlugin` checks the request's cookies and headers for a session JWT. If the user has a valid session, the `clerkPlugin` attaches the [properties](/docs/references/nextjs/auth-object#auth-object-properties) of the authenticated user to the request object. + +```ts +import 'dotenv/config' +import Fastify from 'fastify' +import { clerkClient, clerkPlugin, getAuth } from '@clerk/fastify' + +const fastify = Fastify({ logger: true }) + +fastify.register(clerkPlugin) + +fastify.get('/', async (request, reply) => { + const { userId } = getAuth(request) + + // Protect the route from unauthenticated users + if (!userId) { + return reply.code(403).send({ error: 'Unauthorized request.' }) + } + + const user = userId ? await clerkClient.users.getUser(userId) : null + + return reply.send({ + message: 'User retrieved successfully.', + user, + }) +}) + +const start = async () => { + try { + await fastify.listen({ port: 8080 }) + } catch (error) { + fastify.log.error(error) + process.exit(1) + } +} + +start() +``` + +For more information on the Clerk plugin and SDK features, see the [Fastify SDK](/docs/quickstarts/fastify) page. + +## Clerk Backend SDK + +If you're not using Express or Fastify, use the `@clerk/backend` package to access `clerkClient`. + +```ts +import { createClerkClient } from '@clerk/backend' + +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, + authorizedParties: ['https://example.com'], +}) + +if (!isSignedIn) { + return Response.json({ status: 401 }) +} +``` diff --git a/docs/manifest.json b/docs/manifest.json index e3c7551d3a..8ebbfa40f1 100644 --- a/docs/manifest.json +++ b/docs/manifest.json @@ -702,8 +702,8 @@ "items": [ [ { - "title": "Node.js & Express", - "href": "/docs/backend-requests/handling/nodejs" + "title": "JS Backend SDKs", + "href": "/docs/backend-requests/handling/js-backend-sdks" }, { "title": "Go", @@ -718,6 +718,10 @@ { "title": "Manual JWT Verification", "href": "/docs/backend-requests/handling/manual-jwt" + }, + { + "title": "Node.js (Deprecated)", + "href": "/docs/backend-requests/handling/nodejs" } ] ] diff --git a/docs/references/backend/sessions/get-token.mdx b/docs/references/backend/sessions/get-token.mdx index 2990dab33c..3a1cff2e8a 100644 --- a/docs/references/backend/sessions/get-token.mdx +++ b/docs/references/backend/sessions/get-token.mdx @@ -103,6 +103,11 @@ _Token { + > [!CAUTION] + > On January 8, 2025, the Node SDK will no longer be available. [Upgrade to the Express SDK.](/docs/upgrade-guides/node-to-express) + + {/* TODO: Update Node example - SDK is being deprecated */} + ```js {{ filename: 'getToken.ts' }} import { clerkClient } from '@clerk/clerk-sdk-node' diff --git a/docs/references/backend/user/update-user.mdx b/docs/references/backend/user/update-user.mdx index 79142ba8a4..9d943449b4 100644 --- a/docs/references/backend/user/update-user.mdx +++ b/docs/references/backend/user/update-user.mdx @@ -311,6 +311,11 @@ _User { + > [!CAUTION] + > On January 8, 2025, the Node SDK will no longer be available. [Upgrade to the Express SDK.](/docs/upgrade-guides/node-to-express) + + {/* TODO: Update Node example - SDK is being deprecated */} + ```js {{ filename: 'updateUser.js' }} import { clerkClient } from '@clerk/clerk-sdk-node' diff --git a/docs/upgrade-guides/core-2/backend.mdx b/docs/upgrade-guides/core-2/backend.mdx index 540b54caa6..eb0041cef5 100644 --- a/docs/upgrade-guides/core-2/backend.mdx +++ b/docs/upgrade-guides/core-2/backend.mdx @@ -241,6 +241,9 @@ The `orgs` claim was part of the `JwtPayload`. Here are a few examples of where + > [!CAUTION] + > On January 8, 2025, the Node SDK will no longer be available. [Upgrade to the Express SDK.](/docs/upgrade-guides/node-to-express) + ```typescript {{ filename: '@clerk/clerk-sdk-node' }} import { clerkClient } from '@clerk/clerk-sdk-node' diff --git a/docs/upgrade-guides/core-2/chrome-extension.mdx b/docs/upgrade-guides/core-2/chrome-extension.mdx index 3a4b8e898f..8f872bb849 100644 --- a/docs/upgrade-guides/core-2/chrome-extension.mdx +++ b/docs/upgrade-guides/core-2/chrome-extension.mdx @@ -153,6 +153,9 @@ The `orgs` claim was part of the `JwtPayload`. Here are a few examples of where + > [!CAUTION] + > On January 8, 2025, the Node SDK will no longer be available. [Upgrade to the Express SDK.](/docs/upgrade-guides/node-to-express) + ```typescript {{ filename: '@clerk/clerk-sdk-node' }} import { clerkClient } from '@clerk/clerk-sdk-node' diff --git a/docs/upgrade-guides/core-2/expo.mdx b/docs/upgrade-guides/core-2/expo.mdx index 60890d677b..714323a7d0 100644 --- a/docs/upgrade-guides/core-2/expo.mdx +++ b/docs/upgrade-guides/core-2/expo.mdx @@ -133,6 +133,9 @@ The `orgs` claim was part of the `JwtPayload`. Here are a few examples of where + > [!CAUTION] + > On January 8, 2025, the Node SDK will no longer be available. [Upgrade to the Express SDK.](/docs/upgrade-guides/node-to-express) + ```typescript {{ filename: '@clerk/clerk-sdk-node' }} import { clerkClient } from '@clerk/clerk-sdk-node' diff --git a/docs/upgrade-guides/core-2/fastify.mdx b/docs/upgrade-guides/core-2/fastify.mdx index 9daa78684a..b38512e70c 100644 --- a/docs/upgrade-guides/core-2/fastify.mdx +++ b/docs/upgrade-guides/core-2/fastify.mdx @@ -96,6 +96,9 @@ The `orgs` claim was part of the `JwtPayload`. Here are a few examples of where + > [!CAUTION] + > On January 8, 2025, the Node SDK will no longer be available. [Upgrade to the Express SDK.](/docs/upgrade-guides/node-to-express) + ```typescript {{ filename: '@clerk/clerk-sdk-node' }} import { clerkClient } from '@clerk/clerk-sdk-node' diff --git a/docs/upgrade-guides/core-2/javascript.mdx b/docs/upgrade-guides/core-2/javascript.mdx index 3376fc108c..3f3007d448 100644 --- a/docs/upgrade-guides/core-2/javascript.mdx +++ b/docs/upgrade-guides/core-2/javascript.mdx @@ -142,6 +142,9 @@ The `orgs` claim was part of the `JwtPayload`. Here are a few examples of where + > [!CAUTION] + > On January 8, 2025, the Node SDK will no longer be available. [Upgrade to the Express SDK.](/docs/upgrade-guides/node-to-express) + ```typescript {{ filename: '@clerk/clerk-sdk-node' }} import { clerkClient } from '@clerk/clerk-sdk-node' diff --git a/docs/upgrade-guides/core-2/nextjs.mdx b/docs/upgrade-guides/core-2/nextjs.mdx index 205de614d8..36870b6c91 100644 --- a/docs/upgrade-guides/core-2/nextjs.mdx +++ b/docs/upgrade-guides/core-2/nextjs.mdx @@ -439,6 +439,9 @@ As part of this release, some of the top-level exports of `@clerk/nextjs` have b + > [!CAUTION] + > On January 8, 2025, the Node SDK will no longer be available. [Upgrade to the Express SDK.](/docs/upgrade-guides/node-to-express) + The `@clerk/nextjs/api` subpath was removed completely. It re-exported helpers from `@clerk/clerk-sdk-node` and its types. If you relied on these, import from `@clerk/clerk-sdk-node` directly instead. ```js {{ prettier: false, del: [8, 11], ins: [9, 12] }} @@ -526,6 +529,9 @@ The `orgs` claim was part of the `JwtPayload`. Here are a few examples of where + > [!CAUTION] + > On January 8, 2025, the Node SDK will no longer be available. [Upgrade to the Express SDK.](/docs/upgrade-guides/node-to-express) + ```typescript {{ filename: '@clerk/clerk-sdk-node' }} import { clerkClient } from '@clerk/clerk-sdk-node' @@ -737,6 +743,9 @@ As part of this major version, a number of previously deprecated props, argument + > [!CAUTION] + > On January 8, 2025, the Node SDK will no longer be available. [Upgrade to the Express SDK.](/docs/upgrade-guides/node-to-express) + The import subpath `@clerk/nextjs/api` has been removed. This includes the following imports: ```js diff --git a/docs/upgrade-guides/core-2/node.mdx b/docs/upgrade-guides/core-2/node.mdx index e8a377b3f0..9fe7f9d44c 100644 --- a/docs/upgrade-guides/core-2/node.mdx +++ b/docs/upgrade-guides/core-2/node.mdx @@ -1,8 +1,11 @@ --- title: Upgrading `@clerk/clerk-sdk-node` to Core 2 -description: "Learn how to upgrade Clerk's Node SDK to the lastest version." +description: "Learn how to upgrade Clerk's Node SDK to the latest version." --- +> [!CAUTION] +> On January 8, 2025, the Node SDK will no longer be available. [Upgrade to the Express SDK.](/docs/upgrade-guides/node-to-express) + {/* WARNING: This is a generated file and should not be edited directly. To update its contents, see the "upgrade" package in the clerk/javascript repo. */} Core 2 is included in the Node.js SDK starting with version 5. This new version ships with a variety of smaller DX improvements and housekeeping items. Each of the potentially breaking changes are detailed in this guide, below. diff --git a/docs/upgrade-guides/core-2/react.mdx b/docs/upgrade-guides/core-2/react.mdx index 3b9f20d081..a43f719021 100644 --- a/docs/upgrade-guides/core-2/react.mdx +++ b/docs/upgrade-guides/core-2/react.mdx @@ -170,6 +170,9 @@ The `orgs` claim was part of the `JwtPayload`. Here are a few examples of where + > [!CAUTION] + > On January 8, 2025, the Node SDK will no longer be available. [Upgrade to the Express SDK.](/docs/upgrade-guides/node-to-express) + ```typescript {{ filename: '@clerk/clerk-sdk-node' }} import { clerkClient } from '@clerk/clerk-sdk-node' diff --git a/docs/upgrade-guides/core-2/remix.mdx b/docs/upgrade-guides/core-2/remix.mdx index e35866c34c..4af8976f93 100644 --- a/docs/upgrade-guides/core-2/remix.mdx +++ b/docs/upgrade-guides/core-2/remix.mdx @@ -176,6 +176,9 @@ The `orgs` claim was part of the `JwtPayload`. Here are a few examples of where + > [!CAUTION] + > On January 8, 2025, the Node SDK will no longer be available. [Upgrade to the Express SDK.](/docs/upgrade-guides/node-to-express) + ```typescript {{ filename: '@clerk/clerk-sdk-node' }} import { clerkClient } from '@clerk/clerk-sdk-node' diff --git a/docs/users/creating-users.mdx b/docs/users/creating-users.mdx index 5a9f711dfd..fed78dd9ad 100644 --- a/docs/users/creating-users.mdx +++ b/docs/users/creating-users.mdx @@ -40,6 +40,11 @@ To create users using the Clerk API, you can use the [`createUser()`](/docs/refe + > [!CAUTION] + > On January 8, 2025, the Node SDK will no longer be available. [Upgrade to the Express SDK.](/docs/upgrade-guides/node-to-express) + + {/* TODO: Update Node example - SDK is being deprecated */} + ```ts {{ filename: 'create-user.ts' }} import { clerkClient } from '@clerk/clerk-sdk-node' diff --git a/docs/users/deleting-users.mdx b/docs/users/deleting-users.mdx index f7c0018e0b..7f31693dbb 100644 --- a/docs/users/deleting-users.mdx +++ b/docs/users/deleting-users.mdx @@ -38,6 +38,11 @@ To delete users using the Clerk API, you can use the [`deleteUser()`](/docs/refe + > [!CAUTION] + > On January 8, 2025, the Node SDK will no longer be available. [Upgrade to the Express SDK.](/docs/upgrade-guides/node-to-express) + + {/* TODO: Update Node example - SDK is being deprecated */} + ```ts {{ filename: 'delete-user.ts' }} import { clerkClient } from '@clerk/clerk-sdk-node' diff --git a/docs/users/metadata.mdx b/docs/users/metadata.mdx index 043c26e5b9..24b8713a4e 100644 --- a/docs/users/metadata.mdx +++ b/docs/users/metadata.mdx @@ -58,6 +58,11 @@ Private metadata is only accessible by the backend, which makes this useful for + > [!CAUTION] + > On January 8, 2025, the Node SDK will no longer be available. [Upgrade to the Express SDK.](/docs/upgrade-guides/node-to-express) + + {/* TODO: Update Node example - SDK is being deprecated */} + ```ts {{ filename: 'private.ts' }} import { clerkClient } from '@clerk/clerk-sdk-node' @@ -154,6 +159,11 @@ You can retrieve the private metadata for a user by using the [`getUser`](/docs/ + > [!CAUTION] + > On January 8, 2025, the Node SDK will no longer be available. [Upgrade to the Express SDK.](/docs/upgrade-guides/node-to-express) + + {/* TODO: Update Node example - SDK is being deprecated */} + ```ts {{ filename: 'private.ts' }} import { clerkClient } from '@clerk/clerk-sdk-node' @@ -242,6 +252,11 @@ Public metadata is accessible by both the frontend and the backend, but can only + > [!CAUTION] + > On January 8, 2025, the Node SDK will no longer be available. [Upgrade to the Express SDK.](/docs/upgrade-guides/node-to-express) + + {/* TODO: Update Node example - SDK is being deprecated */} + ```ts {{ filename: 'public.ts' }} import { clerkClient } from '@clerk/clerk-sdk-node' @@ -363,6 +378,11 @@ Updating this value overrides the previous value; it does not merge. To perform + > [!CAUTION] + > On January 8, 2025, the Node SDK will no longer be available. [Upgrade to the Express SDK.](/docs/upgrade-guides/node-to-express) + + {/* TODO: Update Node example - SDK is being deprecated */} + ```ts {{ filename: 'private.ts' }} import { clerkClient } from '@clerk/clerk-sdk-node' diff --git a/docs/users/user-impersonation.mdx b/docs/users/user-impersonation.mdx index f29ca8a2f0..2d0a632a3f 100644 --- a/docs/users/user-impersonation.mdx +++ b/docs/users/user-impersonation.mdx @@ -170,6 +170,11 @@ To detect impersonated sessions in the frontend, the `actor` object contains the + > [!CAUTION] + > On January 8, 2025, the Node SDK will no longer be available. [Upgrade to the Express SDK.](/docs/upgrade-guides/node-to-express) + + {/* TODO: Update Node example - SDK is being deprecated */} + The Node.js SDK provides a [middleware](/docs/backend-requests/handling/nodejs) that augments the request object with the authentication context. ```js From a123093a8a226af385b88cdbb65f1758a8700cd1 Mon Sep 17 00:00:00 2001 From: panteliselef Date: Fri, 25 Oct 2024 18:21:59 -0400 Subject: [PATCH 3/7] Update authorization examples (#1651) Co-authored-by: Alexis Aguilar <98043211+alexisintech@users.noreply.github.com> --- .../organizations/verify-user-permissions.mdx | 168 +++++++++++------- docs/references/nextjs/auth.mdx | 142 ++++----------- 2 files changed, 133 insertions(+), 177 deletions(-) diff --git a/docs/organizations/verify-user-permissions.mdx b/docs/organizations/verify-user-permissions.mdx index e0ddc60848..87de1b1c46 100644 --- a/docs/organizations/verify-user-permissions.mdx +++ b/docs/organizations/verify-user-permissions.mdx @@ -4,7 +4,7 @@ description: A collection of utility functions and components in order to allow --- > [!IMPORTANT] -> The following authorization checks are predicated on a user having an active organization. Without this, they will likely always evaluate to false by default. Learn more about [active organizations](/docs/organizations/overview#active-organization). +> The following authorization checks are predicated on a user having an active organization. Without this, they will likely always evaluate to false by default. Learn more about [active organizations](/docs/organizations/overview#active-organization). If you would like to perform authorization checks without using Clerk's organizations feature, see [the Role Based Access Control (RBAC) guide](/docs/guides/basic-rbac). In general, you should always verify whether or not a user is authorized to access sensitive information, important content, or exclusive features. The most secure way to implement authorization is by checking the active user's [role or permissions](/docs/organizations/roles-permissions#permissions). @@ -18,7 +18,7 @@ Clerk enables two broad approaches to role and permissions-based authorization: ## Authorization in Client Components -The examples below work for both SSR and CSR. Examples are written for Next.js App Router but they are supported by any React meta framework, such as Remix. +The following examples work for both SSR and CSR. ", "has()"]}> @@ -28,7 +28,7 @@ The examples below work for both SSR and CSR. Examples are written for Next.js A 'use client' import { Protect } from '@clerk/nextjs' - export function SettingsForm() { + export default function SettingsForm() { return ( - Use the [`useAuth()`](/docs/references/react/use-auth) hook to access the `has()` helper in Client Components. - The following example uses `has()` to inspect a user's permissions granularly. If the user doesn't have the permission, `has()` returns `false`, causing the component to return `null` instead of rendering its children. ```tsx {{ filename: '/app/dashboard/settings/form.tsx' }} 'use client' import { useAuth } from '@clerk/nextjs' - export function SettingsForm() { + export default function SettingsForm() { const { has } = useAuth() + if (!has) return null + + // Check if the user is authorized const canManageSettings = has({ permission: 'org:team_settings:manage' }) + // If has() returns false, the user does not have the correct permissions + // You can choose how your app responds. This example returns null. if (!canManageSettings) return null + // If the user is both authenticated and authorized, move forward with your logic return
{/* Add UI for managing team settings */}
} ``` @@ -67,7 +71,10 @@ The examples below work for both SSR and CSR. Examples are written for Next.js A ", "has()", "auth.protect()"]}> - The following example uses Clerk's `` component to only render the form for users with the correct permission. If the user is not authorized, the component will not render its children. + The following example uses Clerk's `` component to only render the layout for users with the correct permission. If the user is not authorized, the component will not render its children. + + > [!WARNING] + > Be cautious when doing authorization checks in layouts, as these don't re-render on navigation, meaning the user session won't be checked on every route change. [Read more in the Next.js docs.](https://nextjs.org/docs/app/building-your-application/authentication#layouts-and-auth-checks) ```tsx {{ filename: '/app/dashboard/settings/layout.tsx' }} import type { PropsWithChildren } from 'react' @@ -82,6 +89,9 @@ The examples below work for both SSR and CSR. Examples are written for Next.js A The following example uses `has()` to inspect a user's permissions granularly. If the user doesn't have the correct permission, `has()` returns `false`, causing the component to return `null` instead of rendering its children. + > [!WARNING] + > Be cautious when doing authorization checks in layouts, as these don't re-render on navigation, meaning the user session won't be checked on every route change. [Read more in the Next.js docs.](https://nextjs.org/docs/app/building-your-application/authentication#layouts-and-auth-checks) + ```tsx {{ filename: '/app/dashboard/settings/layout.tsx' }} import type { PropsWithChildren } from 'react' import { auth } from '@clerk/nextjs/server' @@ -89,8 +99,11 @@ The examples below work for both SSR and CSR. Examples are written for Next.js A export default async function SettingsLayout(props: PropsWithChildren) { const { has } = await auth() + // Check if the user is authorized const canAccessSettings = has({ permission: 'org:team_settings:read' }) + // If has() returns false, the user does not have the correct permissions + // You can choose how your app responds. This example returns null. if (!canAccessSettings) return null return props.children @@ -100,7 +113,7 @@ The examples below work for both SSR and CSR. Examples are written for Next.js A > [!WARNING] - > `auth.protect()` only works for App Router and is considered experimental. + > [`auth.protect()`](/docs/references/nextjs/auth#protect) is only available for App Router, and only works on the server-side. The following example uses [`auth.protect()`](/docs/references/nextjs/auth#protect) to protect a RSC from unauthenticated and unauthorized access. @@ -108,14 +121,13 @@ The examples below work for both SSR and CSR. Examples are written for Next.js A - If the user is authenticated but is not authorized (as in, does not have the `org:team_settings:read` permission), `auth.protect()` will throw a `404` error. - If the user is both authenticated and authorized, `auth.protect()` will return the user's `userId`. - ```tsx {{ filename: '/app/dashboard/settings/layout.tsx' }} - import type { PropsWithChildren } from 'react' + ```tsx {{ filename: '/app/dashboard/settings/page.tsx' }} import { auth } from '@clerk/nextjs/server' - export default async function SettingsLayout(props: PropsWithChildren) { + export default async function Page() { const { userId } = await auth.protect({ permission: 'org:team_settings:read' }) - return props.children + return

{userId} is authorized to access this page.

} ```
@@ -131,21 +143,24 @@ The examples below work for both SSR and CSR. Examples are written for Next.js A import { auth } from '@clerk/nextjs/server' export default async function ExampleServerComponent() { - async function myAction(formData: FormData) { + async function myServerAction(formData: FormData) { 'use server' const { has } = await auth() + // Check if the user is authorized const canManage = has({ permission: 'org:team_settings:manage' }) // If has() returns false, the user does not have the correct permissions + // You can choose how your app responds. This example returns a 403 error. if (!canManage) return Response.json({ error: 'User does not have the correct permissions' }, { status: 403 }) - // Add logic for managing team settings + // If the user is both authenticated and authorized, move forward with your logic + return users.getTeams(userId) } return ( -
+ {/* Add UI for managing team settings */}
@@ -161,24 +176,29 @@ The examples below work for both SSR and CSR. Examples are written for Next.js A The example: - - uses the `userId` returned from [`auth()`](/docs/references/nextjs/auth) to check if the user is signed in. If the user is not authenticated, the Route Handler will return a `401` error. - - uses `has()` to check if the user has the correct permission. If the user is not authorized, `has()` will return false, causing the Route Handler to return a `403` error. + - uses the `userId` returned from [`auth()`](/docs/references/nextjs/auth) to check if the user is signed in. If the user is not **authenticated**, the Route Handler will return a `401` error. + - uses `has()` to check if the user has the correct permission. If the user is not **authorized**, `has()` will return false, causing the Route Handler to return a `403` error. ```tsx {{ filename: 'app/api/get-teams/route.tsx' }} import { auth } from '@clerk/nextjs/server' - export const GET = () => { + export const GET = async () => { const { userId, has } = await auth() + // Check if the user is authenticated if (!userId) { return Response.json({ error: 'User is not signed in' }, { status: 401 }) } + // Check if the user is authorized const canRead = has({ permission: 'org:team_settings:read' }) + // If has() returns false, the user does not have the correct permissions + // You can choose how your app responds. This example returns a 403 error. if (!canRead) return Response.json({ error: 'User does not have the correct permissions' }, { status: 403 }) + // If the user is both authenticated and authorized, move forward with your logic return users.getTeams(userId) } ``` @@ -186,7 +206,7 @@ The examples below work for both SSR and CSR. Examples are written for Next.js A > [!WARNING] - > `auth.protect()` only works for App Router and is considered experimental. + > [`auth.protect()`](/docs/references/nextjs/auth#protect) is only available for App Router, and only works on the server-side. The following example uses [`auth.protect()`](/docs/references/nextjs/auth#protect) to protect a Next.js Route Handler from unauthenticated and unauthorized access. @@ -196,12 +216,12 @@ The examples below work for both SSR and CSR. Examples are written for Next.js A ```tsx {{ filename: 'app/api/create-team/route.tsx' }} import { auth } from '@clerk/nextjs/server' - export const POST = async () => { + export const GET = async () => { const { userId } = await auth.protect({ permission: 'org:team_settings:manage', }) - return users.createTeam(userId) + return Response.json({ userId }) } ``` @@ -213,8 +233,8 @@ The examples below work for both SSR and CSR. Examples are written for Next.js A The following example: - - uses the `userId` returned from `getAuth()` to check if the user is signed in. If the user is not authenticated, the route will return a `401` error. - - uses `has()` to check if the user has the correct permission. If the user is not authorized, `has()` will return false, causing the route to return a `403` error. + - uses the `userId` returned from `getAuth()` to check if the user is signed in. If the user is not **authenticated**, the route will return a `401` error. + - uses `has()` to check if the user has the correct permission. If the user is not **authorized**, `has()` will return false, causing the route to return a `403` error. ```tsx {{ filename: 'src/pages/api/get-teams.ts' }} import { getAuth } from '@clerk/nextjs/server' @@ -222,12 +242,17 @@ The examples below work for both SSR and CSR. Examples are written for Next.js A export default async function handler(req: NextApiRequest) { const { userId, has } = await getAuth(req) + // Check if the user is authenticated if (!userId) return res.status(401) + // Check if the user is authorized const canRead = has({ permission: 'org:team_settings:read' }) + // If has() returns false, the user does not have the correct permissions + // You can choose how your app responds. This example returns a 403 error. if (!canRead) return res.status(403) + // If the user is both authenticated and authorized, move forward with your logic return users.getTeams(userId) } ``` @@ -236,53 +261,60 @@ The examples below work for both SSR and CSR. Examples are written for Next.js A ## Authorization in Remix Loaders - - ```tsx - export const loader: LoaderFunction = async (args) => { - const { has } = await getAuth(args) +The following example uses the [`has()`](/docs/references/nextjs/auth-object#has) helper to check if the user has the correct permission. If the user is not authorized, `has()` will return false, causing the loader to redirect the user to the `/request-access` route. - if (has({ permission: 'org:team_settings:manage' })) { - return redirect('/request-access') + + + ```tsx + export const loader: LoaderFunction = async (args) => { + const { has } = await getAuth(args) + + if (has({ permission: 'org:team_settings:manage' }) === false) { + return redirect('/request-access') + } + + return {} } - return {} - } - export default function Settings() { - return ( -
-

Settings Page

-
- ) - } - ``` -
+ export default function Settings() { + return ( +
+

Settings Page

+
+ ) + } + ``` +
+
## Authorization in JavaScript -If you are not using React or any of the meta-frameworks we support, you can use the Clerk JavaScript SDK. The following example demonstrates how to use the [`checkAuthorization()`](/docs/references/javascript/session#check-authorization) method to check if a user is authorized. +If you are not using React or any of the meta-frameworks we support, you can use the [Clerk JavaScript SDK](/docs/references/javascript/overview). The following example demonstrates how to use the [`checkAuthorization()`](/docs/references/javascript/session#check-authorization) method to check if a user is authorized. - ```tsx {{ filename: 'main.js' }} - import { Clerk } from '@clerk/clerk-js' - - // Initialize Clerk with your Clerk publishable key - const clerk = new Clerk('{{pub_key}}') - await clerk.load() - - // Check if the user is authenticated - if (clerk.user) { - // Check if the user is authorized - const canManageSettings = clerk.session.checkAuthorization({ - permission: 'org:team_settings:manage', - }) - } - ``` + + ```tsx {{ filename: 'main.js' }} + import { Clerk } from '@clerk/clerk-js' + + // Initialize Clerk with your Clerk publishable key + const clerk = new Clerk('{{pub_key}}') + await clerk.load() + + // Check if the user is authenticated + if (clerk.user) { + // Check if the user is authorized + const canManageSettings = clerk.session.checkAuthorization({ + permission: 'org:team_settings:manage', + }) + } + ``` + ## Authorize with roles > [!WARNING] -> We suggest permission-based authorization over role-based authorization, as it reduces complexity and increases security. Usually, complex role checks can be refactored with a single permission check. +> It's best practice to use permission-based authorization over role-based authorization, as it reduces complexity and increases security. Usually, complex role checks can be refactored with a single permission check. You can pass a `role` the same way you can pass a `permission` in all the examples above. @@ -290,16 +322,15 @@ You can pass a `role` the same way you can pass a `permission` in all the exampl The following example uses ``'s `condition` prop to conditionally render its children if the user has the correct role. - ```tsx {{ filename: '/app/dashboard/settings/layout.tsx' }} - import type { PropsWithChildren } from 'react' + ```tsx {{ filename: '/app/dashboard/settings/Page.tsx' }} import { Protect } from '@clerk/nextjs' - export default function SettingsLayout(props: PropsWithChildren) { + export default function Page() { return ( has({ role: 'org:admin' }) || has({ role: 'org:billing_manager' })} > - {props.children} +

Admin settings

) } @@ -308,7 +339,7 @@ You can pass a `role` the same way you can pass a `permission` in all the exampl > [!WARNING] - > `auth.protect()` only works for App Router and is considered experimental. + > [`auth.protect()`](/docs/references/nextjs/auth#protect) is only available for App Router, and only works on the server-side. The following example uses [`auth.protect()`](/docs/references/nextjs/auth#protect) to protect a RSC from unauthenticated and unauthorized access. @@ -316,23 +347,20 @@ You can pass a `role` the same way you can pass a `permission` in all the exampl - If the user is authenticated but is not authorized (as in, does not have the `org:admin` or `org:billing_manager` role), `auth.protect()` will throw a `404` error. - If the user is both authenticated and authorized, `auth.protect()` will return the user's `userId`. - ```tsx {{ filename: '/app/dashboard/settings/layout.tsx' }} - import type { PropsWithChildren } from 'react' + ```tsx {{ filename: '/app/dashboard/settings/page.tsx' }} import { auth } from '@clerk/nextjs/server' - export default async function SettingsLayout(props: PropsWithChildren) { + export default async function Page() { const { userId } = await auth.protect( (has) => has({ role: 'org:admin' }) || has({ role: 'org:billing_manager' }), ) - return props.children + return

{userId} is authorized to access this page.

} ```
- Use the [`useAuth()`](/docs/references/react/use-auth) hook to access the `has()` helper in Client Components. - The following example uses `has()` to inspect a user's roles granularly. If the user doesn't have the correct role, `has()` returns `false`, causing the component to return `null` instead of rendering its children. ```tsx {{ filename: '/app/dashboard/settings/form.tsx' }} @@ -342,10 +370,14 @@ You can pass a `role` the same way you can pass a `permission` in all the exampl export function SettingsForm() { const { has } = useAuth() + // Check if the user is authorized const canAccessSettings = has({ role: 'org:admin' }) || has({ role: 'org:billing_manager' }) + // If has() returns false, the user does not have the correct permissions + // You can choose how your app responds. This example returns null. if (!canAccessSettings) return null + // If the user is both authenticated and authorized, move forward with your logic return
{/* Add UI for team settings */}
} ``` diff --git a/docs/references/nextjs/auth.mdx b/docs/references/nextjs/auth.mdx index cbb08a92f9..9cf89c08bd 100644 --- a/docs/references/nextjs/auth.mdx +++ b/docs/references/nextjs/auth.mdx @@ -3,27 +3,20 @@ title: '`auth()`' description: Access minimal authentication data for managing sessions and data fetching. --- -The `auth()` helper returns the [`Auth`](/docs/references/nextjs/auth-object) object of the currently active user. This is the same `Auth` object that is returned by the [`getAuth()`](/docs/references/nextjs/get-auth) hook. However, it can be used in Server Components, Route Handlers, and Server Actions. +The `auth()` helper returns the [`Auth`](/docs/references/nextjs/auth-object) object of the currently active user, as well as the [`redirectToSignIn()`](#redirect-to-sign-in) method. -The `auth()` helper does require [Middleware](/docs/references/nextjs/clerk-middleware). +- Only available for App Router. +- Only works on the server-side, such as in Server Components, Route Handlers, and Server Actions. +- Requires [`clerkMiddleware()`](/docs/references/nextjs/clerk-middleware) to be configured. -## Returns +## `auth.protect()` -`auth()` returns the [`Auth`](/docs/references/nextjs/auth-object) object with a few extra properties: - -- [`redirectToSignIn()`](#redirect-to-sign-in) - -### `auth.protect()` - -> [!WARNING] -> `auth.protect()` only works for App Router and is considered experimental. - -You can use the `auth.protect()` helper in two ways: +`auth` includes a single property, the `protect()` method, which you can use in two ways: - to check if a user is authenticated (signed in) - to check if a user is authorized (has the correct roles or permissions) to access something, such as a component or a route handler -The following table describes how the `auth.protect()` helper behaves based on user authentication or authorization status: +The following table describes how `auth.protect()` behaves based on user authentication or authorization status: | Authenticated | Authorized | `auth.protect()` will | | - | - | - | @@ -54,7 +47,7 @@ The following table describes how the `auth.protect()` helper behaves based on u - `has?` - `(isAuthorizedParams: CheckAuthorizationParamsWithCustomPermissions) => boolean` - A function that returns a boolean based on the permission or role provided as parameter. Can be used for authorization. See the dedicated [`has()`](/docs/references/nextjs/auth-object#has) section for more information. + A function that returns a boolean based on the permission or role provided as parameter. Can be used for authorization. See [the dedicated `has()` section](/docs/references/nextjs/auth-object#has) for more information. --- @@ -71,11 +64,15 @@ The following table describes how the `auth.protect()` helper behaves based on u The URL to redirect the user to if they are not authenticated. -For more information on how to use `auth.protect()`, see the [examples](#use-auth-to-check-if-a-user-is-authenticated) in this guide. There are also examples in the [Verify user permissions](/docs/organizations/verify-user-permissions) guide. +### Examples -### `redirectToSignIn()` +`auth.protect()` can be used to check if a user is authenticated or authorized to access certain parts of your application or even entire routes. See detailed examples in [the dedicated guide.](/docs/organizations/verify-user-permissions) -`redirectToSignIn()` is a method that redirects the user to the sign-in page. It accepts the following parameters: +## `redirectToSignIn()` + +The `auth()` helper returns the `redirectToSignIn()` method, which you can use to redirect the user to the sign-in page. + +`redirectToSignIn()` accepts the following parameters: - `returnBackUrl?` @@ -87,6 +84,22 @@ For more information on how to use `auth.protect()`, see the [examples](#use-aut > [!NOTE] > `auth()` on the server-side can only access redirect URLs defined via [environment variables](/docs/deployments/clerk-environment-variables#sign-in-and-sign-up-redirects) or [`clerkMiddleware` dynamic keys](/docs/references/nextjs/clerk-middleware#dynamic-keys). +### Example + +The following example shows how to use `redirectToSignIn()` to redirect the user to the sign-in page if they are not authenticated. It's also common to use `redirectToSignIn()` in `clerkMiddleware()` to protect entire routes; see [the `clerkMiddleware()` docs](/docs/references/nextjs/clerk-middleware) for more information. + +```tsx {{ filename: 'app/page.tsx' }} +import { auth } from '@clerk/nextjs/server' + +export default async function Page() { + const { userId, redirectToSignIn } = await auth() + + if (!userId) return redirectToSignIn() + + return

Hello, {userId}

+} +``` + ## Use `auth()` to retrieve `userId` You can use `auth()` to check if a `userId` exists. If it does not, that means there is no user signed in. You can use this information to protect pages, as shown in the following example: @@ -131,95 +144,6 @@ export async function GET() { } ``` -## Use `auth.protect()` to check if a user is authenticated - -`auth.protect()` can be used in a `layout.tsx` file to protect the entire route, including all children. - -In the following example, - -- the `auth.protect()` helper is used to check if a user visiting any `/dashboard` route is authenticated. -- If the user is not authenticated, they will be redirected to the sign-in route. -- If the user is authenticated, they can view any `/dashboard` route and its children. - -```tsx {{ filename: 'app/dashboard/layout.tsx' }} -import { auth } from '@clerk/nextjs/server' - -export default async function Layout({ children }: { children: React.ReactNode }) { - await auth.protect() - - return <>{children} -} -``` - -## Use `auth()` to check if a user is authorized - -`auth()` returns the [`Auth`](/docs/references/nextjs/auth-object#auth-object) object, which includes the [`has()`](/docs/references/nextjs/auth-object#has) helper. - -You can protect certain parts of your application or even entire routes based on user authorization status by checking if the user has the required roles or permissions. - -- Use `auth.protect()` if you want Clerk to return a `404` if the user does not have the role or permission. -- Use `has()` if you want more control over what your app does based on the authorization status instead of immediately returning a `404`. - - - - The following example uses `has()` to protect a pages content from unauthorized access. - - - If the user does not have the permission, `has()` will return `false`, causing the component to return `null`. - - If the user has the permission, `has()` will return `true`, allowing the component to render its children. - - ```tsx {{ filename: 'app/team-settings/page.tsx' }} - import { auth } from '@clerk/nextjs/server' - - export default async function Page() { - const { has } = await auth() - - const canManage = has({ permission: 'org:team_settings:manage' }) - - if (!canManage) return null - - return

Team Settings

- } - ``` -
- - - > [!WARNING] - > `auth.protect()` only works for App Router and is considered experimental. - - The following example uses `auth.protect()` to protect a Next.js Route Handler from unauthenticated and unauthorized access. - - - If the user is not authenticated, `auth.protect()` will redirect the user to the sign-in route. - - If the user is authenticated but is not authorized (as in, does not have the `org:team_settings:manage` permission), `auth.protect()` will throw a `404` error. - - If the user is both authenticated and authorized, `auth.protect()` will return the user's `userId`. +## Use `auth()` to protect your app - ```tsx {{ filename: 'app/api/create-team/route.ts' }} - import { auth } from '@clerk/nextjs/server' - - export const POST = async () => { - const { userId } = await auth.protect({ permission: 'org:team_settings:manage' }) - - return users.createTeam(userId) - } - ``` - -
- -## Use `auth()` to check your current user's role - -In some cases, you need to check your user's current organization role before displaying data or allowing certain actions to be performed. - -Check the current user's role with the `orgRole` property of the `Auth` object returned by `auth()`, as shown in the following example: - -```tsx {{ filename: 'app/page.tsx' }} -import { auth } from '@clerk/nextjs/server' - -export default async function Page() { - const { orgRole } = await auth() - - return ( - <> -
Your current role is {orgRole}
- - ) -} -``` +You can protect certain parts of your application or even entire routes based on a user's authentication and/or authorization status. See detailed examples in [the dedicated guide.](/docs/organizations/verify-user-permissions) From 1feae6a710218c57e1f5b0d1594555a4b5cfe6df Mon Sep 17 00:00:00 2001 From: George Raphael Date: Mon, 28 Oct 2024 21:38:15 +0300 Subject: [PATCH 4/7] Update local-credentials.mdx (#1659) --- docs/references/expo/local-credentials.mdx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/references/expo/local-credentials.mdx b/docs/references/expo/local-credentials.mdx index b35ad878e4..c5859c8c99 100644 --- a/docs/references/expo/local-credentials.mdx +++ b/docs/references/expo/local-credentials.mdx @@ -100,10 +100,10 @@ This guide shows you how to use the `useLocalCredentials()` hook to enhance your /> setPassword(password)} />