# Verify API keys in your TanStack React Start application with Clerk

When building a resource server that needs to accept and verify API keys issued by Clerk, it's crucial to verify these keys on your backend to ensure the request is coming from an authenticated client.

> This guide assumes you've configured [clerkMiddleware()](https://clerk.com/docs/tanstack-react-start/reference/tanstack-react-start/clerk-middleware.md) in your TanStack React Start application. The `auth()` helper requires Clerk Middleware to be configured before it can read request authentication state.

Clerk's TanStack React Start SDK provides a built-in [auth()](https://clerk.com/docs/tanstack-react-start/reference/tanstack-react-start/auth.md) function that supports token validation via the `acceptsToken` parameter. This lets you specify which type(s) of token your server function or API route should accept.

By default, `acceptsToken` is set to `session_token`, which means API keys will **not** be accepted unless explicitly configured. You can pass either a **single token type** or an **array of token types** to `acceptsToken`. To learn more about the supported token types, see the [auth() parameters documentation](https://clerk.com/docs/tanstack-react-start/reference/tanstack-react-start/auth.md#parameters).

Below are two examples of verifying API keys in a TanStack React Start API route using Clerk's SDK:

## Example 1: Accepting a single token type

In the following example, the `acceptsToken` parameter is set to only accept `api_key`s.

- If the API key is invalid or missing, `auth()` will return `false` for `isAuthenticated`, and the request will be rejected with a `401` response.
- If the API key is valid, `subject`, `scopes`, and `claims` are returned. API keys are scoped to either a user or an Organization, so `subject` is the user ID or Organization ID associated with the key.

filename: app/routes/api/example.tsx
```tsx
import { json } from '@tanstack/react-start'
import { createFileRoute } from '@tanstack/react-router'
import { auth } from '@clerk/tanstack-react-start/server'

export const ServerRoute = createFileRoute('/api/example')({
  server: {
    handlers: {
      GET: async () => {
        const authObject = await auth({
          acceptsToken: 'api_key',
        })

        // If isAuthenticated is false, the token is invalid
        if (!authObject.isAuthenticated) {
          return json({ error: 'Unauthorized' }, { status: 401 })
        }

        const { subject, scopes, claims } = authObject

        return json({ subject, scopes, claims })
      },
    },
  },
})
```

## Example 2: Accepting multiple token types

In the following example, the `acceptsToken` parameter allows `session_token`s, `oauth_token`s, and `api_key`s.

- If the token is invalid or missing, `auth()` will return `false` for `isAuthenticated`. Check `isAuthenticated` before reading the other properties, like `userId`.
- If the token is an `api_key`, use `subject` to identify the user or Organization associated with the key.
- If the token is valid, `isAuthenticated` is `true`. This example includes pseudo-code that uses `subject` for API keys or `userId` for session and OAuth tokens to get data from a database.

filename: app/routes/api/example.tsx
```tsx
import { json } from '@tanstack/react-start'
import { createFileRoute } from '@tanstack/react-router'
import { auth } from '@clerk/tanstack-react-start/server'

export const ServerRoute = createFileRoute('/api/example')({
  server: {
    handlers: {
      POST: async () => {
        // Accept session_token, oauth_token, and api_key types
        const authObject = await auth({
          acceptsToken: ['session_token', 'oauth_token', 'api_key'],
        })

        // If the token is invalid or missing
        if (!authObject.isAuthenticated) {
          return json({ error: 'Unauthorized' }, { status: 401 })
        }

        // Check if the token is an api key and if it doesn't have the required scope
        if (authObject.tokenType === 'api_key' && !authObject.scopes.includes('read:data')) {
          return json({ error: 'API Key missing the "read:data" scope' }, { status: 401 })
        }

        // If the token is valid, move forward with the application logic
        // This example includes pseudo-code for getting data from a database using the resource owner ID
        const ownerId = authObject.tokenType === 'api_key' ? authObject.subject : authObject.userId
        const data = db.select().from(resources).where(eq(resources.ownerId, ownerId))

        return json({ data })
      },
    },
  },
})
```

---

## Sitemap

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