Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

update fastify doc and quickstart #1555

Merged
merged 17 commits into from
Sep 27, 2024
Merged
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
198 changes: 115 additions & 83 deletions docs/quickstarts/fastify.mdx
Original file line number Diff line number Diff line change
@@ -1,21 +1,58 @@
---
title: Use Clerk with Fastify
description: Learn how to use Clerk to easily add authentication focused on security, speed, and DX to your Fastify server.
title: Fastify Quickstart
description: Learn how to integrate Clerk for secure authentication and user management into your application using a Fastify backend.
---

Learn how to use Clerk to easily add authentication focused on security, speed, and DX to your Fastify server.
<TutorialHero
framework="react"
exampleRepo={[
{
title: "Fastify Quickstart",
link: "https://github.com/clerk/clerk-fastify-quickstart"

After following this guide, you should have a working Fastify app with public and private routes, authenticated using the `clerkPlugin` and `getAuth` helpers.
}
]}
beforeYouStart={[
{
title: "Set up a Clerk application",
link: "/docs/quickstarts/setup-clerk",
icon: "clerk",
}, {
title: "Add Fastify as your backend",
link: "https://fastify.dev/docs/latest/Guides/Getting-Started",
icon: "fastify",
victoriaxyz marked this conversation as resolved.
Show resolved Hide resolved
}
]}
>
- Create a Clerk application
- 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
</TutorialHero>

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](https://github.com/fastify/fastify-nextjs). If you're using a newer version of Next.js, consider using a different backend framework that supports the latest Next.js features.
victoriaxyz marked this conversation as resolved.
Show resolved Hide resolved
>
> This guide uses ECMAScript Modules (ESM). To use ESM in your project, you must include `"type": "module"` in your `package.json`.

> [!NOTE]
> If you're looking for a more complete example, check out our [Fastify example app](https://github.com/clerk/clerk-fastify-starter/).
> If you're using ECMAScript Modules (ESM) in your project, you must include `"type": "module"` in your `package.json` to enable ESM support in Node.js.
victoriaxyz marked this conversation as resolved.
Show resolved Hide resolved

<Steps>
### Install `@clerk/fastify`

<CodeBlockTabs type="installer" options={["npm", "yarn", "pnpm"]}>
[Clerk's Fastify SDK](https://github.com/clerk/javascript/tree/main/packages/fastify) has prebuilt components, React hooks, and helpers to make user authentication easier.

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

<CodeBlockTabs options={["npm", "yarn", "pnpm"]}>
```bash {{ filename: 'terminal' }}
npm install @clerk/fastify

```

```bash {{ filename: 'terminal' }}
Expand All @@ -27,171 +64,166 @@ After following this guide, you should have a working Fastify app with public an
```
</CodeBlockTabs>

### Set environment variables
### Set your Clerk API keys

Below is an example of an `.env.local` file.
<SignedIn>
Add the following keys to your `.env.local` file. These keys can always be retrieved from the [API Keys](https://dashboard.clerk.com/last-active?path=api-keys) page of your Clerk Dashboard.
</SignedIn>

**Pro tip!** If you are signed into your Clerk Dashboard, your secret key should become visible by clicking on the eye icon. Otherwise, you can find your keys in the Clerk Dashboard on the [API Keys](https://dashboard.clerk.com/last-active?path=api-keys) page.
<SignedOut>
1. Navigate to the Clerk Dashboard.
1. In the navigation sidebar, select [API Keys](https://dashboard.clerk.com/last-active?path=api-keys).
1. In the **Quick Copy** section, copy your Clerk publishable and secret key.
1. Paste your keys into your `.env` file.

```env {{ filename: '.env.local' }}
The final result should resemble the following:
</SignedOut>

```env {{ filename: '.env' }}
CLERK_PUBLISHABLE_KEY={{pub_key}}
CLERK_SECRET_KEY={{secret}}
```

This examples uses `dotenv` to load the environment variables. You can use any other library or method, if you so wish.

<CodeBlockTabs type="installer" options={["npm", "yarn", "pnpm"]}>
```bash {{ filename: 'terminal' }}
npm install dotenv
npm install -D @types/dotenv
```

```bash {{ filename: 'terminal' }}
yarn add dotenv
yarn add -D @types/dotenv
```
### Configure `clerkPlugin` for all routes

```bash {{ filename: 'terminal' }}
pnpm add dotenv
pnpm add -D @types/dotenv
```
</CodeBlockTabs>
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.
victoriaxyz marked this conversation as resolved.
Show resolved Hide resolved

### Configure `clerkPlugin` in your Fastify application
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**](/docs/quickstarts/fastify#using-clerk-for-specific-routes-only) section.

The Clerk plugin can be registered globally or for specific routes. This examples registers the plugin globally.
> [!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 details, refer to the [Fastify docs](https://fastify.dev/docs/latest/Guides/Getting-Started/#loading-order-of-your-plugins).

```ts {{ filename: 'index.ts' }}
import * as dotenv from 'dotenv'

dotenv.config()

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

const fastify = Fastify({ logger: true })

fastify.register(clerkPlugin)

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

start()
```

### Accessing auth state using `getAuth`
### Use `getAuth()` to access the auth state and protect routes

The `getAuth` helper can be used to access the auth state of the current request.
The `getAuth()` helper retrieves the authentication state from the current request. In the following example, the `userId` loads the entire [`User`](/docs/references/javascript/user/user) object from Clerk.
victoriaxyz marked this conversation as resolved.
Show resolved Hide resolved

```ts {{ filename: 'index.ts' }}
import * as dotenv from 'dotenv'
[`clerkClient`](/docs/references/backend/overview) is an instance of Clerk's JavaScript Backend SDK, which provides access to Clerk's Backend API resources and low-level utilities for handling authentication in JavaScript environments. With `clerkClient`, you can manage users, sessions, and metadata by interacting directly with Clerk's API.
victoriaxyz marked this conversation as resolved.
Show resolved Hide resolved

dotenv.config()
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.

```ts {{ filename: 'index.ts', mark: [3, [9, 17]] }}
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 (req, reply) => {
/**
* Access the auth state for this request.
* In this example, the userId loads the whole User object
* from the Clerk servers
*/
const { userId } = getAuth(req)
fastify.get('/', async (request, reply) => {
const { userId } = getAuth(request)
const user = userId ? await clerkClient.users.getUser(userId) : null
return { user }

return reply.send({
message: 'Authentication state retrieved successfully.',
victoriaxyz marked this conversation as resolved.
Show resolved Hide resolved
user,
})
})

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

start()
```

### Require authentication for a route

To protect a route using Clerk, you can use `getAuth` to check if the user is authenticated. If the user is not authenticated, you can return a 403 error.
To protect a route using Clerk, use the `getAuth()` method to check if the user is authenticated. If not, it returns an error response. If authenticated, it retrieves the user information using `clerkClient`.

```ts {{ filename: 'index.ts' }}
fastify.get('/protected', async (request, reply) => {
const { userId } = getAuth(request)
if (!userId) {
return reply.code(403).send()
}
try {
const { userId } = getAuth(request)

const user = await clerkClient.users.getUser(userId)
return { user }
if (!userId) {
return reply.code(403).send({ error: 'Unauthorized request.' })
}

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

return reply.send({
message: 'Authentication state retrieved successfully.',
user,
})
} catch (error) {
fastify.log.error(error)
return reply.code(500).send({ error: 'Failed to retrieve user information.' })
}
})
```
</Steps>
victoriaxyz marked this conversation as resolved.
Show resolved Hide resolved

### Using Clerk for specific routes only
### Configure `clerkPlugin` for specific routes

If you want to use Clerk for specific routes only, you can register the plugin for specific routes. In this example, the routes are split into two groups: one for public routes and one for private 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 public and private routes.

```ts {{ filename: 'index.ts' }}
import * as dotenv from 'dotenv'

dotenv.config()

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

const fastify = Fastify({ logger: true })

/**
* Register Clerk only for a subset of your routes
*/
const protectedRoutes: FastifyPluginCallback = (instance, opts, done) => {
const protectedRoutes: FastifyPluginCallback = (instance, options, done) => {
instance.register(clerkPlugin)

instance.get('/protected', async (request, reply) => {
const { userId } = getAuth(request)
if (!userId) {
return reply.code(403).send()
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.' })
return { user }
})
victoriaxyz marked this conversation as resolved.
Show resolved Hide resolved

done()
}

const publicRoutes: FastifyPluginCallback = (instance, opts, done) => {
const publicRoutes: FastifyPluginCallback = (instance, options, done) => {
instance.get('/', async (request, reply) => {
return {
message: 'This is a public endpoint. Request /protected to test the Clerk auth middleware',
}
return { message: 'This is a public route.' }
victoriaxyz marked this conversation as resolved.
Show resolved Hide resolved
})

done()
}

/**
* Register your routes as you normally would
*/
fastify.register(protectedRoutes)
fastify.register(publicRoutes)

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