How to Build Secure SSR Authentication with Supabase, Astro, and Cloudflare Turnstile

In this guide, you'll build a full server-side rendered (SSR) authentication system using Astro, Supabase, and Cloudflare Turnstile to protect against bots. By the end, you'll have a fully functional authentication system with Astro actions, magic li...

Jun 21, 2025 - 00:00
 0
How to Build Secure SSR Authentication with Supabase, Astro, and Cloudflare Turnstile

In this guide, you'll build a full server-side rendered (SSR) authentication system using Astro, Supabase, and Cloudflare Turnstile to protect against bots.

By the end, you'll have a fully functional authentication system with Astro actions, magic link authentication using Supabase, bot protection via Cloudflare Turnstile, protected routes and middleware, and secure session management.

Table of Contents

Prerequisites

This tutorial assumes you are familiar with:

Understanding the Technologies

What is Astro?

Astro is a UI-agnostic web framework that renders server-first by default. It can be used with any UI framework, including Astro client components.

What are Astro Actions?

Astro actions allow you to write server-side functions that can be called without explicitly setting up API routes. They provide many useful utilities that simplify the process of running server logic and can be called from both client and server environments.

What is Supabase?

Supabase is an open-source Backend-as-a-Service that builds upon Postgres. It provides key features such as authentication, real-time capabilities, edge functions, storage, and more. Supabase offers both a hosted version for easy scaling and a self-hostable version for full control.

What is Cloudflare Turnstile?

Turnstile is Cloudflare's replacement for CAPTCHAs, which are visual puzzles used to differentiate between genuine users and bots. Unlike traditional CAPTCHAs, which are visually clunky, annoying, and sometimes difficult to solve, Turnstile detects malicious activity without requiring users to solve puzzles, while providing a better user experience.

Understanding SSR Authentication

Server-side rendered (SSR) auth refers to handling authentication on the server using a cookie-based authentication method.

The flow works as follows:

  1. The server creates a session and stores a session ID in a cookie sent to the client

  2. The browser receives the cookie and automatically includes it in future requests

  3. The server uses the cookie to determine if the user is authenticated

Since browsers cannot modify HTTP-only cookies and servers cannot access local storage, SSR authentication requires careful management to prevent security risks such as session hijacking and stale sessions.

SSR vs. SPA Authentication

Single-Page Applications (SPAs), like traditional React apps, handle authentication on the client side because they don't have direct access to a server. SPAs typically use JWTs stored in local storage, cookies, or session storage, sending these tokens in HTTP headers when communicating with servers.

Why Protect Auth Forms?

Authentication protects sensitive resources from unauthorized access, making auth forms primary targets for bots and malicious actors. Taking extra precautions is important for maintaining security.

Part 1: How to Set Up the Backend

Set Up Supabase Backend

First, you'll need a Supabase account. Create a project, then:

  1. Go to the Authentication tab in the sidebar

  2. Click the Sign In / Up tab under Configuration

  3. Enable user sign-ups

  4. Scroll down to Auth Providers and enable email (disable email confirmation for this tutorial)

Supabase authentication configuration interface showing user signup options and email provider enabled

Set Up Cloudflare Turnstile

  1. Log in or register for a Cloudflare account

  2. Click the Turnstile tab in the sidebar

  3. Click the "Add widget" button

  4. Name your widget and add "localhost" as the hostname

  5. Leave all other settings as default, and create the widget

Cloudflare Turnstile widget creation interface

After creating the widget, copy the secret key and add it to your Supabase dashboard:

  1. Go back to Supabase Authentication settings

  2. Navigate to the Auth Protection tab under Configuration

  3. Turn on Captcha protection

  4. Choose Cloudflare as the provider

  5. Paste your secret key

Supabase Attack Protection settings with Turnstile configuration

Part 2: How to Set Up the Frontend

Create the Astro Project

Next, you will need to create an Astro project. Open your preferred IDE or Text editor’s integrated terminal and run the following command to scaffold an Astro project in a folder named “ssr-auth.” Feel free to use any name you like.

npm create astro@latest ssr-auth

Follow the provided prompts and choose a basic template to start with. When it’s done, change into the folder, then run npm install to install dependencies, followed by npm run dev to start the server, and your site will be available at localhost:4321.

Configure Astro for SSR

Set Astro to run in SSR mode by adding output: "server", to the defineConfig function found in the astro.config.mjs file at the root of the folder.

Next, add an adapter to create a server runtime. For this, use the Node.js adapter by running this command in a terminal: npx astro add node. This will add it and automatically make all relevant changes.

Finally, add Tailwind for styling. Run this command in a terminal window: npx astro add tailwind. Follow the prompts, and it will make any changes necessary.

At this stage, your astro.config.mjs should look like this:

// @ts-check
import { defineConfig } from "astro/config";
import node from "@astrojs/node";
import tailwindcss from "@tailwindcss/vite";

// https://astro.build/config
export default defineConfig({
  output: "server",
  adapter: node({
    mode: "standalone",
  }),
  vite: {
    plugins: [tailwindcss()],
  },
});

Install Supabase Dependencies

You can do this by running the following command:

npm install @supabase/supabase-js @supabase/ssr

Configure Environment Variables

Create a .env file in the project root and add the following. Remember to replace with your actual credentials:

SUPABASE_URL=
SUPABASE_ANON_KEY=
TURNSTILE_SITE_KEY=

You can get the Supabase values from the dashboard:

Supabase project connection interface showing environment variables