How to Use AuthJS in Astro

This article is for version ^1.0.0 of auth-astro. For new projects, check out the latest version of the adapter for a new and improved experience.

With the release of Astro 2.0 it seems a good a time as any to announce the unofficial community prerelease of an Auth.js Astro adapter! Let’s dive in, and implement authentication in a new Astro project.

Setup

Create a new Astro project, with the default/recommended options:

Terminal window
npm init astro

Install the unofficial Astro adapter & the core for Auth.js, along with a platform adapter for Astro (e.g. @astrojs/node):

Terminal window
npm install @auth/core auth-astro @astrojs/node

Head to astro.config.mjs and change the output to server.

Authentication Providers

Next, we need to configure the authentication providers we want to use. For this demo, we’ll use GitHub. Create a new file at src/routes/api/auth/[...astroAuth].ts and add the following code:

import { AstroAuth, type AstroAuthConfig } from "auth-astro"
import GitHub from "@auth/core/providers/github"
export const authOpts: AstroAuthConfig = {
providers: [
// @ts-ignore
GitHub({
clientId: process.env.GITHUB_ID!,
clientSecret: process.env.GITHUB_SECRET!,
}),
],
debug: false,
}
export const { get, post } = AstroAuth(authOpts)

The exported request handlers will process the callback from the OAuth provider and handle the authentication. The clientId and clientSecret are passed in as environment variables. We’ll set these up next.

GitHub OAuth

Go to GitHub’s developer settings and create a new OAuth app. Set the callback URL to http://localhost:4321/api/auth/callback/github. The http://localhost:4321 part is the default URL for Astro. If you’re using a different port, or are deploying your app, you’ll need to change this. You’ll also need to set the Homepage URL to http://localhost:4321. Save the client ID and client secret for the next step.

Configure Environment Variables

Next, we need to configure the environment variables. Create a new file in the root of the project called .env and add the following, replacing the placeholders with your own values. AUTH_SECRET must be a random string of 32 characters. The documentation suggests on Linux, you generate one using openssl rand -hex 32, or you can navigate to generate-secret.vercel.app to generate one in the browser.

Terminal window
GITHUB_ID=<your-github-id>
GITHUB_SECRET=<your-github-secret>
AUTH_SECRET=<auth-secret>
AUTH_TRUST_HOST=true

Fetching the Session & Logging In

To know if a user is authenticated, we need to fetch the session data. Navigate to src/routes/index.tsx and import the Auth context provider. Wrap the Layout in the Auth component, and pass in the authOpts we created in the API route. The child element of Auth should be a JSX method, taking the session as a parameter. This will be called with the session data, or null if the user is not authenticated. We can use this to display a login button, or the user’s name.

The Signin and Signout components are provided by the adapter, and will handle the authentication flow. The Signin component takes a provider prop, which should match the name of the provider you configured in the API route. The Signout component will log the user out. Both are optional, and you can implement your own login and logout flows using the signIn & signOut methods from auth-astro/client.

---
import Layout from '../layouts/Layout.astro';
import type { Session } from '@auth/core/types';
import { Auth, Signin, Signout } from '../lib/components';
import { authOpts } from './api/auth/[...astroAuth]';
---
<Layout title="Welcome to Astro Auth">
<Auth authOpts={authOpts}>
{(session: Session | null) =>
<main>
<h1>Astro + AuthJS</h1>
<p>
<a href="/protected">Protected Route</a>
</p>
<Signin provider="github">Login</Signin>
<Signout>Logout</Signout>
<p>
{session ? `Logged in as ${session.user?.name}` : 'Not logged in'}
</p>
</main>
}
</Auth>
</Layout>

Protected Routes

Using the getSession method from auth-astro, we can fetch the session data in a protected route. Navigate to src/routes/protected.tsx and if the session is null, redirect to the home page. Otherwise, display the user’s name.

---
import { getSession } from "../lib";
import { authOpts } from "./api/auth/[...astroAuth]";
let session = await getSession(Astro.request, authOpts)
if (!session) return Astro.redirect("/")
---
<p>Only logged in users can see this page.</p>
<p>Logged in as {session?.user?.name}</p>
<p><a href="/">Home</a></p>

That’s it!

That’s all there is to it! You can now run the project with npm run dev and try out the authentication flow. You can also deploy the project to Vercel, and use the Vercel adapter to link it to your GitHub account. You can find the source code for this demo here.


Thanks for reading! If you have any questions, feel free to reach out to me on Twitter or hop into my Discord.