# Backend-only SDK

When creating a backend-only SDK, you have two options for implementing the [BAPI](https://clerk.com/docs/guides/development/sdk-development/terminology.md) endpoints: either [develop a backend SDK that encompasses all BAPI endpoints](#implementation-bapi) or [create an SDK tailored for an existing backend framework](#implementation-node-js-backend-framework).

The source of truth for all BAPI endpoints is the [BAPI reference docs](https://clerk.com/docs/reference/backend-api){{ target: '_blank' }}. For Node.js backend frameworks, you can build on top of the [`clerkClient`](https://clerk.com/docs/reference/backend/overview.md) methods.

## Expected features

- User only needs to provide their Secret Key
- Centralized request authentication (e.g. in a middleware or plugin)
- Give access to the instance of BAPI client (so that users can use all methods)
- User should be able to limit access to routes by checking for [Roles and Permissions](https://clerk.com/docs/guides/organizations/control-access/roles-and-permissions.md)

> BAPI has [rate limits](https://clerk.com/docs/guides/how-clerk-works/system-limits.md) to help protect users against brute-force attacks or stop abuse of Clerk's platform. Be sure to include a backoff mechanism into your fetching logic and respect the `Retry-After` header to gracefully handle any active rate limits.

If you're using `@clerk/backend` to build an SDK for an existing framework, these additional features are expected:

- User should be able to use all `@clerk/backend` options

## Optional features

- User should be able to enforce authentication on individual routes (e.g. with a [`requireAuth`](https://clerk.com/docs/guides/development/sdk-development/backend-only.md#create-a-require-auth-helper) helper)
- Use singleton pattern to only create a pre-configured instance of Clerk backend client

## Implementation: BAPI

You can manually create a wrapper library around the [BAPI OpenAPI](https://clerk.com/docs/reference/backend-api){{ target: '_blank' }} or use one the many automatic SDK generation tools that take in OpenAPI definitions.

> If you're looking for a real-world example, have a look at [`clerk-sdk-go`](https://github.com/clerk/clerk-sdk-go).

## Implementation: Node.js backend framework

`@clerk/backend` is built for Node.js/V8 isolates (Cloudflare Workers, Vercel Edge Runtime, etc.). It’s the foundational package for all JavaScript Backend SDKs and works across all JavaScript runtimes. By using `@clerk/backend` you can be sure to communicate with Clerk’s BAPI in a correct and secure way.

> The code blocks below will be written in pseudo-code. If you're looking for real-world examples, have a look at [`@clerk/fastify`](https://github.com/clerk/javascript/tree/main/packages/fastify) and [`@clerk/express`](https://github.com/clerk/javascript/tree/main/packages/express).

1. ### Create a Clerk client

   Use [createClerkClient](https://clerk.com/docs/getting-started/quickstart.md#usage) from `@clerk/backend` to create your default Clerk client which will be used for the middleware.

   filename: client.ts

   ```ts
   import { createClerkClient } from '@clerk/backend'

   const API_VERSION = process.env.CLERK_API_VERSION || 'v1'
   const SECRET_KEY = process.env.CLERK_SECRET_KEY || ''
   const PUBLISHABLE_KEY = process.env.CLERK_PUBLISHABLE_KEY || ''
   const API_URL = process.env.CLERK_API_URL || ''
   const JWT_KEY = process.env.CLERK_JWT_KEY || ''
   const SDK_METADATA = {
     name: PACKAGE_NAME,
     version: PACKAGE_VERSION,
     environment: process.env.NODE_ENV,
   }

   export const clerkClient = createClerkClient({
     secretKey: SECRET_KEY,
     apiUrl: API_URL,
     apiVersion: API_VERSION,
     jwtKey: JWT_KEY,
     userAgent: `${PACKAGE_NAME}@${PACKAGE_VERSION}`,
     sdkMetadata: SDK_METADATA,
   })
   ```
2. ### Create your middleware/plugin

   Inside the middleware, you’ll use the user-provided Clerk client (or use the default one created in the previous step) and authenticate the request. [`authenticateRequest`](https://clerk.com/docs/reference/backend/authenticate-request.md) returns `Promise<RequestState>`. The middleware should set `requestState.toAuth()` into its context as this will contain the resolved signed-in/signed-out [`Auth`](https://clerk.com/docs/reference/backend/types/auth-object.md) object. This way other helpers can access it later in the chain.

   filename: clerk-middleware.ts

   ```ts
   import { clerkClient as defaultClerkClient } from './client.ts'

   const clerkMiddleware = (options) => {
     return async (context, next) => {
       const clerkClient = options.clerkClient || defaultClerkClient

       const requestState = await clerkClient.authenticateRequest(context.req, {
         authorizedParties: ['https://example.com'],
       })

       context.set('clerkAuth', requestState.toAuth())
       context.set('clerk', clerkClient)

       await next()
     }
   }
   ```
3. ### Create a `getAuth` helper

   This utility will access the stored `requestState` (in the example above saved as `clerkAuth`) and return it.

   filename: get-auth.ts

   ```ts
   export const getAuth = (context) => context.get('clerkAuth')
   ```

   Your end-users can use this utility in cases like these:

   filename: index.ts

   ```ts
   const app = new Framework()

   app.use('*', clerkMiddleware())
   app.get('/', (context) => {
     const auth = getAuth(context)

     if (!auth?.userId) {
       return context.json({ message: 'Not signed in' })
     }

     return context.json({ message: 'Signed in', userId: auth.userId })
   })
   ```

   > See the Next.js [getAuth()](https://clerk.com/docs/reference/nextjs/pages-router/get-auth.md) reference to see how it's implemented.
4. ### Create a `requireAuth` helper

   This utility will require auth requests for user authenticated or authorized requests. An HTTP `401` status code is returned for unauthorized requests.

   filename: require-auth.ts

   ```ts
   export const requireAuth = (context, next) => {
     if (!hasAuthObject(context)) {
       throw new Error('Middleware required')
     }
     if (!getAuth(context).userId) {
       context.status = 401
       return
     }
     return next()
   }
   ```

   Your end-users can use this utility in cases like these:

   filename: index.ts

   ```ts
   const app = new Framework()

   app.get('/path', requireAuth())
   ```

   Your end-users will also have access to a [`has()`](https://clerk.com/docs/reference/backend/types/auth-object.md#has) function on the [`Auth`](https://clerk.com/docs/reference/backend/types/auth-object.md) object. They can combine it with `requireAuth()` like so:

   filename: index.ts

   ```ts
   const app = new Framework()

   const hasPermission = (context, next) => {
     const auth = getAuth(context)
     if (!auth.has({ permission: 'org:feature:permission' })) {
       context.status = 403
       return
     }
     return next()
   }

   app.get('/path', requireAuth(), hasPermission())
   ```

---

## Sitemap

[Overview of all docs pages](https://clerk.com/docs/llms.txt)
