---
title: "Announcing the Auth0 Fastify API SDK: Secure Your APIs with Speed!"
description: "Secure Fastify APIs easily with the Auth0 Fastify SDK. It simplifies Auth0 integration, offering route protection and token validation."
authors:
  - name: "Dan Arias"
    url: "https://auth0.com/blog/authors/dan-arias/"
date: "Apr 10, 2025"
category: "Developers,Deep Dive,Fastify"
tags: ["fastify", "fastify-sdk", "sdk", "auth0"]
url: "https://auth0.com/blog/auth0-fastify-sdk/"
---

# Announcing the Auth0 Fastify API SDK: Secure Your APIs with Speed!

Fastify is rapidly gaining traction among Node.js developers, and for good reason! If you're looking for a high-performance and low-overhead way to build web applications and APIs, Fastify is an excellent choice. Its plugin architecture is powerful, but securing those APIs remains a critical concern for developers.

To help address this, we are introducing the **`auth0-fastify-api` SDK**. This new package brings seamless Auth0 integration into your Fastify projects, simplifying API endpoint protection.

## So, What is Fastify, Anyway?

For those who might be new to it, Fastify is a web framework for Node.js focused on delivering a strong developer experience with minimal overhead, built around a robust plugin system. Key features include:

- **High Performance:** Fastify is known as one of the fastest Node.js frameworks, utilizing optimizations like schema-based request/response serialization.
- **Extensibility:** A rich ecosystem of plugins allows developers to easily add needed functionality.
- **Developer Experience:** Features like built-in logging, developer-friendly error handling, and first-class TypeScript support contribute to a smoother development process.
- **Schema-Powered:** Use JSON Schema to validate routes and serialize outputs, leading to more predictable and robust applications.
- **Helpful CLI:** The **`fastify-cli`** tool streamlines common development tasks like running the app and generating project scaffolds ([See fastify-cli on GitHub](https://github.com/fastify/fastify-cli)).
- **NestJS Integration:** Fastify's performance can also be leveraged within the popular NestJS framework by using it as the underlying HTTP provider ([Learn More](https://docs.nestjs.com/techniques/performance#performance-fastify)).

## Introducing `auth0-fastify-api`

This new SDK is specifically designed to secure Fastify APIs. It functions as a dedicated Fastify plugin to simplify the validation of access tokens issued by Auth0.

Here's what the SDK offers:

- **Simple Integration:** Sets up as a standard Fastify plugin.
- **Automatic Token Validation:** Handles the validation of incoming JWT access tokens (sent as Bearer tokens) against your Auth0 tenant configuration.
- **Route Protection:** Provides a **`requireAuth`** decorator for easily securing specific routes.
- **Scope Enforcement:** Allows specification of required scopes (permissions) needed to access certain endpoints.
- **User Information Access:** Makes the validated token payload available on **`request.user`**.
- **Token Access Utility:** Includes **`request.getToken()`** for accessing the raw token string if necessary.
- **Standard Error Handling:** Sends standards-compliant `WWW-Authenticate` headers on authentication/authorization errors.

## Getting Started: Quick Setup

Integrating the SDK involves two main steps:

1.  **Install the SDK:**

```bash
npm install @auth0/auth0-fastify-api
# or
yarn add @auth0/auth0-fastify-api
```

2.  **Register the Plugin:**

In your main Fastify application file, register the plugin, providing your Auth0 domain and API audience:

```typescript
import Fastify from "fastify";
import Auth0 from "@auth0/auth0-fastify-api";

const fastify = Fastify({ logger: true });

fastify.register(Auth0, {
  domain: "YOUR_AUTH0_DOMAIN", // For example: your-tenant.auth0.com
  audience: "YOUR_API_AUDIENCE", // The Identifier of your API in Auth0
});

// ... rest of your setup
```

> Remember to replace the placeholder values with your actual Auth0 domain and API identifier.

### A Functional Example

Let's look at a functional example that demonstrates setting up a basic server, loading configuration from the environment, and protecting a route.

Create a `fastify` directory anywhere in your system and initialize a Node.js project within it:

```bash
npm init -y
```

Within that directory, create a `server.ts` file and follow the instructions in this section to build it up.

First, import the necessary modules and use `dotenv` to load configurations like your Auth0 domain and audience from a `.env` file, which avoids hardcoding sensitive credentials.

```typescript
import Fastify from "fastify";
import Auth0 from "@auth0/auth0-fastify-api";
import * as dotenv from "dotenv";

dotenv.config();

const fastify = Fastify({
  logger: true,
});

if (!process.env.AUTH0_DOMAIN || !process.env.AUTH0_AUDIENCE) {
  fastify.log.error("Auth0 domain or audience not configured in .env file");

  process.exit(1);
}
```

It's good to check that the environment variables were loaded correctly.

Next, register the `Auth0` plugin, passing the configuration loaded from the environment variables:

```typescript
fastify.register(Auth0, {
  domain: process.env.AUTH0_DOMAIN,
  audience: process.env.AUTH0_AUDIENCE,
});
```

To ensure the `Auth0` plugin has finished loading before defining routes that use its decorators, such as `requireAuth`, register your protected routes inside an anonymous plugin function:

```typescript
fastify.register(() => {
  fastify.get("/", { preHandler: fastify.requireAuth() }, (_, reply) => {
    reply.send({ ok: true });
  });
});
```

Finally, start the server, listening on the port `3000`:

```typescript
fastify.listen({ port: 3000 }, function (err, address) {
  if (err) {
    fastify.log.error(err);
    process.exit(1);
  }

  fastify.log.info(`Server is now listening on ${address}`);
});
```

You can run this short example by following these steps:

Install dependencies:

```bash
npm install fastify @auth0/auth0-fastify-api dotenv
```

Create a `.env` file with your Auth0 details:

```bash
AUTH0_DOMAIN=your-tenant.auth0.com
AUTH0_AUDIENCE=your-api-identifier
```

You can follow the steps on the ["Register APIs"](https://auth0.com/docs/get-started/auth0-overview/set-up-apis) document to learn how to create an API in the Auth0 Dashboard and get the required values: the Auth0 Domain, which is your tenant domain, and the Auth0 Audience, which is a unique identifier for your API.

Run the server:

```bash
npx ts-node server.ts
```

This provides a basic but functional starting point that loads configuration securely and correctly waits for the Auth0 plugin before defining protected routes.

## Securing A Route with `requireAuth`

As you saw earlier, to protect an individual API endpoint, use the **`requireAuth`** decorator provided by the SDK. Add it as a `preHandler` in your route definition:

```typescript
fastify.get(
  "/private",
  { preHandler: fastify.requireAuth() },
  async (request, reply) => {
    const user = request.user;
    return { message: "This is a protected route", user };
  }
);
```

Fastify will only reach the body of the route event handler if the token sent in the request authorization header is valid. The decoded token claims of the token are available in the `request.user` object.

If a request is made to `/private` without a valid Bearer token in the `Authorization` header, the SDK automatically rejects it with a `401 Unauthorized` status.

### Securing Multiple Routes

Applying the `preHandler` to every route can be repetitive if multiple routes require the same protection. Fastify's plugin system and encapsulation offer an efficient way to apply an authorization guard at the router level to protect multiple routes at once.

Group related routes within their own plugin and apply the **`requireAuth`** hook once using [`fastify.addHook`](https://fastify.dev/docs/latest/Reference/Server/#addhook) within that plugin's context. All routes defined within that plugin will then inherit the hook.

Let's see this concept in action.

**1. Create a routes plugin:**

Within an asynchronous Fastify plugin, you use `fastify.addHook("preHandler", fastify.requireAuth())` to run the authentication check before any route defined within this plugin. Routes defined after this hook (`/profile`, `/orders`, etc.) are automatically protected.

```typescript
// private-routes.ts
import { FastifyPluginAsync } from "fastify";

const privateRoutes: FastifyPluginAsync = async (fastify, opts) => {
  // Apply the hook once for all routes in this plugin
  fastify.addHook("preHandler", fastify.requireAuth());

  fastify.get("/profile", async (request, reply) => {
    // Token is already validated by the hook
    return { user: request.user };
  });

  fastify.get("/orders", async (request, reply) => {
    // Hook handles main auth; specific checks can still happen here
    if (!request.user.scope?.includes("read:orders")) {
      return reply.code(403).send({ error: "insufficient_scope" });
    }
    return {
      orders: [
        /* ... */
      ],
      user_id: request.user.sub,
    };
  });
  // Define more protected routes here...
};

export default privateRoutes;
```

**2. Register the plugin in your main server file:**

In your main server setup (likely within the `fastify.register(async function(fastify){...})` block), import the `privateRoutes` plugin. Use `fastify.register` to load it, passing the `prefix` option (e.g., `{ prefix: "/api/v1" }`) to mount all routes from the plugin under that path.

```typescript
import Fastify from "fastify";
import Auth0 from "@auth0/auth0-fastify-api";
import * as dotenv from "dotenv";
import privateRoutes from "./private-routes"; // Import the routes plugin

dotenv.config();

const fastify = Fastify();

fastify.register(Auth0, {
  domain: process.env.AUTH0_DOMAIN,
  audience: process.env.AUTH0_AUDIENCE,
});

fastify.register(async function (fastify) {
  if (!process.env.AUTH0_DOMAIN || !process.env.AUTH0_AUDIENCE) {
    fastify.log.error("Auth0 domain or audience not configured in .env file");
    
    process.exit(1);
  }

  // Register the protected routes plugin under the /api/v1 prefix
  fastify.register(privateRoutes, { prefix: "/api/v1" });

  // Routes defined outside that plugin don't inherit its hooks 
  // and need their own protection
  fastify.get("/", { preHandler: fastify.requireAuth() }, (_, reply) => {
    reply.send({ ok: true });
  });
});

fastify.listen({ port: process.env.PORT || 3000 });
```

Now, requests to `/api/v1/profile`, `/api/v1/orders`, or any other route inside `private-routes.ts` are automatically protected by the **`requireAuth`** hook applied at the plugin level.

## Enforcing Scopes

If you need to ensure the user has been granted specific permissions (scopes) in their access token, use the `scopes` property of the **`requireAuth`** decorator:

```typescript
const requiredScopes = ["read:messages", "write:messages"];

fastify.post(
  "/messages",
  { preHandler: fastify.requireAuth({ scopes: requiredScopes }) },
  async (request, reply) => {
    return { message: "Message created successfully", user: request.user };
  }
);
```

Only requests with valid tokens containing both `read:messages` and `write:messages` scopes will reach the route event handler body.

If you don't have multiple scopes to check, you can also assign `scopes` a string as its value. For a single scope, you could use the following:

```typescript
const requiredScopes = "read:messages";
```

If the validated token doesn't include _all_ the specified scopes, the SDK will return a `403 Forbidden` error with an `insufficient_scope` code.

## Accessing User Information

Once a token is validated by `requireAuth`, its decoded payload (claims) is attached to the Fastify request object at `request.user`. This typically includes information like the user ID (`sub`), audience (`aud`), issuer (`iss`), and granted scopes (`scope`).

```typescript
fastify.get(
  "/profile",
  { preHandler: fastify.requireAuth() },
  async (request, reply) => {
    // Access the user's unique identifier (subject)
    const userId = request.user.sub;
    // Access the scopes granted in this token
    const scopes = request.user.scope;

    return { userId, scopes, fullProfile: request.user };
  }
);
```

## Conclusion

The `auth0-fastify-api` SDK provides a straightforward way to secure your Fastify APIs by integrating Auth0 token validation. It offers simple decorators for protecting routes and checking scopes, allowing you to focus on your application's core logic.

We encourage you to try it out in your next Fastify project and share your feedback! Check out the [source code](https://github.com/auth0/auth0-fastify/blob/main/packages/auth0-fastify-api) and [examples](https://github.com/auth0/auth0-fastify/blob/main/packages/auth0-fastify-api/EXAMPLES.md) to learn more.

Happy coding!