Docs

Fastify Quickstart

You will learn the following:

  • Install @clerk/fastify
  • Set your Clerk API keys
  • Configure clerkPlugin for all routes
  • Use getAuth() to access the auth state and protect routes
  • Configure clerkPlugin for specific routes

Learn how to integrate Clerk into your Fastify backend for secure user authentication and management. This guide uses TypeScript and allows you to choose your frontend framework.

Important

Fastify is only compatible with Next.js versions 13.4 and below. If you're using a newer version of Next.js, consider using a different backend framework that supports the latest Next.js features.

This guide uses ECMAScript Modules (ESM). To use ESM in your project, you must include "type": "module" in your package.json.

Install @clerk/fastify

Clerk's Fastify SDK provides a range of backend utilities to simplify user authentication and management in your application.

To get started using Clerk with Fastify, add the SDK to your project:

terminal
npm install @clerk/fastify
terminal
yarn add @clerk/fastify
terminal
pnpm add @clerk/fastify
.env
CLERK_PUBLISHABLE_KEY=YOUR_PUBLISHABLE_KEY
CLERK_SECRET_KEY=YOUR_SECRET_KEY

Configure clerkPlugin for all routes

The clerkPlugin is a Fastify plugin provided by Clerk to integrate authentication into your Fastify application. To ensure that Clerk's authentication and user management features are applied across your Fastify application, configure the clerkPlugin to handle all routes or limit it to specific ones.

The following example registers the plugin for all routes. To register the plugin for specific routes only, refer to the Using Clerk for specific pages only section.

Important

The dotenv/config module must be imported before any Clerk modules. This order is important because Clerk instances are created during the import process and rely on environment variables, such as API keys, to be initialized correctly. For more information, refer to the Fastify docs.

index.ts
import 'dotenv/config'
import Fastify from 'fastify'
import { clerkPlugin } from '@clerk/fastify'

const fastify = Fastify({ logger: true })

fastify.register(clerkPlugin)

const start = async () => {
  try {
    await fastify.listen({ port: 8080 })
  } catch (error) {
    fastify.log.error(error)
    process.exit(1)
  }
}

start()

Use getAuth() to access the auth state and protect routes

The following example uses getAuth() to retrieve the userId, which is used to protect the route and is passed to clerkClient.users.getUser() to retrieve the current user's User object.

index.ts
import 'dotenv/config'
import Fastify from 'fastify'
import { clerkClient, clerkPlugin, getAuth } from '@clerk/fastify'

const fastify = Fastify({ logger: true })

fastify.register(clerkPlugin)

fastify.get('/', async (request, reply) => {
  const { userId } = getAuth(request)

  // Protect the route from unauthenticated users
  if (!userId) {
    return reply.code(403).send({ error: 'Unauthorized request.' })
  }

  const user = userId ? await clerkClient.users.getUser(userId) : null

  return reply.send({
    message: 'User retrieved successfully.',
    user,
  })
})

const start = async () => {
  try {
    await fastify.listen({ port: 8080 })
  } catch (error) {
    fastify.log.error(error)
    process.exit(1)
  }
}

start()

Configure clerkPlugin for specific routes

If you want to use Clerk for specific pages only, you can register the plugin for specific routes. In the following example, the routes are split into protected and public routes.

index.ts
import 'dotenv/config'
import Fastify, { FastifyPluginCallback } from 'fastify'
import { clerkClient, clerkPlugin, getAuth } from '@clerk/fastify'

const fastify = Fastify({ logger: true })

const protectedRoutes: FastifyPluginCallback = (instance, options, done) => {
  instance.register(clerkPlugin)

  instance.get('/protected', async (request, reply) => {
    const { userId } = getAuth(request)

    // Protect the route from unauthenticated users
    if (!userId) {
      return reply.code(403).send({ message: 'Access denied. Authentication required.' })
    }

    const user = await clerkClient.users.getUser(userId)

    // Only authenticated users will see the following message
    reply.send({ message: 'This is a protected route.', user })
  })

  done()
}

const publicRoutes: FastifyPluginCallback = (instance, options, done) => {
  instance.get('/', async (request, reply) => {
    reply.send({ message: 'This is a public route.' })
  })

  done()
}

fastify.register(protectedRoutes)
fastify.register(publicRoutes)

const start = async () => {
  try {
    await fastify.listen({ port: 8080 })
  } catch (error) {
    fastify.log.error(error)
    process.exit(1)
  }
}

start()

Feedback

What did you think of this content?

Last updated on