惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

GbyAI
GbyAI
Simon Willison's Weblog
Simon Willison's Weblog
Microsoft Security Blog
Microsoft Security Blog
Y
Y Combinator Blog
The GitHub Blog
The GitHub Blog
Engineering at Meta
Engineering at Meta
F
Fortinet All Blogs
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
A
About on SuperTechFans
Last Week in AI
Last Week in AI
月光博客
月光博客
有赞技术团队
有赞技术团队
P
Proofpoint News Feed
MyScale Blog
MyScale Blog
Martin Fowler
Martin Fowler
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
C
Check Point Blog
U
Unit 42
The Register - Security
The Register - Security
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
Hugging Face - Blog
Hugging Face - Blog
阮一峰的网络日志
阮一峰的网络日志
V
Visual Studio Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
D
DataBreaches.Net
WordPress大学
WordPress大学
aimingoo的专栏
aimingoo的专栏
H
Hacker News: Front Page
Recent Announcements
Recent Announcements
C
CXSECURITY Database RSS Feed - CXSecurity.com
Latest news
Latest news
小众软件
小众软件
P
Palo Alto Networks Blog
PCI Perspectives
PCI Perspectives
Security Latest
Security Latest
S
Secure Thoughts
Scott Helme
Scott Helme
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
T
Threat Research - Cisco Blogs
P
Proofpoint News Feed
M
MIT News - Artificial intelligence
Application and Cybersecurity Blog
Application and Cybersecurity Blog
Google DeepMind News
Google DeepMind News
Recorded Future
Recorded Future
O
OpenAI News
S
Securelist
云风的 BLOG
云风的 BLOG
H
Help Net Security
T
Troy Hunt's Blog

Clerk Blog

