How to add authentication to your Astro site

How to add authentication to your Astro site 🔒

Tags:
Astro

Auth-astro package

To add Auth to my Astro application, I used the package "auth-astro". Which provides auth.js for Astro. There is currently also a pull request which merges the "auth-astro" package into auth.js.

Adding the package

To add the package, you can use the astro cli like this. If you are using pnpm you also need to install the cookie package: pnpm i cookie

npm run astro add auth-astro
npm run astro add auth-astro

or install the needed packages manually:

npm install auth-astro@latest @auth/core@latest
npm install auth-astro@latest @auth/core@latest

Configuration

To configure the package, you need to edit the astro config called "astro.config.mjs" in the root of your project. As you can see in the example below (line 14 to 21), you need to add the auth function to the integrations array. You also need to add the auth provider you want to use. In this example I used Google. You can find more providers here.

astro.config.mjs
import { defineConfig } from 'astro/config'; import tailwind from "@astrojs/tailwind"; import vercel from "@astrojs/vercel/serverless"; import partytown from "@astrojs/partytown"; import { loadEnv } from 'vite'; import auth from 'auth-astro' import Google from "@auth/core/providers/google" const env = loadEnv('production', process.cwd(), ''); // https://astro.build/config export default defineConfig({ integrations: [tailwind(), partytown(), auth({ providers: [ Google({ clientId: env.GOOGLE_ID, clientSecret: env.GOOGLE_SECRET }) ] }) ], output: "server", adapter: vercel({ analytics: true }) });
astro.config.mjs
import { defineConfig } from 'astro/config'; import tailwind from "@astrojs/tailwind"; import vercel from "@astrojs/vercel/serverless"; import partytown from "@astrojs/partytown"; import { loadEnv } from 'vite'; import auth from 'auth-astro' import Google from "@auth/core/providers/google" const env = loadEnv('production', process.cwd(), ''); // https://astro.build/config export default defineConfig({ integrations: [tailwind(), partytown(), auth({ providers: [ Google({ clientId: env.GOOGLE_ID, clientSecret: env.GOOGLE_SECRET }) ] }) ], output: "server", adapter: vercel({ analytics: true }) });

Setup Environment Variables

To setup the environment variables, you need to create a ".env" file in the root of your project and add the following variables:

.env
AUTH_SECRET=<auth-secret> AUTH_TRUST_HOST=true GOOGLE_SECRET=<google-secret> GOOGLE_ID=<google-id>
.env
AUTH_SECRET=<auth-secret> AUTH_TRUST_HOST=true GOOGLE_SECRET=<google-secret> GOOGLE_ID=<google-id>

for the AUTH_SECRET you can use the following command to generate a random secret or use this site https://randomkeygen.com/

openssl rand -hex 32
openssl rand -hex 32

Creating the login page

Here is an example of a login page:

src/pages/login.astro
import Layout from "../../layouts/Layout.astro"; import { authOpts } from "src/pages/api/auth/[...astroAuth]"; import { Icon } from "astro-icon"; --- <Layout title="Login"> <main class="flex flex-col gap-4 items-center justify-center h-screen"> <div class="flex flex-col gap-2 rounded-xl overflow-hidden font-sans border-2 border-base-neutral p-4" > <button id="google" class="btn"> <span class="flex gap-2"> <Icon class="w-4 h-4" name="mdi:google" /> Login with Google </span> </button> </div> </main> </Layout> <script> const { signIn } = await import("auth-astro/client"); const google = document.getElementById("google"); google.addEventListener("click", () => { signIn("google"); }); </script>
src/pages/login.astro
import Layout from "../../layouts/Layout.astro"; import { authOpts } from "src/pages/api/auth/[...astroAuth]"; import { Icon } from "astro-icon"; --- <Layout title="Login"> <main class="flex flex-col gap-4 items-center justify-center h-screen"> <div class="flex flex-col gap-2 rounded-xl overflow-hidden font-sans border-2 border-base-neutral p-4" > <button id="google" class="btn"> <span class="flex gap-2"> <Icon class="w-4 h-4" name="mdi:google" /> Login with Google </span> </button> </div> </main> </Layout> <script> const { signIn } = await import("auth-astro/client"); const google = document.getElementById("google"); google.addEventListener("click", () => { signIn("google"); }); </script>

Check if a user is logged in

To check if the user is logged in, you can use the following code:

src/pages/protected-page.astro
--- import { getSession } from "auth-astro/server"; let session = await getSession(Astro.request); if (!session) { return Astro.redirect("/login"); } --- <div> <h1>Protected Page</h1> <p>Hi {{session.user.name}, only logged in users can see this page</p> </div>
src/pages/protected-page.astro
--- import { getSession } from "auth-astro/server"; let session = await getSession(Astro.request); if (!session) { return Astro.redirect("/login"); } --- <div> <h1>Protected Page</h1> <p>Hi {{session.user.name}, only logged in users can see this page</p> </div>

If the user is not logged in, he will be redirected to the login page using the Astros redirect utility function. You can find more information about the redirect function here.