diff --git a/docs/integrations/databases/convex.mdx b/docs/integrations/databases/convex.mdx index 2bb985f2d3..1da0c08b2a 100644 --- a/docs/integrations/databases/convex.mdx +++ b/docs/integrations/databases/convex.mdx @@ -11,165 +11,273 @@ description: Learn how to integrate Clerk into your Convex application. icon: "clerk", }, { - title: "Create a React + Convex application", - link: "https://docs.convex.dev/quickstart/react", - icon: "react", + title: "Integrate a Clerk SDK into your app", + link: "/docs/quickstarts/overview", + icon: "code-bracket", }, + { + title: "Integrate Convex into your app", + link: "https://docs.convex.dev/quickstarts", + icon: "code-bracket" + } + ]} + exampleRepo={[ + { + title: "Convex's Next.js + Clerk Template", + link: "https://github.com/get-convex/template-nextjs-clerk" + }, + { + title: "Convex's React + Clerk Template", + link: "https://github.com/get-convex/template-react-vite-clerk" + } ]} > - - Create a JWT template based on Convex - - Configure Convex with the Clerk issuer domain - - Install and configure Clerk's React SDK - - Configure the Clerk and Convex providers - - Access user identity in Convex queries and mutations + - Create a JWT template in Clerk to generate Convex JWTs + - Configure Convex to accept JWTs from Clerk + - Configure the Clerk and Convex providers to work together -Convex is the full-stack TypeScript development platform. With Convex you get to build a backend with a provided realtime database, file storage, text search, scheduling and more. Paired with Clerk's user authentication and management features, you can build a powerful application with minimal effort. - -This tutorial assumes that you have already [set up a Clerk application](/docs/quickstarts/setup-clerk) and a [React + Convex application](https://docs.convex.dev/quickstart/react){{ target: '_blank' }}. This tutorial will also assume that you have not added Clerk to your application yet. +With [Convex](https://www.convex.dev/), you can build a backend with a provided realtime database, file storage, text search, scheduling and more. Paired with Clerk's user authentication and management features, you can build a powerful application with minimal effort. This tutorial will show you how to integrate Clerk into your Convex application. It assumes that you have already integrated both Convex and one of Clerk's SDKs into your app. ## Create a JWT template based on Convex - In the Clerk Dashboard, navigate to the [**JWT templates**](https://dashboard.clerk.com/last-active?path=jwt-templates) page. Select the **New template** button to create a new template based on Convex. - - ![The JWT templates page in the Clerk Dashboard. The 'New template' button was clicked, and a pop up titled 'New JWT template' is shown. The 'Convex' template is hovered over](/docs/images/integrations/convex/jwt-templates.webp) - - Once the Convex template is created, you will be redirected to the template's page. You can now configure the template to your needs. - - ![The 'Create new template' page of the JWT templates page in the Clerk Dashboard](/docs/images/integrations/convex/create-template.webp) - - The Convex template will pre-populate the default audience (`aud`) claim required by Convex. You can include additional claims as necessary. [Shortcodes](/docs/backend-requests/jwt-templates#shortcodes) are available to make adding dynamic user values easy. + 1. In the Clerk Dashboard, navigate to the [**JWT templates**](https://dashboard.clerk.com/last-active?path=jwt-templates) page. + 1. Select **New template** and then from the list of templates, select **Convex**. You'll be redirected to the template's settings page. + 1. Copy and save the **Issuer** URL somewhere secure. This URL is the issuer domain for Clerk's JWT templates, which is your application's **Frontend API URL**. In development, it's format will be `https://verb-noun-00.clerk.accounts.dev`. In production, it's format will be `https://clerk..com`. - ![The 'Create new template' page of the JWT templates page in the Clerk Dashboard. The page is scrolled down to the 'Claims' section](/docs/images/integrations/convex/template-shortcodes.webp) + ## Map additional claims (optional) - By default, Clerk will sign the JWT with a private key automatically generated for your application, which is what most developers use for Convex. If you so choose, you can customize this key. + In the **Claims** section, the default audience (`aud`) claim required by Convex is pre-mapped, as well as some other helpful claims like Convex's `name` claim to Clerk's `user.full_name` claim. You can include additional claims as necessary. [Shortcodes](/docs/backend-requests/jwt-templates#shortcodes) are available to make adding dynamic user values easy. ## Configure Convex with the Clerk issuer domain - The next step is to configure Convex with the issuer domain provided by Clerk. From your Clerk **JWT template** screen, find the **Issuer** input and click to **Copy** the URL. - - ![The 'Create new template' page of the JWT templates page in the Clerk Dashboard. There is a red box surrounding the 'Issuer' section](/docs/images/integrations/convex/template-issuer.webp) - - In your `convex` folder, add an `auth.config.js` file with the following configuration: - - ```ts {{ filename: 'convex/auth.config.js' }} - export default { - providers: [ - { - domain: 'https://your-issuer-url.clerk.accounts.dev/', - applicationID: 'convex', - }, - ], - } - ``` - - Replace the `domain` string with the **Issuer** URL you copied. + 1. In your `env` file, add your **Issuer** URL as the `CLERK_FRONTEND_API_URL` environment variable. If you already have it set, great! + ```env {{ filename: '.env' }} + CLERK_FRONTEND_API_URL={{fapi_url}} + ``` + 1. In your app's `convex` folder, create a `auth.config.js` file with the following configuration: + ```ts {{ filename: 'convex/auth.config.js' }} + export default { + providers: [ + { + domain: process.env.CLERK_FRONTEND_API_URL, + applicationID: 'convex', + }, + ], + } + ``` ## Deploy your changes to Convex Run `npx convex dev` to automatically sync your configuration to your backend. - ## Install `@clerk/clerk-react` - - Run the following command to install Clerk's React SDK: - - - ```bash {{ filename: 'terminal' }} - npm install @clerk/clerk-react - ``` - - ```bash {{ filename: 'terminal' }} - yarn add @clerk/clerk-react - ``` - - ```bash {{ filename: 'terminal' }} - pnpm add @clerk/clerk-react - ``` - - - ## Set environment variables - - In your React project's root folder, you may have an `.env` file alongside `package.json` and other configuration files. If you don't see it, create it. - - - Add your Clerk Publishable Key to your `.env` file. It can always be retrieved from the [**API keys**](https://dashboard.clerk.com/last-active?path=api-keys) page in the Clerk Dashboard. - - - - 1. In the Clerk Dashboard, navigate to the [**API keys**](https://dashboard.clerk.com/last-active?path=api-keys) page. - 1. In the **Quick Copy** section, copy your Clerk Publishable Key. - 1. Paste your key into your `.env` file. - - The final result should resemble the following: - - - ```env {{ filename: '.env' }} - VITE_CLERK_PUBLISHABLE_KEY={{pub_key}} - ``` - ## Configure the Clerk and Convex providers - Both Clerk and Convex have provider components that are required to provide authentication and client context. - - Clerk's provider component is ``, which should wrap your entire app at the entry point to make authentication globally accessible. See the [reference docs](/docs/components/clerk-provider) for other configuration options. - - Convex offers a provider that is specifically for integrating with Clerk called [``](https://docs.convex.dev/auth/clerk). - - The following example demonstrates how to configure Clerk and Convex's providers. Clerk's `useAuth()` hook must be passed to `` and Clerk's `` must be wrapped around it. - - ```ts {{ filename: 'src/main.tsx' }} - import React from 'react' - import ReactDOM from 'react-dom/client' - import App from './App' - import './index.css' - import { ClerkProvider, useAuth } from '@clerk/clerk-react' - import { ConvexProviderWithClerk } from 'convex/react-clerk' - import { ConvexReactClient } from 'convex/react' - - // Import your Publishable Key - const PUBLISHABLE_KEY = import.meta.env.VITE_CLERK_PUBLISHABLE_KEY - - if (!PUBLISHABLE_KEY) { - throw new Error('Missing Publishable Key') - } - - const convex = new ConvexReactClient(import.meta.env.VITE_CONVEX_URL as string) - - ReactDOM.createRoot(document.getElementById('root')!).render( - - - - - - - , - ) - ``` - - ## Access user identity in Convex queries and mutations - - You can access the user information from the JWT in Convex queries and mutations. - Use the `ctx.auth.getUserIdentity()` which returns the parsed information from the JWT, or `null` if the client isn't authenticated. - - ```ts - import type { UserIdentity } from 'convex/server' + Both Clerk and Convex have provider components that are required to provide authentication and client context. You should already have Clerk's provider component, ``, in your app. Convex offers a provider that is specifically for integrating with Clerk called ``. + + + + `` calls `ConvexReactClient()` to get Convex's client, so it must be used in a Client Component. Your `app/layout.tsx`, where you would use ``, is a Server Component, and a Server Component cannot contain Client Component code. To solve this, you must first create a _wrapper_ Client Component around ``. + + ```tsx {{ filename: 'components/ConvexClientProvider.tsx' }} + 'use client' + + import { ReactNode } from 'react' + import { ConvexReactClient } from 'convex/react' + import { ConvexProviderWithClerk } from 'convex/react-clerk' + import { useAuth } from '@clerk/nextjs' + + if (!process.env.NEXT_PUBLIC_CONVEX_URL) { + throw new Error('Missing NEXT_PUBLIC_CONVEX_URL in your .env file') + } + + const convex = new ConvexReactClient(process.env.NEXT_PUBLIC_CONVEX_URL) + + export default function ConvexClientProvider({ children }: { children: ReactNode }) { + return ( + + {children} + + ) + } + ``` + + Now, your Server Component, `app/layout.tsx`, can use the wrapper component, ``. It's important that `` wraps ``, and not the other way around, as Convex needs to be able to access the Clerk context. + + ```tsx {{ filename: 'app/layout.tsx', mark: [5, 31] }} + import type { Metadata } from 'next' + import { Geist, Geist_Mono } from 'next/font/google' + import './globals.css' + import { ClerkProvider } from '@clerk/nextjs' + import ConvexClientProvider from '@/components/ConvexClientProvider' + + const geistSans = Geist({ + variable: '--font-geist-sans', + subsets: ['latin'], + }) + + const geistMono = Geist_Mono({ + variable: '--font-geist-mono', + subsets: ['latin'], + }) + + export const metadata: Metadata = { + title: 'Clerk Next.js Quickstart', + description: 'Generated by create next app', + } + + export default function RootLayout({ + children, + }: Readonly<{ + children: React.ReactNode + }>) { + return ( + + + + {children} + + + + ) + } + ``` + + + + The following example demonstrates how to configure Clerk and Convex's providers. Clerk's [`useAuth()`](/docs/hooks/use-auth) hook must be passed to Convex's `` and Clerk's `` must be wrapped around it. + + ```ts {{ filename: 'src/main.tsx', mark: [[5, 7], 19, 21] }} + import React from 'react' + import ReactDOM from 'react-dom/client' + import App from './App.tsx' + import './index.css' + import { ClerkProvider, useAuth } from '@clerk/clerk-react' + import { ConvexProviderWithClerk } from 'convex/react-clerk' + import { ConvexReactClient } from 'convex/react' + + // Import your Publishable Key + const PUBLISHABLE_KEY = import.meta.env.VITE_CLERK_PUBLISHABLE_KEY + + if (!PUBLISHABLE_KEY) { + throw new Error('Add your Clerk Publishable Key to the .env file') + } + + ReactDOM.createRoot(document.getElementById('root')!).render( + + + + + + + , + ) + ``` + + + + ## Show UI based on auth state + + You can control which UI is shown when the user is signed in or signed out using Convex's ``, `` and `` helper components. These should be used instead of Clerk's ``, `` and `` components, respectively. + + It's important to use the [`useConvexAuth()`](https://docs.convex.dev/api/modules/react#useconvexauth) hook instead of Clerk's `useAuth()` hook when you need to check whether the user is logged in or + not. The `useConvexAuth()` hook makes sure that the browser has fetched the auth token needed to make authenticated requests to your Convex backend, and that the Convex backend has validated it. + + In the following example, the `` component is a child of ``, so its content and any of its child components are guaranteed to have an authenticated user, and Convex queries can require authentication. + + + + ```tsx title="app/page.tsx" + 'use client' + + import { Authenticated, Unauthenticated } from 'convex/react' + import { SignInButton, UserButton } from '@clerk/nextjs' + import { useQuery } from 'convex/react' + import { api } from '../convex/_generated/api' + + export default function Home() { + return ( + <> + + + + + + + + + ) + } + + function Content() { + const messages = useQuery(api.messages.getForCurrentUser) + return
Authenticated content: {messages?.length}
+ } + ``` +
+ + + ```tsx title="src/App.tsx" + import { SignInButton, UserButton } from '@clerk/clerk-react' + import { Authenticated, Unauthenticated, AuthLoading, useQuery } from 'convex/react' + import { api } from '../convex/_generated/api' + + function App() { + return ( +
+ + + + + + + + +

Still loading

+
+
+ ) + } + + function Content() { + const messages = useQuery(api.messages.getForCurrentUser) + return
Authenticated content: {messages?.length}
+ } + + export default App + ``` +
+
+ + ## Use auth state in your Convex functions + + If the client is authenticated, you can access the information stored in the JWT via `ctx.auth.getUserIdentity`. + + If the client isn't authenticated, `ctx.auth.getUserIdentity` will return `null`. + + **Make sure that the component calling this query is a child of `` from + `convex/react`**. Otherwise, it will throw on page load. + + ```ts {{ filename: 'convex/messages.ts' }} import { query } from './_generated/server' - export default query(async (ctx) => { - const user = await ctx.auth.getUserIdentity() - - if (user === null) { - return null - } - - return user.tokenIdentifier + export const getForCurrentUser = query({ + args: {}, + handler: async (ctx) => { + const identity = await ctx.auth.getUserIdentity() + if (identity === null) { + throw new Error('Not authenticated') + } + return await ctx.db + .query('messages') + .filter((q) => q.eq(q.field('author'), identity.email)) + .collect() + }, }) ``` +
- You can customize the information in the JWT by navigating to the [**JWT templates**](https://dashboard.clerk.com/last-active?path=jwt-templates) page in the Clerk Dashboard. Previously, Convex explicitly listed fields derived from [OpenID standard claims](https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims). Now, Convex allows keys to accept [custom claims](https://docs.convex.dev/api/interfaces/server.UserIdentity). - - ## Finished! +## Next steps - You now have a fully functioning React and Convex application with Clerk authentication. Be aware that Convex may require usage of their custom hooks and methods rather than Clerk's, such as using Convex's `useConvexAuth()` hook instead of Clerk's `useAuth()` hook in some cases. For more information on how to use Convex with Clerk, see the [Convex docs](https://docs.convex.dev/auth/clerk). - +Be aware that Convex may require usage of their custom hooks and methods rather than Clerk's, such as using Convex's `useConvexAuth()` hook instead of Clerk's `useAuth()` hook in some cases. For more information on how to use Convex with Clerk, see the [Convex docs](https://docs.convex.dev/auth/clerk). diff --git a/docs/integrations/databases/instantdb.mdx b/docs/integrations/databases/instantdb.mdx index 0eebd1feb1..62a8081942 100644 --- a/docs/integrations/databases/instantdb.mdx +++ b/docs/integrations/databases/instantdb.mdx @@ -11,20 +11,18 @@ description: Learn how to integrate Clerk into your InstantDB application. icon: "clerk", }, { - title: "Create an InstantDB account", - link: "https://instantdb.com", - icon: "cog-6-teeth", + title: "Integrate a Clerk SDK into your app", + link: "/docs/quickstarts/overview", + icon: "code-bracket", }, { - title: "Integrate the appropriate Clerk SDK in your local project", - link: "/docs/quickstarts/overview", + title: "Integrate InstantDB into your app", + link: "https://www.instantdb.com/docs", icon: "code-bracket", }, ]} > - - Configure your Clerk session token to include the `email` claim. - - Configure InstantDB to use your Clerk application. - - Integrate InstantDB into your Clerk application. + - > [!IMPORTANT] @@ -37,7 +35,7 @@ This guide will walk you through the steps to integrate InstantDB with Clerk in ## Configure your Clerk session token - InstantDB uses Clerk's [session token](/docs/backend-requests/resources/session-tokens) to authenticate users. To use InstantDB with Clerk, you need to include the `email` claim in your session token. + InstantDB uses Clerk's [session token](/docs/backend-requests/resources/session-tokens) to authenticate users. To use InstantDB with Clerk, you need to include the `email` claim in your Clerk session token. 1. In the Clerk Dashboard, navigate to the [**Sessions**](https://dashboard.clerk.com/last-active?path=sessions) page. 1. In the **Customize session token** section, select **Edit**. @@ -61,11 +59,11 @@ This guide will walk you through the steps to integrate InstantDB with Clerk in 1. Select **Setup Clerk**. 1. Add the Publishable Key you copied in the previous step. 1. Confirm the **The session token has the "email" claim.** message. - 1. Select **Add Clerk app**. + 1. Select **Add Clerk app**. Save the **Client Name** as you'll need it later. ## Install the InstantDB library - Run the following command to add the InstantDB library to your project. + If you haven't already added InstantDB to your app, run the following command to install it: ```bash {{ filename: 'terminal' }} diff --git a/public/images/integrations/convex/create-template.webp b/public/images/integrations/convex/create-template.webp deleted file mode 100644 index bc5ca8e4e5..0000000000 Binary files a/public/images/integrations/convex/create-template.webp and /dev/null differ diff --git a/public/images/integrations/convex/jwt-templates.webp b/public/images/integrations/convex/jwt-templates.webp deleted file mode 100644 index dac007bb8a..0000000000 Binary files a/public/images/integrations/convex/jwt-templates.webp and /dev/null differ diff --git a/public/images/integrations/convex/template-issuer.webp b/public/images/integrations/convex/template-issuer.webp deleted file mode 100644 index a314baee64..0000000000 Binary files a/public/images/integrations/convex/template-issuer.webp and /dev/null differ diff --git a/public/images/integrations/convex/template-shortcodes.webp b/public/images/integrations/convex/template-shortcodes.webp deleted file mode 100644 index cad3aeefb7..0000000000 Binary files a/public/images/integrations/convex/template-shortcodes.webp and /dev/null differ