{
    "componentChunkName": "component---src-pages-blog-markdown-remark-fields-slug-js",
    "path": "/blog/how-to-integrate-clerk-with-supabase",
    "result": {"data":{"markdownRemark":{"html":"<p>In this guide, we’ll walk through integrating Clerk with Supabase step-by-step. We start with a basic, no-auth Next.js app and gradually add authentication and secure, user-specific data storage using Clerk for auth and Supabase for data. You’ll end up with a diagram editor where each user can save and retrieve their own diagrams.</p>\n<p><strong>What You’ll Learn</strong></p>\n<ul>\n<li>Set up Clerk authentication in a Next.js app.</li>\n<li>Connect Clerk and Supabase (using the updated 2025 integration).</li>\n<li>Configure Row-Level Security (RLS) for user-specific access.</li>\n<li>See it all come together in a diagram editor where authenticated users save and load their own charts.</li>\n</ul>\n<p>We begin with a simple “no-auth” editor (users can draw and preview Mermaid diagrams, but nothing is saved). Then we layer on Clerk and Supabase. Clerk provides sign-in flows, session tokens, and user IDs. Supabase holds the diagrams and enforces per-user data access via RLS.</p>\n<p>Finally, we’ll introduce SuperTokens as an alternative in Part II, showing how it can offer more control (especially for session management) while still working with Supabase. Clerk is great out of the box if you want a quick, managed solution, but SuperTokens is worth a look if you need advanced extensibility or self-hosting.</p>\n<h2 id=\"how-clerk-and-supabase-work-together\" style=\"position:relative;\"><a href=\"#how-clerk-and-supabase-work-together\" aria-label=\"how clerk and supabase work together permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>How Clerk and Supabase Work Together</h2>\n<p>In this integration, Clerk and Supabase take on two distinct roles:</p>\n<ul>\n<li>\n<p><strong>Clerk handles authentication and user identity</strong> <br />It provides everything needed to securely sign users in like login flows, session management, and user IDs. Each user gets a unique userId (the <code class=\"language-text\">sub</code> claim in Clerk’s JWT) that stays the same across sessions.</p>\n</li>\n<li>\n<p><strong>Supabase handles data storage and access control</strong> <br />We use Supabase to store content (in our example, each user’s saved Mermaid chart) and to enforce fine-grained access rules. Supabase’s Row-Level Security (RLS) policies make sure users only see and modify their own data, even though everyone’s data lives in the same database.</p>\n</li>\n</ul>\n<h3 id=\"how-the-integration-flow-works\" style=\"position:relative;\"><a href=\"#how-the-integration-flow-works\" aria-label=\"how the integration flow works permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>How the Integration Flow Works</h3>\n<ol>\n<li><strong>User signs in with Clerk</strong><br /> Clerk verifies their credentials and returns a JWT (JSON Web Token) containing the user’s unique ID (<code class=\"language-text\">sub</code> claim).</li>\n<li><strong>Your app sends the JWT to Supabase</strong><br /> You configure the Supabase client to include Clerk’s token on each request. Supabase sees the token and uses it to identify the user.</li>\n<li><strong>Supabase enforces RLS policies</strong> <br />For example, if we have a charts table with a user_id column, RLS policies can be written like:\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"20584463032834500000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"Copied!\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`-- Only allow a user to see rows where user_id matches their ID from Clerk\npolicy &quot;Users can access their own charts&quot;\non charts\nfor all\nusing (auth.uid() = user_id);`, `20584463032834500000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                <svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"sql\"><pre class=\"language-sql\"><code class=\"language-sql\"><span class=\"token comment\">-- Only allow a user to see rows where user_id matches their ID from Clerk</span>\npolicy <span class=\"token string\">\"Users can access their own charts\"</span>\n<span class=\"token keyword\">on</span> charts\n<span class=\"token keyword\">for</span> <span class=\"token keyword\">all</span>\n<span class=\"token keyword\">using</span> <span class=\"token punctuation\">(</span>auth<span class=\"token punctuation\">.</span>uid<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=</span> user_id<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre></div>\n</li>\n</ol>\n<blockquote>\n<p><strong>RLS ensures each user sees only their own data, even in a shared database.</strong></p>\n</blockquote>\n<p><strong>This works because</strong></p>\n<ul>\n<li>Authentication is fully managed by Clerk out of the box.</li>\n<li>User data is stored in Supabase and automatically tied to individual user identities.</li>\n<li>Row-Level Security (RLS) policies enforce strict access control, preventing users from viewing or altering data that isn’t theirs.</li>\n</ul>\n<h2 id=\"clerk-and-supabase-integration-project-overview\" style=\"position:relative;\"><a href=\"#clerk-and-supabase-integration-project-overview\" aria-label=\"clerk and supabase integration project overview permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Clerk and Supabase Integration: Project Overview</h2>\n<p>🐙 <strong><a href=\"https://github.com/meems1996/mermaid-charting-app\" target=\"_blank\" rel=\"nofollow\">View the full demo on GitHub</a></strong> - this Next.js example shows Clerk + Supabase in action.</p>\n<h3 id=\"app-features\" style=\"position:relative;\"><a href=\"#app-features\" aria-label=\"app features permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>App Features:</h3>\n<ul>\n<li><strong>MermaidJS Editor</strong>. A live editor to write and render Mermaid diagrams.</li>\n<li><strong>Clerk Authentication</strong>. Sign-up/sign-in UI components and session handling.</li>\n<li><strong>Supabase Storage</strong>. Save and retrieve diagrams in a secure database.</li>\n<li><strong>Row-Level Security</strong>. Supabase policies ensure each user’s data is private.</li>\n</ul>\n<p><strong>Initial State:</strong> The app starts as a simple, stateless editor. Users can draw and preview diagrams, but nothing is saved – as soon as the page reloads, the content is lost.</p>\n<p><strong>With Clerk + Supabase:</strong> After adding Clerk, users must sign in. Then, with Supabase connected, each user can save their diagram, and it will reappear the next time they log in. Each saved chart is tagged with that user’s Clerk user ID, and RLS guarantees no user can see another’s charts. This turns the tool into a full multi-user app with persistent, private data.</p>\n<h3 id=\"what-youll-build\" style=\"position:relative;\"><a href=\"#what-youll-build\" aria-label=\"what youll build permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>What You’ll Build</h3>\n<p>We’ll enhance the basic editor by adding:</p>\n<ol>\n<li><strong>Clerk Authentication:</strong> Add Clerk to the Next.js app. Users can sign up and sign in (or sign out). After login, they see personalized content.</li>\n<li><strong>Supabase Integration:</strong> Configure Supabase so that each signed-in user can save their diagrams to the database. Supabase will use the Clerk user ID (from the JWT) to scope the data. RLS policies enforce that users only access their own data.</li>\n</ol>\n<p>By the end, you’ll have a working diagram editor where each user signs in, sees their own saved charts, and nothing else.</p>\n<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 630px; \"\n    >\n      <a\n    class=\"gatsby-resp-image-link\"\n    href=\"/static/c306fa1832402834f73c18a7bc391d4d/da18d/image.png\"\n    style=\"display: block\"\n    target=\"_blank\"\n    rel=\"noopener\"\n  >\n    <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 68.35443037974683%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAOCAYAAAAvxDzwAAAACXBIWXMAABYlAAAWJQFJUiTwAAACHklEQVQ4y61TW2sTQRTOu6BCXyxtrViUUrXSFy+/yxetsU1JN7UpgTz64K0JuawJBR+KIFXU4m9ITASR1iQNyWZnk83szl4+mZM0JiXVPnjg48w5M+eb+Q5nAtHlB3iz/QypjApVzSKfzyGfz49AVVWk02lCNpNFJpMZxBKpVAq5XA7xeByBXz9/4Nj2Pn7G8so6VtY28CQUIQRXFbx8tQ2z0+mf8nGaVSoVBIrfSoPEw8chnJ+YxtSVeUzOXMfU7DwuTMzg+YvXEEKg067ioLGPw1oNBuPwfQ+O48C2baovFAoIlEp/CMPKJi5fXcCtpXtYWLxDXsZf9r/SvtY8gs4O0Wxx6LoAMzTKu65LXnIFyuXyEGEUs3M3sbh0Hzdu3yUv470Pn2i/XudgDNBbPppaByZn1IFTCR8Fwzh3cZKkXpq+Rl7Gu+/e075hmNA0Dk3rwuI9mb7vw/O8IcKBZAe7b3cQDIUR2dxC5GkUysYWVtfWUf5eHip2qXe9+C+EfrsG86iKhiYlAKbZv8YBGg0Bw+CwLIeKORcQjgPXs8YQ9iXLYbCEAb1VAWMH0Fkdti3QaHbBmE1r13WoX2bXAuccQpjjCHsv9FwPnif74pL8Y4knbSQ3VnL/hTLpuh5Jky+w7TblZMG/MEJYLBYpkMMph9eybJJj25yG9iwYGexqtYr/ZfT1FEWhz55IJJBMJsn31r34LJDnJUcsFsNvZ1HP2KVgEaoAAAAASUVORK5CYII='); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"alt text\"\n        title=\"alt text\"\n        src=\"/static/c306fa1832402834f73c18a7bc391d4d/f058b/image.png\"\n        srcset=\"/static/c306fa1832402834f73c18a7bc391d4d/c26ae/image.png 158w,\n/static/c306fa1832402834f73c18a7bc391d4d/6bdcf/image.png 315w,\n/static/c306fa1832402834f73c18a7bc391d4d/f058b/image.png 630w,\n/static/c306fa1832402834f73c18a7bc391d4d/40601/image.png 945w,\n/static/c306fa1832402834f73c18a7bc391d4d/78612/image.png 1260w,\n/static/c306fa1832402834f73c18a7bc391d4d/da18d/image.png 2924w\"\n        sizes=\"(max-width: 630px) 100vw, 630px\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        loading=\"lazy\"\n        decoding=\"async\"\n      />\n  </a>\n    </span></p>\n<h2 id=\"setting-up-clerk\" style=\"position:relative;\"><a href=\"#setting-up-clerk\" aria-label=\"setting up clerk permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Setting Up Clerk</h2>\n<p>Let’s start by integrating Clerk for authentication. Clerk provides a powerful auth-as-a-service with pre-built React components, so most of this is straightforward setup.</p>\n<h3 id=\"1-sign-up-for-clerk\" style=\"position:relative;\"><a href=\"#1-sign-up-for-clerk\" aria-label=\"1 sign up for clerk permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>1. Sign Up for Clerk</h3>\n<p>Go to Clerk’s website and create an account. After signing up, log in to the Clerk dashboard, where you can manage your applications and auth settings.</p>\n<h3 id=\"2-create-a-new-clerk-application\" style=\"position:relative;\"><a href=\"#2-create-a-new-clerk-application\" aria-label=\"2 create a new clerk application permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>2. Create a New Clerk Application</h3>\n<p>In your Clerk dashboard:</p>\n<ol>\n<li>Click <strong>Create Application</strong> and give it a name (e.g. <em>Mermaid Visualizer</em>).</li>\n<li>Choose your auth methods. (For simplicity, we’ll enable only the email authentication method in this demo.)</li>\n<li>Clerk will then guide you to install its SDK and configure your app.</li>\n</ol>\n<h3 id=\"3-install-the-clerk-sdk\" style=\"position:relative;\"><a href=\"#3-install-the-clerk-sdk\" aria-label=\"3 install the clerk sdk permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>3. Install the Clerk SDK</h3>\n<p>In your project directory, install Clerk’s Next.js SDK:</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"77342056405660500000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"Copied!\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`# If you're using npm \nnpm install @clerk/nextjs\n\n# If you're using yarn \nyarn add @clerk/nextjs\n\n# If you're using pnpm\npnpm add @clerk/nextjs`, `77342056405660500000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                <svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token comment\"># If you're using npm </span>\n<span class=\"token function\">npm</span> <span class=\"token function\">install</span> @clerk/nextjs\n\n<span class=\"token comment\"># If you're using yarn </span>\n<span class=\"token function\">yarn</span> <span class=\"token function\">add</span> @clerk/nextjs\n\n<span class=\"token comment\"># If you're using pnpm</span>\n<span class=\"token function\">pnpm</span> <span class=\"token function\">add</span> @clerk/nextjs</code></pre></div>\n<p>This SDK gives you React components (like <code class=\"language-text\">SignInButton</code>) and server helpers for middleware.</p>\n<h3 id=\"4-set-your-clerk-api-keys\" style=\"position:relative;\"><a href=\"#4-set-your-clerk-api-keys\" aria-label=\"4 set your clerk api keys permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>4. Set your Clerk API keys</h3>\n<p>Add these keys to your <code class=\"language-text\">.env</code> file, or create the file if it doesn’t exist.</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"43116565010222720000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"Copied!\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=your-clerk-key\nCLERK_SECRET_KEY=your-clerk-secret`, `43116565010222720000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                <svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=your-clerk-key\nCLERK_SECRET_KEY=your-clerk-secret</code></pre></div>\n<h3 id=\"5-update-middlewarets\" style=\"position:relative;\"><a href=\"#5-update-middlewarets\" aria-label=\"5 update middlewarets permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>5. Update <code class=\"language-text\">middleware.ts</code></h3>\n<p>Update your middleware file, or create one at the <strong>root</strong> of your project, or the <strong>src/</strong> directory if you’re using a src/ directory structure.</p>\n<p>The <code class=\"language-text\">clerkMiddleware</code> helper enables authentication and is where you’ll configure your protected routes.</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"6209035426455834000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"Copied!\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`import { clerkMiddleware } from &quot;@clerk/nextjs/server&quot;;\n\nexport default clerkMiddleware();\n\nexport const config = {\n  matcher: [\n    // Skip Next.js internals and all static files, unless found in search params\n    '/((?!_next|[^?]*\\\\.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest)).*)',\n    // Always run for API routes\n    '/(api|trpc)(.*)',\n  ],\n};`, `6209035426455834000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                <svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> clerkMiddleware <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">\"@clerk/nextjs/server\"</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> <span class=\"token function\">clerkMiddleware</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">const</span> config <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token literal-property property\">matcher</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span>\n    <span class=\"token comment\">// Skip Next.js internals and all static files, unless found in search params</span>\n    <span class=\"token string\">'/((?!_next|[^?]*\\\\.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest)).*)'</span><span class=\"token punctuation\">,</span>\n    <span class=\"token comment\">// Always run for API routes</span>\n    <span class=\"token string\">'/(api|trpc)(.*)'</span><span class=\"token punctuation\">,</span>\n  <span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></code></pre></div>\n<h3 id=\"6-add-clerkprovider-and-the-signupsignin-buttons\" style=\"position:relative;\"><a href=\"#6-add-clerkprovider-and-the-signupsignin-buttons\" aria-label=\"6 add clerkprovider and the signupsignin buttons permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>6. Add ClerkProvider and the SignUp/SignIn Buttons</h3>\n<p>To enable Clerk throughout your app, you’ll use the ClerkProvider in your layout.tsx file.</p>\n<p>Here’s what to do:</p>\n<ul>\n<li><strong>Import the necessary components</strong> from <code class=\"language-text\">@clerk/nextjs</code>.</li>\n<li><strong>Wrap your app</strong> with <code class=\"language-text\">ClerkProvider</code> to make Clerk’s features available globally.</li>\n<li>Use <code class=\"language-text\">SignedOut</code> to wrap the <code class=\"language-text\">SignInButton</code> and<code class=\"language-text\">SignUpButton</code>. These will only appear when the user is signed out.</li>\n<li>Use <code class=\"language-text\">SignedIn</code> to wrap both the <code class=\"language-text\">UserButton</code> and your app’s content. These will only show when the user is signed in.</li>\n</ul>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"33080198856391150000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"Copied!\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`import { type Metadata } from &quot;next&quot;;\nimport { Geist, Geist_Mono } from &quot;next/font/google&quot;;\nimport &quot;./globals.css&quot;;\n// 🔐 Clerk components for authentication flows\nimport {\n  ClerkProvider, // Wraps your app to provide authentication context\n  SignInButton, // Renders a sign-in button that opens Clerk's sign-in modal\n  SignUpButton, // Renders a sign-up button that opens Clerk's sign-up modal\n  SignedIn, // Conditionally renders children *only* if the user is signed in\n  SignedOut, // Conditionally renders children *only* if the user is signed out\n  UserButton, // Displays the user's avatar with a dropdown for account management\n} from '@clerk/nextjs'\n\nconst geistSans = Geist({\n  variable: &quot;--font-geist-sans&quot;,\n  subsets: [&quot;latin&quot;],\n});\n\nconst geistMono = Geist_Mono({\n  variable: &quot;--font-geist-mono&quot;,\n  subsets: [&quot;latin&quot;],\n});\n\nexport const metadata: Metadata = {\n  title: &quot;Create Next App&quot;,\n  description: &quot;Generated by create next app&quot;,\n};\n\nexport default function RootLayout({\n  children,\n}: Readonly<{\n  children: React.ReactNode;\n}>) {\n  return (\n    // ✅ ClerkProvider wraps the entire app, enabling access to auth state and Clerk components\n    <ClerkProvider>\n      <html lang=&quot;en&quot;>\n        <body className={\\`\\${geistSans.variable} \\${geistMono.variable} antialiased\\`} >\n          <header className=&quot;p-5&quot;>\n\n          {/* 👋 Show these only when the user is signed out */}\n          <SignedOut>\n            <SignInButton /> {/* Opens a modal for users to sign in */}\n            <SignUpButton /> {/* Opens a modal for users to create an account */}\n          </SignedOut>\n\n          {/* 🙌 Show these only when the user is signed in */}\n          <SignedIn>\n            <UserButton /> {/* Shows user profile options like sign out */}\n            {children}  {/* Show the app content only to signed-in users */}\n          </SignedIn>\n          \n        </header>\n        </body>\n      </html>\n    </ClerkProvider>\n  );\n}`, `33080198856391150000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                <svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight has-highlighted-lines\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> type Metadata <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">\"next\"</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> Geist<span class=\"token punctuation\">,</span> Geist_Mono <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">\"next/font/google\"</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">import</span> <span class=\"token string\">\"./globals.css\"</span><span class=\"token punctuation\">;</span>\n<span class=\"gatsby-highlight-code-line\"><span class=\"token comment\">// 🔐 Clerk components for authentication flows</span></span><span class=\"gatsby-highlight-code-line\"><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span></span><span class=\"gatsby-highlight-code-line\">  ClerkProvider<span class=\"token punctuation\">,</span> <span class=\"token comment\">// Wraps your app to provide authentication context</span></span><span class=\"gatsby-highlight-code-line\">  SignInButton<span class=\"token punctuation\">,</span> <span class=\"token comment\">// Renders a sign-in button that opens Clerk's sign-in modal</span></span><span class=\"gatsby-highlight-code-line\">  SignUpButton<span class=\"token punctuation\">,</span> <span class=\"token comment\">// Renders a sign-up button that opens Clerk's sign-up modal</span></span><span class=\"gatsby-highlight-code-line\">  SignedIn<span class=\"token punctuation\">,</span> <span class=\"token comment\">// Conditionally renders children *only* if the user is signed in</span></span><span class=\"gatsby-highlight-code-line\">  SignedOut<span class=\"token punctuation\">,</span> <span class=\"token comment\">// Conditionally renders children *only* if the user is signed out</span></span><span class=\"gatsby-highlight-code-line\">  UserButton<span class=\"token punctuation\">,</span> <span class=\"token comment\">// Displays the user's avatar with a dropdown for account management</span></span><span class=\"gatsby-highlight-code-line\"><span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">'@clerk/nextjs'</span></span>\n<span class=\"token keyword\">const</span> geistSans <span class=\"token operator\">=</span> <span class=\"token function\">Geist</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n  <span class=\"token literal-property property\">variable</span><span class=\"token operator\">:</span> <span class=\"token string\">\"--font-geist-sans\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token literal-property property\">subsets</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">\"latin\"</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">const</span> geistMono <span class=\"token operator\">=</span> <span class=\"token function\">Geist_Mono</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n  <span class=\"token literal-property property\">variable</span><span class=\"token operator\">:</span> <span class=\"token string\">\"--font-geist-mono\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token literal-property property\">subsets</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span><span class=\"token string\">\"latin\"</span><span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">const</span> <span class=\"token literal-property property\">metadata</span><span class=\"token operator\">:</span> Metadata <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token literal-property property\">title</span><span class=\"token operator\">:</span> <span class=\"token string\">\"Create Next App\"</span><span class=\"token punctuation\">,</span>\n  <span class=\"token literal-property property\">description</span><span class=\"token operator\">:</span> <span class=\"token string\">\"Generated by create next app\"</span><span class=\"token punctuation\">,</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> <span class=\"token keyword\">function</span> <span class=\"token function\">RootLayout</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span>\n  children<span class=\"token punctuation\">,</span>\n<span class=\"token punctuation\">}</span><span class=\"token operator\">:</span> Readonly<span class=\"token operator\">&lt;</span><span class=\"token punctuation\">{</span>\n  <span class=\"token literal-property property\">children</span><span class=\"token operator\">:</span> React<span class=\"token punctuation\">.</span>ReactNode<span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span><span class=\"token operator\">></span></span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">return</span> <span class=\"token punctuation\">(</span>\n    <span class=\"token comment\">// ✅ ClerkProvider wraps the entire app, enabling access to auth state and Clerk components</span>\n<span class=\"gatsby-highlight-code-line\">    <span class=\"token operator\">&lt;</span>ClerkProvider<span class=\"token operator\">></span></span>      <span class=\"token operator\">&lt;</span>html lang<span class=\"token operator\">=</span><span class=\"token string\">\"en\"</span><span class=\"token operator\">></span>\n        <span class=\"token operator\">&lt;</span>body className<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token template-string\"><span class=\"token template-punctuation string\">`</span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>geistSans<span class=\"token punctuation\">.</span>variable<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\"> </span><span class=\"token interpolation\"><span class=\"token interpolation-punctuation punctuation\">${</span>geistMono<span class=\"token punctuation\">.</span>variable<span class=\"token interpolation-punctuation punctuation\">}</span></span><span class=\"token string\"> antialiased</span><span class=\"token template-punctuation string\">`</span></span><span class=\"token punctuation\">}</span> <span class=\"token operator\">></span>\n          <span class=\"token operator\">&lt;</span>header className<span class=\"token operator\">=</span><span class=\"token string\">\"p-5\"</span><span class=\"token operator\">></span>\n\n<span class=\"gatsby-highlight-code-line\">          <span class=\"token punctuation\">{</span><span class=\"token comment\">/* 👋 Show these only when the user is signed out */</span><span class=\"token punctuation\">}</span></span><span class=\"gatsby-highlight-code-line\">          <span class=\"token operator\">&lt;</span>SignedOut<span class=\"token operator\">></span></span><span class=\"gatsby-highlight-code-line\">            <span class=\"token operator\">&lt;</span>SignInButton <span class=\"token operator\">/</span><span class=\"token operator\">></span> <span class=\"token punctuation\">{</span><span class=\"token comment\">/* Opens a modal for users to sign in */</span><span class=\"token punctuation\">}</span></span><span class=\"gatsby-highlight-code-line\">            <span class=\"token operator\">&lt;</span>SignUpButton <span class=\"token operator\">/</span><span class=\"token operator\">></span> <span class=\"token punctuation\">{</span><span class=\"token comment\">/* Opens a modal for users to create an account */</span><span class=\"token punctuation\">}</span></span><span class=\"gatsby-highlight-code-line\">          <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>SignedOut<span class=\"token operator\">></span></span>\n<span class=\"gatsby-highlight-code-line\">          <span class=\"token punctuation\">{</span><span class=\"token comment\">/* 🙌 Show these only when the user is signed in */</span><span class=\"token punctuation\">}</span></span><span class=\"gatsby-highlight-code-line\">          <span class=\"token operator\">&lt;</span>SignedIn<span class=\"token operator\">></span></span><span class=\"gatsby-highlight-code-line\">            <span class=\"token operator\">&lt;</span>UserButton <span class=\"token operator\">/</span><span class=\"token operator\">></span> <span class=\"token punctuation\">{</span><span class=\"token comment\">/* Shows user profile options like sign out */</span><span class=\"token punctuation\">}</span></span><span class=\"gatsby-highlight-code-line\">            <span class=\"token punctuation\">{</span>children<span class=\"token punctuation\">}</span>  <span class=\"token punctuation\">{</span><span class=\"token comment\">/* Show the app content only to signed-in users */</span><span class=\"token punctuation\">}</span></span><span class=\"gatsby-highlight-code-line\">          <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>SignedIn<span class=\"token operator\">></span></span>          \n        <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>header<span class=\"token operator\">></span>\n        <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>body<span class=\"token operator\">></span>\n      <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>html<span class=\"token operator\">></span>\n<span class=\"gatsby-highlight-code-line\">    <span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>ClerkProvider<span class=\"token operator\">></span></span>  <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>🎉 And that’s it! You’ve now set up Clerk for user authentication in your app. Users can sign in, sign up, and see personalized content based on their auth state.</p>\n<h3 id=\"7-run-your-project-and-get-your-first-user\" style=\"position:relative;\"><a href=\"#7-run-your-project-and-get-your-first-user\" aria-label=\"7 run your project and get your first user permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>7. Run Your Project and Get Your First User</h3>\n<p>Start your dev server:</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"7712212621888170000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"Copied!\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`# If you're using npm \nnpm run dev\n\n# If you're using yarn \nyarn dev\n\n# If you're using pnpm\npnpm dev`, `7712212621888170000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                <svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token comment\"># If you're using npm </span>\n<span class=\"token function\">npm</span> run dev\n\n<span class=\"token comment\"># If you're using yarn </span>\n<span class=\"token function\">yarn</span> dev\n\n<span class=\"token comment\"># If you're using pnpm</span>\n<span class=\"token function\">pnpm</span> dev</code></pre></div>\n<p>Once it’s running, head to <code class=\"language-text\">http://localhost:3000</code> in your browser. You should see your app with sign-in and sign-up options. Go ahead and register—this will create your first authenticated user.</p>\n<p>Next up, we’ll connect Supabase and set it up to store user-specific data like saved Mermaid charts.</p>\n<h2 id=\"setting-up-supabase-with-clerk\" style=\"position:relative;\"><a href=\"#setting-up-supabase-with-clerk\" aria-label=\"setting up supabase with clerk permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Setting Up Supabase with Clerk</h2>\n<p>To integrate Supabase with your Next.js project and secure user-specific data using Clerk authentication, follow these steps:</p>\n<h3 id=\"1-create-a-supabase-project\" style=\"position:relative;\"><a href=\"#1-create-a-supabase-project\" aria-label=\"1 create a supabase project permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>1. Create a Supabase Project</h3>\n<ul>\n<li>Visit <a href=\"https://supabase.com/\" target=\"_blank\" rel=\"nofollow\">supabase.com</a> and sign up for a free account.</li>\n<li>Once inside the dashboard, click <strong>“New Project”</strong>.</li>\n<li>Choose a <strong>Project Name</strong> (e.g. <em>Mermaid Visualizer</em>), select the <strong>closest region</strong> for your users, and set a strong password (you can use the “Generate Password” feature).</li>\n<li>Save this password in your password manager.</li>\n</ul>\n<h3 id=\"2-install-supabase-client\" style=\"position:relative;\"><a href=\"#2-install-supabase-client\" aria-label=\"2 install supabase client permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>2. Install Supabase Client</h3>\n<p>Install the Supabase JavaScript client in your project:</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"674847078938944900\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"Copied!\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`npm install @supabase/supabase-js`, `674847078938944900`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                <svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"bash\"><pre class=\"language-bash\"><code class=\"language-bash\"><span class=\"token function\">npm</span> <span class=\"token function\">install</span> @supabase/supabase-js</code></pre></div>\n<h3 id=\"3-connect-clerk-to-supabase-new-2025-flow\" style=\"position:relative;\"><a href=\"#3-connect-clerk-to-supabase-new-2025-flow\" aria-label=\"3 connect clerk to supabase new 2025 flow permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>3. Connect Clerk to Supabase (New 2025 Flow)</h3>\n<p>As of April 2025, Supabase has updated its integration method with Clerk from JWT templates to native third-party support, which simplifies setup and improves security.</p>\n<ol>\n<li><strong>Configure Clerk for Supabase:</strong> In your Clerk dashboard, navigate to API Keys and enable Supabase compatibility.</li>\n<li><strong>Add Clerk as a Third-Party Auth Provider in Supabase:</strong> In Supabase, go to <strong>Authentication > Providers > External OAuth</strong> and select <strong>Clerk</strong>. You’ll need to input the <strong>Issuer URL</strong> and <strong>JWKS endpoint</strong> from Clerk (Clerk’s docs or connect page will show you what values to use).</li>\n</ol>\n<h3 id=\"4-set-up-row-level-security-rls-with-clerk\" style=\"position:relative;\"><a href=\"#4-set-up-row-level-security-rls-with-clerk\" aria-label=\"4 set up row level security rls with clerk permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>4. Set Up Row-Level Security (RLS) with Clerk</h3>\n<p>By default, Supabase uses its own <code class=\"language-text\">auth.uid()</code> method, which doesn’t work when using Clerk. To fix that, we’ll extract the authenticated user’s ID from the Clerk-provided JWT.</p>\n<h4 id=\"create-a-helper-function-for-clerk-ids\" style=\"position:relative;\"><a href=\"#create-a-helper-function-for-clerk-ids\" aria-label=\"create a helper function for clerk ids permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Create a Helper Function for Clerk IDs</h4>\n<p>In Supabase’s SQL Editor, paste the following:</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"95280324012653380000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"Copied!\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`CREATE OR REPLACE FUNCTION requesting_user_id()\nRETURNS TEXT AS \\$\\$\n  SELECT NULLIF(\n    current_setting('request.jwt.claims', true)::json->>'sub',\n    ''\n  )::text;\n\\$\\$ LANGUAGE SQL STABLE;`, `95280324012653380000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                <svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"sql\"><pre class=\"language-sql\"><code class=\"language-sql\"><span class=\"token keyword\">CREATE</span> <span class=\"token operator\">OR</span> <span class=\"token keyword\">REPLACE</span> <span class=\"token keyword\">FUNCTION</span> requesting_user_id<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n<span class=\"token keyword\">RETURNS</span> <span class=\"token keyword\">TEXT</span> <span class=\"token keyword\">AS</span> $$\n  <span class=\"token keyword\">SELECT</span> <span class=\"token keyword\">NULLIF</span><span class=\"token punctuation\">(</span>\n    current_setting<span class=\"token punctuation\">(</span><span class=\"token string\">'request.jwt.claims'</span><span class=\"token punctuation\">,</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">)</span>::json<span class=\"token operator\">-</span><span class=\"token operator\">>></span><span class=\"token string\">'sub'</span><span class=\"token punctuation\">,</span>\n    <span class=\"token string\">''</span>\n  <span class=\"token punctuation\">)</span>::<span class=\"token keyword\">text</span><span class=\"token punctuation\">;</span>\n$$ <span class=\"token keyword\">LANGUAGE</span> <span class=\"token keyword\">SQL</span> STABLE<span class=\"token punctuation\">;</span></code></pre></div>\n<p>This function safely retrieves the authenticated Clerk user ID from the incoming JWT token.</p>\n<h4 id=\"create-the-charts-table\" style=\"position:relative;\"><a href=\"#create-the-charts-table\" aria-label=\"create the charts table permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Create the <code class=\"language-text\">charts</code> Table</h4>\n<p>Run the following SQL to create a table and enable RLS with Clerk support:</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"57760123980819310000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"Copied!\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`create table if not exists charts (\n  id UUID default gen_random_uuid() primary key,\n  content text not null,\n  user_id text not null,\n  created_at timestamptz default now()\n);`, `57760123980819310000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                <svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"sql\"><pre class=\"language-sql\"><code class=\"language-sql\"><span class=\"token keyword\">create</span> <span class=\"token keyword\">table</span> <span class=\"token keyword\">if</span> <span class=\"token operator\">not</span> <span class=\"token keyword\">exists</span> charts <span class=\"token punctuation\">(</span>\n  id UUID <span class=\"token keyword\">default</span> gen_random_uuid<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token keyword\">primary</span> <span class=\"token keyword\">key</span><span class=\"token punctuation\">,</span>\n  content <span class=\"token keyword\">text</span> <span class=\"token operator\">not</span> <span class=\"token boolean\">null</span><span class=\"token punctuation\">,</span>\n  user_id <span class=\"token keyword\">text</span> <span class=\"token operator\">not</span> <span class=\"token boolean\">null</span><span class=\"token punctuation\">,</span>\n  created_at timestamptz <span class=\"token keyword\">default</span> <span class=\"token function\">now</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre></div>\n<h4 id=\"add-rls-policies-the-right-way-for-clerk\" style=\"position:relative;\"><a href=\"#add-rls-policies-the-right-way-for-clerk\" aria-label=\"add rls policies the right way for clerk permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Add RLS Policies (the Right Way for Clerk)</h4>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"87742739946475180000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"Copied!\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`alter table charts enable row level security;\n\ncreate policy &quot;Users can insert their own charts&quot;\n  on charts\n  for insert\n  with check (\n    user_id = current_setting('request.jwt.claims', true)::json->>'sub'\n  );\n\ncreate policy &quot;Users can view their own charts&quot;\n  on charts\n  for select\n  using (\n    user_id = current_setting('request.jwt.claims', true)::json->>'sub'\n  );`, `87742739946475180000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                <svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"sql\"><pre class=\"language-sql\"><code class=\"language-sql\"><span class=\"token keyword\">alter</span> <span class=\"token keyword\">table</span> charts <span class=\"token keyword\">enable</span> <span class=\"token keyword\">row</span> <span class=\"token keyword\">level</span> security<span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">create</span> policy <span class=\"token string\">\"Users can insert their own charts\"</span>\n  <span class=\"token keyword\">on</span> charts\n  <span class=\"token keyword\">for</span> <span class=\"token keyword\">insert</span>\n  <span class=\"token keyword\">with</span> <span class=\"token keyword\">check</span> <span class=\"token punctuation\">(</span>\n    user_id <span class=\"token operator\">=</span> current_setting<span class=\"token punctuation\">(</span><span class=\"token string\">'request.jwt.claims'</span><span class=\"token punctuation\">,</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">)</span>::json<span class=\"token operator\">-</span><span class=\"token operator\">>></span><span class=\"token string\">'sub'</span>\n  <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">create</span> policy <span class=\"token string\">\"Users can view their own charts\"</span>\n  <span class=\"token keyword\">on</span> charts\n  <span class=\"token keyword\">for</span> <span class=\"token keyword\">select</span>\n  <span class=\"token keyword\">using</span> <span class=\"token punctuation\">(</span>\n    user_id <span class=\"token operator\">=</span> current_setting<span class=\"token punctuation\">(</span><span class=\"token string\">'request.jwt.claims'</span><span class=\"token punctuation\">,</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">)</span>::json<span class=\"token operator\">-</span><span class=\"token operator\">>></span><span class=\"token string\">'sub'</span>\n  <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span></code></pre></div>\n<h4 id=\"common-pitfall-authuid-returns-null\" style=\"position:relative;\"><a href=\"#common-pitfall-authuid-returns-null\" aria-label=\"common pitfall authuid returns null permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Common Pitfall: <code class=\"language-text\">auth.uid()</code> Returns NULL</h4>\n<p>If you previously used this:</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"22106817915741872000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"Copied!\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`USING (auth.uid()::text = user_id)`, `22106817915741872000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                <svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"sql\"><pre class=\"language-sql\"><code class=\"language-sql\"><span class=\"token keyword\">USING</span> <span class=\"token punctuation\">(</span>auth<span class=\"token punctuation\">.</span>uid<span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>::<span class=\"token keyword\">text</span> <span class=\"token operator\">=</span> user_id<span class=\"token punctuation\">)</span></code></pre></div>\n<p>…it won’t work with Clerk. Why?</p>\n<ul>\n<li><code class=\"language-text\">auth.uid()</code> is only available if you’re using <strong>Supabase Auth</strong>, which we’re not.</li>\n<li>Clerk user IDs are strings like <code class=\"language-text\">\"user_2w2a6PJC4T4BfXDsg72AQsLNEyU\"</code>, which are not UUIDs.</li>\n<li>This mismatch causes errors like:\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"20586418208238120000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"Copied!\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`invalid input syntax for type uuid: &quot;user_...&quot;`, `20586418208238120000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                <svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"text\"><pre class=\"language-text\"><code class=\"language-text\">invalid input syntax for type uuid: \"user_...\"</code></pre></div>\n</li>\n</ul>\n<p><strong>The Fix:</strong>\nUse this pattern instead:</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"89631604091959000000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"Copied!\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`current_setting('request.jwt.claims', true)::json->>'sub'`, `89631604091959000000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                <svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"sql\"><pre class=\"language-sql\"><code class=\"language-sql\">current_setting<span class=\"token punctuation\">(</span><span class=\"token string\">'request.jwt.claims'</span><span class=\"token punctuation\">,</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">)</span>::json<span class=\"token operator\">-</span><span class=\"token operator\">>></span><span class=\"token string\">'sub'</span></code></pre></div>\n<p>This safely extracts the sub field (i.e. the Clerk user ID) from the JWT, allowing you to scope data per user, securely and correctly.</p>\n<h2 id=\"integrating-clerk-and-supabase-in-nextjs\" style=\"position:relative;\"><a href=\"#integrating-clerk-and-supabase-in-nextjs\" aria-label=\"integrating clerk and supabase in nextjs permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Integrating Clerk and Supabase in Next.js</h2>\n<p>Clerk and Supabase work together seamlessly to manage authentication and user-specific data in your Next.js app. Here’s how the integration functions:</p>\n<ol>\n<li><strong>Authentication with Clerk</strong>: When a user logs in, Clerk authenticates them and generates a unique user ID and session token.</li>\n<li><strong>Data Storage with Supabase</strong>: That user ID is used to store and retrieve data (e.g. Mermaid charts) in the Supabase database, scoped to the logged-in user.</li>\n</ol>\n<p>Let’s break down how to implement this integration in code:</p>\n<h3 id=\"middleware-for-clerk-authentication\" style=\"position:relative;\"><a href=\"#middleware-for-clerk-authentication\" aria-label=\"middleware for clerk authentication permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Middleware for Clerk Authentication</h3>\n<p>The <code class=\"language-text\">middleware.ts</code> file ensures that all routes requiring authentication are protected by Clerk. It intercepts requests and verifies the session before allowing access:</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"52986137121458274000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"Copied!\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`import { clerkMiddleware } from &quot;@clerk/nextjs/server&quot;;\n\nexport default clerkMiddleware();\n\nexport const config = {\n  matcher: [\n    '/((?!_next|[^?]*\\\\.(?:html?|css|js|png|svg)).*)',\n    '/(api|trpc)(.*)',\n  ],\n};`, `52986137121458274000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                <svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> clerkMiddleware <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">\"@clerk/nextjs/server\"</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> <span class=\"token function\">clerkMiddleware</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">const</span> config <span class=\"token operator\">=</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token literal-property property\">matcher</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">[</span>\n    <span class=\"token string\">'/((?!_next|[^?]*\\\\.(?:html?|css|js|png|svg)).*)'</span><span class=\"token punctuation\">,</span>\n    <span class=\"token string\">'/(api|trpc)(.*)'</span><span class=\"token punctuation\">,</span>\n  <span class=\"token punctuation\">]</span><span class=\"token punctuation\">,</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></code></pre></div>\n<h3 id=\"supabase-provider-with-clerk-session-token\" style=\"position:relative;\"><a href=\"#supabase-provider-with-clerk-session-token\" aria-label=\"supabase provider with clerk session token permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Supabase Provider with Clerk Session Token</h3>\n<p>In order to securely access Supabase on behalf of the authenticated user, we initialize a Supabase client using the session token provided by Clerk:</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"12104934275918412000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"Copied!\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`import { createClient } from &quot;@supabase/supabase-js&quot;;\nimport { useSession } from &quot;@clerk/nextjs&quot;;\n\nexport default function SupabaseProvider({ children }: { children: React.ReactNode }) {\n  const { session } = useSession();\n  const supabase = createClient(\n    process.env.NEXT_PUBLIC_SUPABASE_URL!,\n    process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!, { \n      accessToken: () => session?.getToken() \n    }\n  );\n\n  return <Context.Provider value={{ supabase }}>{children}</Context.Provider>;\n}`, `12104934275918412000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                <svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> createClient <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">\"@supabase/supabase-js\"</span><span class=\"token punctuation\">;</span>\n<span class=\"token keyword\">import</span> <span class=\"token punctuation\">{</span> useSession <span class=\"token punctuation\">}</span> <span class=\"token keyword\">from</span> <span class=\"token string\">\"@clerk/nextjs\"</span><span class=\"token punctuation\">;</span>\n\n<span class=\"token keyword\">export</span> <span class=\"token keyword\">default</span> <span class=\"token keyword\">function</span> <span class=\"token function\">SupabaseProvider</span><span class=\"token punctuation\">(</span><span class=\"token parameter\"><span class=\"token punctuation\">{</span> children <span class=\"token punctuation\">}</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span> <span class=\"token literal-property property\">children</span><span class=\"token operator\">:</span> React<span class=\"token punctuation\">.</span>ReactNode <span class=\"token punctuation\">}</span></span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> session <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> <span class=\"token function\">useSession</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n  <span class=\"token keyword\">const</span> supabase <span class=\"token operator\">=</span> <span class=\"token function\">createClient</span><span class=\"token punctuation\">(</span>\n    process<span class=\"token punctuation\">.</span>env<span class=\"token punctuation\">.</span><span class=\"token constant\">NEXT_PUBLIC_SUPABASE_URL</span><span class=\"token operator\">!</span><span class=\"token punctuation\">,</span>\n    process<span class=\"token punctuation\">.</span>env<span class=\"token punctuation\">.</span><span class=\"token constant\">NEXT_PUBLIC_SUPABASE_ANON_KEY</span><span class=\"token operator\">!</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span> \n      <span class=\"token function-variable function\">accessToken</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> session<span class=\"token operator\">?.</span><span class=\"token function\">getToken</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> \n    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n  <span class=\"token keyword\">return</span> <span class=\"token operator\">&lt;</span>Context<span class=\"token punctuation\">.</span>Provider value<span class=\"token operator\">=</span><span class=\"token punctuation\">{</span><span class=\"token punctuation\">{</span> supabase <span class=\"token punctuation\">}</span><span class=\"token punctuation\">}</span><span class=\"token operator\">></span><span class=\"token punctuation\">{</span>children<span class=\"token punctuation\">}</span><span class=\"token operator\">&lt;</span><span class=\"token operator\">/</span>Context<span class=\"token punctuation\">.</span>Provider<span class=\"token operator\">></span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<h2 id=\"code-walkthrough\" style=\"position:relative;\"><a href=\"#code-walkthrough\" aria-label=\"code walkthrough permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Code Walkthrough</h2>\n<p>You can explore the full codebase in the <a href=\"https://github.com/meems1996/mermaid-charting-app\" target=\"_blank\" rel=\"nofollow\">GitHub repository</a>.</p>\n<h3 id=\"saving-charts\" style=\"position:relative;\"><a href=\"#saving-charts\" aria-label=\"saving charts permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Saving Charts</h3>\n<p>The <code class=\"language-text\">handleSave</code> function stores a Mermaid chart in your Supabase database, associating it with the currently logged-in user:</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"18049940067534154000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"Copied!\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`const handleSave = async () => {\n  if (!supabase || !user) return;\n\n  const { data, error } = await supabase\n    .from('charts')\n    .insert({ content: code, user_id: user.id });\n\n  if (error) console.error('Error saving chart:', error);\n};`, `18049940067534154000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                <svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">handleSave</span> <span class=\"token operator\">=</span> <span class=\"token keyword\">async</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span><span class=\"token operator\">!</span>supabase <span class=\"token operator\">||</span> <span class=\"token operator\">!</span>user<span class=\"token punctuation\">)</span> <span class=\"token keyword\">return</span><span class=\"token punctuation\">;</span>\n\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> data<span class=\"token punctuation\">,</span> error <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> supabase\n    <span class=\"token punctuation\">.</span><span class=\"token function\">from</span><span class=\"token punctuation\">(</span><span class=\"token string\">'charts'</span><span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">.</span><span class=\"token function\">insert</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span> <span class=\"token literal-property property\">content</span><span class=\"token operator\">:</span> code<span class=\"token punctuation\">,</span> <span class=\"token literal-property property\">user_id</span><span class=\"token operator\">:</span> user<span class=\"token punctuation\">.</span>id <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>error<span class=\"token punctuation\">)</span> console<span class=\"token punctuation\">.</span><span class=\"token function\">error</span><span class=\"token punctuation\">(</span><span class=\"token string\">'Error saving chart:'</span><span class=\"token punctuation\">,</span> error<span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></code></pre></div>\n<h3 id=\"fetching-charts\" style=\"position:relative;\"><a href=\"#fetching-charts\" aria-label=\"fetching charts permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Fetching Charts</h3>\n<p>The <code class=\"language-text\">fetchCharts</code> function retrieves all charts for the authenticated user, ordered by creation time:</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"9237076688014901000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"Copied!\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`const fetchCharts = async () => {\n  const { data, error } = await supabase\n    .from('charts')\n    .select('content')\n    .order('created_at', { ascending: false });\n\n  if (data) setSavedCharts(data.map((item) => item.content));\n};`, `9237076688014901000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                <svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token keyword\">const</span> <span class=\"token function-variable function\">fetchCharts</span> <span class=\"token operator\">=</span> <span class=\"token keyword\">async</span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">const</span> <span class=\"token punctuation\">{</span> data<span class=\"token punctuation\">,</span> error <span class=\"token punctuation\">}</span> <span class=\"token operator\">=</span> <span class=\"token keyword\">await</span> supabase\n    <span class=\"token punctuation\">.</span><span class=\"token function\">from</span><span class=\"token punctuation\">(</span><span class=\"token string\">'charts'</span><span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">.</span><span class=\"token function\">select</span><span class=\"token punctuation\">(</span><span class=\"token string\">'content'</span><span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">.</span><span class=\"token function\">order</span><span class=\"token punctuation\">(</span><span class=\"token string\">'created_at'</span><span class=\"token punctuation\">,</span> <span class=\"token punctuation\">{</span> <span class=\"token literal-property property\">ascending</span><span class=\"token operator\">:</span> <span class=\"token boolean\">false</span> <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n\n  <span class=\"token keyword\">if</span> <span class=\"token punctuation\">(</span>data<span class=\"token punctuation\">)</span> <span class=\"token function\">setSavedCharts</span><span class=\"token punctuation\">(</span>data<span class=\"token punctuation\">.</span><span class=\"token function\">map</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">(</span><span class=\"token parameter\">item</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> item<span class=\"token punctuation\">.</span>content<span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">;</span>\n<span class=\"token punctuation\">}</span><span class=\"token punctuation\">;</span></code></pre></div>\n<h3 id=\"challenges-and-solutions\" style=\"position:relative;\"><a href=\"#challenges-and-solutions\" aria-label=\"challenges and solutions permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Challenges and Solutions</h3>\n<ul>\n<li><strong>Session Management</strong>: <br /><em>Challenge:</em> Ensure Clerk’s session is available before initializing Supabase. <br /><em>Solution:</em> Use useEffect to wait for the session before creating the Supabase client.</li>\n<li><strong>Error Handling</strong>: <br /><em>Challenge:</em> Errors when saving or fetching data can disrupt the UX.<br /><em>Solution:</em> Implement error checks and show clear feedback to the user.</li>\n</ul>\n<h2 id=\"what-about-session-security-the-hidden-risk-no-one-talks-about\" style=\"position:relative;\"><a href=\"#what-about-session-security-the-hidden-risk-no-one-talks-about\" aria-label=\"what about session security the hidden risk no one talks about permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>What About Session Security? (The Hidden Risk No One Talks About)</h2>\n<p>So far, Clerk + Supabase covers authentication (who the user is) and data access rules. But one aspect often overlooked is <strong>session security</strong>. Common risks include:</p>\n<ul>\n<li><strong>Stolen Tokens:</strong> If an attacker somehow obtains a user’s refresh token or access token (via XSS, device theft, etc.), they can impersonate that user until the token expires.</li>\n<li><strong>Replay Attacks:</strong> Without proper handling, someone could reuse an old valid refresh token to continue a session indefinitely.</li>\n<li><strong>Session Hijacking:</strong> If your system only allows a single session per user, an attacker who logs in on one device can knock out other sessions, and vice versa.</li>\n</ul>\n<p>Clerk and Supabase handle basic sessions well (Clerk rotates refresh tokens, etc.), but these advanced threats can still be concerns. This is where SuperTokens shines. It’s designed with <strong>advanced session security</strong> features.</p>\n<h2 id=\"how-supertokens-fixes-this-problem\" style=\"position:relative;\"><a href=\"#how-supertokens-fixes-this-problem\" aria-label=\"how supertokens fixes this problem permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>How SuperTokens Fixes This Problem</h2>\n<p><strong>SuperTokens</strong> puts session security at the forefront. Compared to Clerk or vanilla Supabase Auth, SuperTokens offers:</p>\n<ul>\n<li><strong>Self-hosted &#x26; fully customizable:</strong> You can self-host SuperTokens (or use the cloud hosting option). Because it’s open source, you have full control. This means you aren’t locked into a vendor.</li>\n<li><strong>Advanced session management:</strong> Out of the box, SuperTokens uses short-lived access tokens and rotating refresh tokens. Each time a refresh token is used, a new one is issued and the old one is invalidated. This one-time-use refresh scheme means a stolen refresh token is useless after first use.</li>\n<li><strong>Token theft detection &#x26; rotation:</strong> SuperTokens can detect if a refresh token is being reused (an anomaly indicating theft) and revoke all sessions for that user immediately.</li>\n<li><strong>Granular session revocation:</strong> You can revoke individual device sessions. For instance, SuperTokens provides backend functions like <code class=\"language-text\">Session.revokeSession(sessionHandle)</code> or <code class=\"language-text\">Session.revokeAllSessionsForUser(userId)</code>, letting you target a specific session or wipe all of a user’s sessions.</li>\n</ul>\n<p>These features directly mitigate the risks above:</p>\n<ul>\n<li><strong>Stolen token → short expiry &#x26; rotation:</strong> Even if an access token is stolen, it will expire quickly. If a refresh token is stolen, SuperTokens will notice its reuse and invalidate it, limiting damage to minutes.</li>\n<li><strong>Replay attacks → token rotation:</strong> Reusing a refresh token triggers detection. The user’s session can be revoked immediately, so replayed tokens get caught.</li>\n<li><strong>Hijacking → per-device logout:</strong> Users can log out of one device without logging out everywhere, since sessions are separate. An attacker in one session can be locked out while others stay intact.</li>\n</ul>\n<p>By design, SuperTokens “belongs in the backend” of your auth flow. You can still use Clerk’s or your own front end if you wish, but swap in SuperTokens on the server to handle sessions. In short, SuperTokens fixes session management in a way many providers don’t.</p>\n<h2 id=\"how-supertokens-handles-session-security-in-practice\" style=\"position:relative;\"><a href=\"#how-supertokens-handles-session-security-in-practice\" aria-label=\"how supertokens handles session security in practice permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>How SuperTokens Handles Session Security (In Practice)</h2>\n<p>Here’s a quick comparison of how these threats are handled:</p>\n<table>\n<thead>\n<tr>\n<th>Threat</th>\n<th>Risk Without Protection</th>\n<th>SuperTokens Defense</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>Token Theft</strong></td>\n<td>Attacker reuses a stolen refresh token indefinitely.</td>\n<td>Short-lived access tokens + rotating refresh tokens. If a refresh token is stolen and reused, SuperTokens detects the anomaly and revokes it.</td>\n</tr>\n<tr>\n<td><strong>Session Hijacking</strong></td>\n<td>Logging out all devices if a user is compromised on one.</td>\n<td>Per-session tokens: SuperTokens lets you revoke a single session handle (device) or all sessions for a user, avoiding a blanket logout.</td>\n</tr>\n<tr>\n<td><strong>Replay Attacks</strong></td>\n<td>A stolen refresh token could be saved and replayed.</td>\n<td>Refresh tokens are one-time-use. Reuse triggers detection; old tokens are invalidated.</td>\n</tr>\n</tbody>\n</table>\n<p><a href=\"https://supertokens.com/docs/post-authentication/session-management/security\" target=\"_blank\" rel=\"nofollow\">Learn more about how SuperTokens handles these threats.</a></p>\n<h2 id=\"clerk-vs-supabase-vs-supertokens\" style=\"position:relative;\"><a href=\"#clerk-vs-supabase-vs-supertokens\" aria-label=\"clerk vs supabase vs supertokens permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Clerk vs. Supabase vs. SuperTokens</h2>\n<table>\n<thead>\n<tr>\n<th>Feature</th>\n<th>Clerk 🧰</th>\n<th>Supabase 🗄️</th>\n<th>SuperTokens 🛡️</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td><strong>Pre-Built UI Components</strong></td>\n<td>✅ Yes</td>\n<td>❌ No</td>\n<td>✅ Yes (optional)</td>\n</tr>\n<tr>\n<td><strong>Custom Auth Flows</strong></td>\n<td>⚠️ Limited</td>\n<td>⚠️ Limited</td>\n<td>✅ Full flexibility</td>\n</tr>\n<tr>\n<td><strong>Session Management</strong></td>\n<td>⚠️ Basic</td>\n<td>⚠️ Basic</td>\n<td>✅ Advanced</td>\n</tr>\n<tr>\n<td><strong>Self-Hosting</strong></td>\n<td>❌ No</td>\n<td>✅ Yes (via CLI)</td>\n<td>✅ Yes</td>\n</tr>\n<tr>\n<td><strong>Token Theft Detection</strong></td>\n<td>❌ No</td>\n<td>❌ No</td>\n<td>✅ Yes</td>\n</tr>\n<tr>\n<td><strong>Fine-Grained Session Revocation</strong></td>\n<td>❌ No</td>\n<td>❌ No</td>\n<td>✅ Yes</td>\n</tr>\n</tbody>\n</table>\n<ul>\n<li><strong>Pre-Built UI:</strong> Clerk and SuperTokens both offer ready-made login/signup UI components. Supabase itself does not include UI (it’s just a backend service). For example, SuperTokens’ docs explicitly mention using their pre-built UI components (or you can choose a custom UI).</li>\n<li><strong>Custom Flows:</strong> Clerk allows some configuration, but SuperTokens lets you override everything. You can inject your own logic into any part of the auth flow.</li>\n<li><strong>Session Security:</strong> Clerk and Supabase provide basic session handling, but SuperTokens is designed for security. As discussed above, it offers rotating tokens, theft detection, and per-session revocation.</li>\n<li><strong>Self-Hosting:</strong> Supabase is open-source so you can self-host it via the Supabase CLI or Cloud.</li>\n</ul>\n<p>In short, SuperTokens stands out for its flexibility and security. It gives devs full control over auth logic and sessions without sacrificing convenience (it also has pre-built UIs and a simple integration).</p>\n<h2 id=\"custom-auth-flows-with-supertokens\" style=\"position:relative;\"><a href=\"#custom-auth-flows-with-supertokens\" aria-label=\"custom auth flows with supertokens permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Custom Auth Flows with SuperTokens</h2>\n<p>SuperTokens lets you override every piece of the logic—perfect for apps with unique flows or compliance requirements.</p>\n<p>Example: Add custom sign-in behavior:</p>\n<div\n              class=\"gatsby-code-button-container\"\n              data-toaster-id=\"68327016731654136000\"\n              data-toaster-class=\"gatsby-code-button-toaster\"\n              data-toaster-text-class=\"gatsby-code-button-toaster-text\"\n              data-toaster-text=\"Copied!\"\n              data-toaster-duration=\"3500\"\n              onClick=\"copyToClipboard(`override: {\n  functions: (original) => ({\n    ...original,\n    signInUp: async (input) => {\n      // Custom logic here\n    }\n  })\n}`, `68327016731654136000`)\"\n            >\n              <div\n                class=\"gatsby-code-button\"\n                data-tooltip=\"\"\n              >\n                <svg class=\"gatsby-code-button-icon\" xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\"><path fill=\"none\" d=\"M0 0h24v24H0V0z\"/><path d=\"M16 1H2v16h2V3h12V1zm-1 4l6 6v12H6V5h9zm-1 7h5.5L14 6.5V12z\"/></svg>\n              </div>\n            </div>\n<div class=\"gatsby-highlight\" data-language=\"javascript\"><pre class=\"language-javascript\"><code class=\"language-javascript\"><span class=\"token literal-property property\">override</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token function-variable function\">functions</span><span class=\"token operator\">:</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">original</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">(</span><span class=\"token punctuation\">{</span>\n    <span class=\"token operator\">...</span>original<span class=\"token punctuation\">,</span>\n    <span class=\"token function-variable function\">signInUp</span><span class=\"token operator\">:</span> <span class=\"token keyword\">async</span> <span class=\"token punctuation\">(</span><span class=\"token parameter\">input</span><span class=\"token punctuation\">)</span> <span class=\"token operator\">=></span> <span class=\"token punctuation\">{</span>\n      <span class=\"token comment\">// Custom logic here</span>\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>You can also build your own UI, or start with theirs and customize as needed.</p>\n<ul>\n<li><a href=\"https://supertokens.com/docs/references/frontend-sdks/function-overrides\" target=\"_blank\" rel=\"nofollow\">See how to override core logic</a></li>\n<li><a href=\"https://supertokens.com/docs/quickstart/frontend-setup\" target=\"_blank\" rel=\"nofollow\">Build your own UI</a></li>\n</ul>\n<h2 id=\"should-you-use-clerk-supertokens-or-both\" style=\"position:relative;\"><a href=\"#should-you-use-clerk-supertokens-or-both\" aria-label=\"should you use clerk supertokens or both permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Should You Use Clerk, SuperTokens, or Both?</h2>\n<p>There’s no one-size-fits-all answer, but here are some guidelines:</p>\n<ul>\n<li>Choose Clerk if you want a fully managed auth solution with beautiful, drop-in UI components and minimal setup. Clerk covers most common use cases out of the box.</li>\n<li>Choose SuperTokens if you need ultimate control over auth and sessions. For example, if you must self-host, enforce custom token lifetimes, or build a very custom workflow, SuperTokens gives you that flexibility.</li>\n<li>Use Both in a hybrid approach. You might love Clerk’s React components and user experience, but still want SuperTokens’ session security. You can start with Clerk handling UI and signup, and then integrate SuperTokens behind the scenes for session issuance (or vice versa). SuperTokens even provides migration guides from other systems, so you can gradually swap parts out.</li>\n</ul>\n<p>Because SuperTokens is open-source, you can try it risk-free alongside Clerk. For example, you could use Clerk for login/signup UI, but configure Supabase (or your backend) to accept SuperTokens’ tokens for session validation, leveraging SuperTokens’ defenses.</p>\n<h2 id=\"migrating-from-clerk-to-supertokens\" style=\"position:relative;\"><a href=\"#migrating-from-clerk-to-supertokens\" aria-label=\"migrating from clerk to supertokens permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Migrating from Clerk to SuperTokens</h2>\n<p><a href=\"https://supertokens.com/docs/migration/overview\" target=\"_blank\" rel=\"nofollow\">If you want to move from Clerk to SuperTokens</a>, you don’t need to rip everything out. You can migrate gradually:</p>\n<ul>\n<li>Start by having SuperTokens manage the session (tokens) while still using Clerk’s front end.</li>\n<li>Swap out Clerk’s session cookie with SuperTokens’ cookies under the hood.</li>\n<li>Replace one signup/signin flow at a time with SuperTokens recipes.</li>\n</ul>\n<p>SuperTokens provides guides on migrating from other auth systems, making the process smoother.</p>\n<h2 id=\"clerk--supabase-is-a-great-start-but-supertokens-takes-you-further\" style=\"position:relative;\"><a href=\"#clerk--supabase-is-a-great-start-but-supertokens-takes-you-further\" aria-label=\"clerk  supabase is a great start but supertokens takes you further permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Clerk + Supabase Is a Great Start, But SuperTokens Takes You Further</h2>\n<p>To summarize, the Clerk + Supabase integration we built gives you:</p>\n<ul>\n<li>A complete app with secure user sign-in.</li>\n<li>Personalized data storage (each user only sees their charts).</li>\n<li>Row-Level Security enforcing data isolation.</li>\n</ul>\n<p>This is elegant and suitable for many projects. Clerk handles auth beautifully, and Supabase handles data. But if your project has higher security needs or unusual requirements, SuperTokens can take you further. With SuperTokens, you can finely tune session lifetimes, detect stolen tokens, revoke individual sessions, and even self-host everything.</p>\n<p>In <strong>Part II</strong> of this series, we’ll swap Clerk out for SuperTokens in our app and show how to achieve similar functionality (login UI, user-specific data, RLS) with maximum control over sessions.</p>\n<p>Regardless of which tools you choose, you now have a solid blueprint: Clerk (or another provider) for authentication, Supabase for data storage, and well-configured RLS to tie it all together. By adding SuperTokens into the mix, you gain an extra layer of security and flexibility.</p>","frontmatter":{"date":"June 03, 2025","title":"How to Integrate Clerk with Supabase (Plus another option for the curious)","cover":"integrate-clerk-with-supabase.png","author":"Maria Shimkovska","description":"🔐 Learn how to integrate Clerk with Supabase for powerful authentication and database management in your Next.js applications - with step-by-step tutorial and code examples."},"fields":{"slug":"/how-to-integrate-clerk-with-supabase/"}},"site":{"siteMetadata":{"title":"SuperTokens Blog"}}},"pageContext":{"id":"7baf501e-ac4e-5a45-8739-1076a2074ff9","fields__slug":"/how-to-integrate-clerk-with-supabase/","__params":{"fields__slug":"how-to-integrate-clerk-with-supabase"}}},
    "staticQueryHashes": []}