Going to production with Clerk Deploy Clerk Init: The fastest way to start a new project Introducing Clerk CLI Middleware-based route protection bypass Postmortem: Clerk System Outage (March 10, 2026) Clerk for the AI era Add API Key support to your SaaS in minutes Postmortem: Clerk System Outage (February 19, 2026) Using Clerk in a React Native app Postmortem: DNS Provider Outage (February 10, 2026) How do I implement passkeys in Next.js? Clerk ranked #4 fastest-growing software vendor on Ramp’s December 2025 list How do I handle JWT verification in Next.js? Committing to Agent Identity: Clerk raises $50m Series C from Menlo and Anthropic’s Anthology Fund What is the best way to handle authentication in Next.js App Router? Postmortem: Database Incident (September 14–18, 2025) How do I add authentication to a Next.js app? Introducing Free Trials in Clerk Billing Postmortem: August 28, 2025 - elevated API latency and errors Introducing Mosaic: Bring Your Brand to Every Authentication Flow Multi-tenant authentication: What you need to know (and how Clerk helps) What are the risks and challenges of multi-tenancy? Resilience in Practice: Regional Failover at Clerk Build a Cross-Platform B2B App with Clerk, Expo, and Supabase Highlights from the MiduDev/Clerk Hackathon Add multi-tenancy to an app built with Clerk, Lovable, and Supabase How to build an AI coding rules app with Clerk, Lovable, and Supabase How to Build Multi-Tenant Authentication with Clerk Choosing the right SaaS architecture: Multi-Tenant vs. Single-Tenant Postmortem: June 26, 2025 service outage How to Design a Multi-Tenant SaaS Architecture What is multi-tenancy and why it matters for B2B SaaS How OAuth Works Synchronize user data from Clerk to Supabase Add subscriptions to your SaaS with Clerk Billing Getting started with Clerk Billing Multi-tenant analytics with Tinybird and Clerk How Huntr Migrated 250K Users to Clerk: A Scalable Auth Solution for Startups How to take Clerk to Production How to take your Clerk application to production A practical guide to testing Clerk Next.js applications Implementing multi-tenancy into a Supabase app with Clerk How Clerk integrates with a Next.js application using Supabase How Clerk integrates with Supabase Build a blog with tRPC, Prisma, Next.js and Clerk How to enrich PostHog events with Clerk user data How to build a secure project management platform with Next.js, Clerk, and Neon Validate your SaaS idea while building an audience Postmortem: February 6, 2025 service outage Implement Role-Based Access Control in Next.js 15 Build a Next.js sign-up form with React Hook Form Build a Next.js login page template How to implement Google authentication in Next.js 15 What is middleware in Next.js? How to customize Next.js metadata How to set environment variables in Node.js Building a React Login Page Template How to implement per-user OAuth scopes with Clerk Using Clerk SSO to access Google Calendar and other service data Streamline enterprise customer onboarding with SAML and Clerk Clerk launches EASIE SSO and eliminates SSO fees How to secure Liveblocks Rooms with Clerk in Next.js Securing Node.js Express APIs with Clerk and React Combining the benefits of session tokens and JWTs Build a task manager with Next.js, Supabase, and Clerk Comparing Clerk Webhooks vs Backend API Automate Neon schema changes with Drizzle and GitHub Actions A guide to reading authenticated user data from Clerk Role based access control with Clerk Organizations Mitigating OAuth’s recently discovered Open Response Type vulnerability Per-user B2B monetization with Stripe and Clerk Organizations Build a team-based task manager with Next.js, Neon, and Clerk Building a Hybrid Sign-Up/Subscribe Form with Stripe Elements Welcoming Colin from Zod as our inaugural Open Source Fellow Build a modern authenticated chat application with Next.js, Ably, and Clerk Build a waitlist with Clerk user metadata How to use Clerk with PostHog Identify in Next.js How to secure API Gateway using JWT and Lambda Authorizers with Clerk What are passkeys and how do they work? Comparing Authentication in React.js vs. Next.js How to Add an Onboarding Flow for your Application with Clerk Create Your Own Custom User Menu with Radix - Part 2 Introducing Webhook Workflows with Inngest & Svix Clerk raises $30M Series B from CRV and Stripe Clerk in 2023: A Year in Review Build a Movie Emoji Quiz App with Remix, Fauna, and Clerk Ultimate Guide to Magic Link Authentication Create Your Own Custom User Menu with Radix Introducing has(), protect(), and <Protect> Updated Pricing: 10,000 MAUs Free, and a new “Pro Plan” Next.js Authentication with Clerk: Streamlined SSR Handling Clerk Webhooks: Data Sync with Convex Exploring Clerk Metadata with Stripe Webhooks The Ultimate Guide to Next.js Authentication Empower Your Support Team With User Impersonation Clerk Webhooks: Getting Started A Complete Guide to Session Management in Next.js The Advanced Guide to Passwordless Authentication in Next.js How We Roll – Chapter 10: Roundup How We Roll – Chapter 9: Infrastructure
Build a Cookie Clicker App with Clerk and Hasura
Ian McPhail · 2023-07-24 · via Clerk Blog

Hasura provides a GraphQL engine that can help you build real-time APIs and ship modern apps faster. Although Hasura itself does not handle authentication, you can bring your own auth server and integrate it with Hasura via JWTs. This is where Clerk fits in.

In this tutorial we will use Clerk with Hasura to build a full-stack Next.js app with a database and GraphQL API, all without having to write any backend code.

If you would like to skip ahead and see the completed codebase, browse to the repo here.

Assumptions

This tutorial makes the following assumptions:

  • Basic command line usage
  • Node.js installed and npm (or yarn if you prefer) for package management
  • Experience with React components and hooks
  • Familiarity with the Next.js application structure (created with create-next-app)
  • Comfortable running Docker Compose commands (alternative path is to use Hasura Cloud)
  • Clerk and Hasura accounts already set up (if you haven’t done so, do it now... we’ll wait)

Set up Clerk project

We’re going to start off with creating a new project from the Clerk dashboard. I’m going to name this application “More Cookies Please” (you’ll see why shortly) and leave the default options selected for authentication strategy and turn on social login with Google.

Build A Cookie Clicker App With Clerk And Hasura guide illustration

The next thing we need to do is navigate to JWT Templates from the left menu and create a template based on Hasura.

Hasura template

The next thing we need to do is navigate to JWT Templates from the left menu and create a template based on Hasura.

Hasura token claims

Click the “Apply changes” button and navigate back to the Home dashboard. Here we’re going to copy the Frontend API key.

Frontend API key

That’s all we need to do in the Clerk dashboard.

Clone the starter repo

Now it’s time to clone the clerk-hasura-starter repo from GitHub. Name this project directory more-cookies-please to match the Clerk instance name.

Once you have the repository downloaded to your computer, run the following commands to change into the directory, install the package dependencies, and copy the .env.local.sample so we can set a couple environment variables:

Add in the Frontend API key from Clerk that was copied earlier. We’re also going to set the GraphQL endpoint even though it hasn’t been created yet.

Note: CLERK_API_KEY is available in the sample but isn’t needed for this tutorial.

Once those environment variables are set, start up the application with npm run dev

Open your web browser to http://localhost:3000 and you should see the starter application homepage, which prompts you to sign up. So now let’s sign up for an account.

Click the Sign up button and you will be redirected to a Sign Up form generated for your application with Clerk components. I’m going to choose Sign up with Google since it's the fastest (and doesn’t require a new password).

Once you’ve signed up and logged in, you should see the following screen:

App welcome

Now it’s time to customize this application. We’re going to install a little package I created based on the excellent react-rewards library and inspired by Cookie Clicker (thank @bsinthewild for reminding me of this).

Note: ⚠️ You will see some warnings about conflicting peer dependencies due to a mismatch of React versions, but it’s safe to proceed.

We’re going to create a new file called MoreCookies.js inside of the components/ folder.

Because this library does not support server-side rendering (SSR), we need to make use of the dynamic imports from Next.js or we’ll get some nasty errors.

Now let’s add the component to pages/index.js:

The ClerkFeatures component can be removed, but the Footer and Home components should remain untouched.

You can see here we are making use of the SignedIn and SignedOut components from Clerk. We can also finally see the big cookie button!

Go ahead and click it for a nice reward. You’ve earned it. 🍪

Cookie button

Set up Hasura GraphQL engine

Clicking the cookie is a lot of fun, but what is even more fun? Keeping count of all those clicks!

This is where the Hasura GraphQL integration comes in.

There are two different ways we can connect to Hasura: we can use Hasura Cloud or Hasura Core running from a Docker container. We’re going to do the latter for this tutorial, but you can see instructions for connecting with Hasura Cloud in our integration documentation.

The starter repo already contains the docker-compose.yml file we need.

The only part we need to update here is the JWT secret. Uncomment the line for HASURA_GRAPHQL_JWT_SECRET and add in the value for your Clerk Frontend API. The JWT URL path points to the JSON Web Key Set (JWKS) endpoint we have set up for your application.

Note: Make sure the https:// protocol is included in the URL in front of the Frontend API.

Once the JWT secret is set, run the following command:

This will spin up Docker services for GraphQL engine as well as a Postgres database.

You can confirm that the services are running correctly with the following:

If all is good, you should see output similar to:

Head to http://localhost:8080/console to open the Hasura console.

Hasura GraphiQL console

Hasura has already done the work of setting up a GraphQL endpoint for us and also provided the GraphiQL integrated development environment (IDE) to explore the API.

It’s time to set up the database to keep the score count.

Navigate to the Data page and fill out the form to Connect Existing Database. (Remember we have the Postgres one running from Docker Compose?)

Connect database

Name the database default (or something more clever) and input the database URL copied from the docker-compose.yml file. Click connect and the data source will be added.

The next step is to create the database table named scoreboard and add two fields:

  1. user_id is a Text field that will contain the user ID from Clerk
  2. count is an Integer field that will keep track of the click count

Add new table

Set the user_id as the Primary Key for the table. Then click the Add Table button.

The next thing we need to do is set permissions for the “user” role. Click on the Permissions tab and enter user as a new role. Then we need to set the basic CRUD (Create, Read, Update, Delete) operations on the table.

Insert (Create)

For Insert permissions, set the following values:

  • Row insert permissions: Without any checks
  • Column insert permissions: count checked
  • Column presets: user_id from session variable X-Hasura-User-Id

Insert permissions

With the Clerk integration, the user ID will be set as the session variable and Hasura will then set that as the user_id column when the request is made.

Select (Read)

For Select permissions, set the following values:

  • Row select permissions: With custom check {"user_id":{"_eq":"X-Hasura-User-Id"}}
  • Column select permissions: count and user_id checked

Select permissions

The custom check ensures only the current authenticated user can read their own count. If the user ID from the session variable matches the one from the table, the user is granted read permission to every column in their database row.

Update

For Update permissions, set the following values:

  • Pre-update check: With same check as select {"user_id":{"_eq":"X-Hasura-User-Id"}}
  • Column update permissions: count checked

Update permissions

Having the same custom check prevents another authenticated user from updating someone else’s count.

Delete

We can skip over Delete permissions since we aren’t implementing a mechanism to delete user records from the scoreboard.

Your final permissions access chart should look like the following:

Permissions chart

Configure the client

Now it’s time to make authenticated requests from the codebase to Hasura.

If you take a look at hooks/index.js, you can see the useQuery hook that has been set up. It makes use of graphql-request, a minimal GraphQL client, with the useSWR hook to perform query requests to the GraphQL endpoint.

What we’re doing is reading the custom JWT (from the template we named hasura) from the session object provided by Clerk. Note that the call to getToken is asynchronous and returns a Promise that needs to be resolved before accessing the value.

We pass the custom fetcher function, which accepts a GraphQL query and optional variables, to useSWR. The blockRequest parameter is something we’ll make use of later to prevent certain calls from happening.

Let’s try this out to make sure we can get some data. Open up components/MoreCookies.js and import the useQuery hook and log the data to the console:

If all went well, you should see the following:

The data is undefined at first but then gets populated. scoreboard is an empty Array because we haven’t recorded any click counts yet. So let’s do that now.

In order to make the GraphQL mutation we’re going to create another custom hook in hooks/index.js:

This hook accepts the count as the first parameter and the data object containing previous data as the second parameter. It makes use of the useQuery hook to apply the insert_scoreboard_one insert mutation as an upsert. Instead of adding multiple rows to the database table, the on_conflict argument sets a constraint on the primary key (user_id) and if it already exists, only the count column will be updated. Both count and user_id values are returned from a successful mutation.

If we replace the useQuery with useCountMutation in the MoreCookies component, we can give us some credit for those clicks we’ve already made. (I set mine at 10 but you can be more or less generous.)

If you look at the browser console, you should now see something like:

You can confirm that this made it into the Postgres database by going to the Data tab in the Hasura Console and clicking into scoreboard and Browse Rows:

Browse rows

Success! The count (fake or not) has made it into the database and is associated with the authenticated user.

So now that everything is working as intended, we can go ahead and connect it all together. We’ll add one more custom hook that performs both the initial useQuery and the useCountMutation. This is going to need both useState and useEffect from React so make sure you import those.

It returns the current count as well as an increment function, both of which we can pass as props to the <CookieClicker /> component.

By setting the count and onClick props on CookieClicker, it will now reward you with cookies based on the number of times the button is clicked. Keep clicking for more cookies!

Build A Cookie Clicker App With Clerk And Hasura guide illustration

Closing thoughts

Hope you had fun building this. You now have a complete Cookie Clicker app built using Clerk, Hasura, and Next.js — with no backend code required! To take it even further, you could implement an actual scoreboard that keeps track of all the cookie clicks from multiple users. Then deploy this app to production, share it with your friends, and see how much idle time they have on their hands. 😆

If you enjoyed this tutorial or have any questions, feel free to reach out to me (@devchampian) on X, follow @clerk, or join our Discord community to connect with other developers. Happy coding!