Skip to content
Draft
Show file tree
Hide file tree
Changes from all 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
193 changes: 193 additions & 0 deletions docs/_partials/accepting-multiple-token-types-examples.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
<If sdk={["nextjs", "tanstack-react-start"]}>
In the following example, the `acceptsToken` option allows `session_token`s, `oauth_token`s, and `api_key`s.

- If the token is invalid or missing, `auth()` will return `false` for `isAuthenticated`.
- If the token is an `api_key`, the code checks that it includes the required `'write:users'` scope. If not, the request will be rejected with a `401` response.
- If the token is valid, `isAuthenticated` is `true` and the request can move forward with the application logic.

<If sdk="nextjs">
```tsx {{ filename: 'app/api/example/route.ts' }}
import { NextResponse } from 'next/server'
import { auth } from '@clerk/nextjs/server'

export async function POST() {
// Accept session_token, oauth_token, and api_key types
const authObject = await auth({
acceptsToken: ['session_token', 'oauth_token', 'api_key'],
})

if (!authObject.isAuthenticated) {
return NextResponse.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('write:users')) {
return NextResponse.json({ error: 'API key missing the "write:users" scope' }, { status: 401 })
}

const subject = authObject.tokenType === 'session_token' ? authObject.userId : authObject.subject

return NextResponse.json({ subject, tokenType: authObject.tokenType })
}
```

You can also protect entire route groups using [`clerkMiddleware()`](/docs/reference/nextjs/clerk-middleware). See how to implement this in [the middleware docs](/docs/reference/nextjs/clerk-middleware#protect-routes-based-on-token-types).
</If>

<If sdk="tanstack-react-start">
```tsx {{ filename: 'app/routes/api/example.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 () => {
const authObject = await auth({
acceptsToken: ['session_token', 'oauth_token', 'api_key'],
})

if (!authObject.isAuthenticated) {
return json({ error: 'Unauthorized' }, { status: 401 })
}

if (authObject.tokenType === 'api_key' && !authObject.scopes.includes('write:users')) {
return json({ error: 'API key missing the "write:users" scope' }, { status: 401 })
}

const subject =
authObject.tokenType === 'session_token' ? authObject.userId : authObject.subject

return json({ subject, tokenType: authObject.tokenType })
},
},
},
})
```
</If>
</If>

<If sdk={["fastify", "expressjs", "react-router"]}>
In the following example, the `acceptsToken` option allows `session_token`s, `oauth_token`s, and `api_key`s.

- If the token is invalid or missing, `getAuth()` will return `false` for `isAuthenticated`.
- If the token is an `api_key`, the code checks that it includes the required `'write:users'` scope. If not, the request will be rejected with a `401` response.
- If the token is valid, `isAuthenticated` is `true` and the request can move forward with the application logic.

<If sdk="expressjs">
```ts {{ filename: 'index.ts' }}
import express from 'express'
import { clerkMiddleware, getAuth } from '@clerk/express'

const app = express()

app.use(clerkMiddleware())

app.post('/api/example', (req, res) => {
const authObject = getAuth(req, {
acceptsToken: ['session_token', 'oauth_token', 'api_key'],
})

if (!authObject.isAuthenticated) {
res.status(401).json({ error: 'Unauthorized' })
return
}

if (authObject.tokenType === 'api_key' && !authObject.scopes.includes('write:users')) {
res.status(401).json({ error: 'API key missing the "write:users" scope' })
return
}

const subject = authObject.tokenType === 'session_token' ? authObject.userId : authObject.subject

res.json({ subject, tokenType: authObject.tokenType })
})
```
</If>

<If sdk="fastify">
```ts {{ filename: 'src/routes/example.ts' }}
import Fastify from 'fastify'
import { clerkPlugin, getAuth } from '@clerk/fastify'

const fastify = Fastify()

fastify.register(clerkPlugin)

fastify.post('/api/example', (request, reply) => {
const authObject = getAuth(request, {
acceptsToken: ['session_token', 'oauth_token', 'api_key'],
})

if (!authObject.isAuthenticated) {
return reply.code(401).send({ error: 'Unauthorized' })
}

if (authObject.tokenType === 'api_key' && !authObject.scopes.includes('write:users')) {
return reply.code(401).send({ error: 'API key missing the "write:users" scope' })
}

const subject = authObject.tokenType === 'session_token' ? authObject.userId : authObject.subject

return reply.send({ subject, tokenType: authObject.tokenType })
})
```
</If>

<If sdk="react-router">
```ts {{ filename: 'app/routes/api.example.ts' }}
import { getAuth } from '@clerk/react-router/server'
import type { Route } from './+types/api.example'

export async function action(args: Route.ActionArgs) {
const authObject = await getAuth(args, {
acceptsToken: ['session_token', 'oauth_token', 'api_key'],
})

if (!authObject.isAuthenticated) {
throw new Response('Unauthorized', { status: 401 })
}

if (authObject.tokenType === 'api_key' && !authObject.scopes.includes('write:users')) {
throw new Response('API key missing the "write:users" scope', { status: 401 })
}

const subject = authObject.tokenType === 'session_token' ? authObject.userId : authObject.subject

return Response.json({ subject, tokenType: authObject.tokenType })
}
```
</If>
</If>

<If sdk="nuxt">
In the following example, the `acceptsToken` option allows `session_token`s, `oauth_token`s, and `api_key`s.

- If the token is invalid or missing, `event.context.auth()` will return `false` for `isAuthenticated`.
- If the token is an `api_key`, the code checks that it includes the required `'write:users'` scope. If not, the request will be rejected with a `401` response.
- If the token is valid, `isAuthenticated` is `true` and the request can move forward with the application logic.

```ts {{ filename: 'server/api/example.ts' }}
export default defineEventHandler((event) => {
const authObject = event.context.auth({
acceptsToken: ['session_token', 'oauth_token', 'api_key'],
})

if (!authObject.isAuthenticated) {
throw createError({ statusCode: 401, statusMessage: 'Unauthorized' })
}

if (authObject.tokenType === 'api_key' && !authObject.scopes.includes('write:users')) {
throw createError({
statusCode: 401,
statusMessage: 'API key missing the "write:users" scope',
})
}

const subject = authObject.tokenType === 'session_token' ? authObject.userId : authObject.subject

return { subject, tokenType: authObject.tokenType }
})
```
</If>
149 changes: 149 additions & 0 deletions docs/_partials/accepting-single-token-type-examples.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
<If sdk={["nextjs", "tanstack-react-start"]}>
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 `null` for machine-specific properties, 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.

<If sdk="nextjs">
```tsx {{ filename: 'app/api/example/route.ts' }}
import { NextResponse } from 'next/server'
import { auth } from '@clerk/nextjs/server'

export async function GET() {
const { isAuthenticated, claims, scopes, subject } = await auth({ acceptsToken: 'api_key' })

// If auth() returns null, the token is invalid
if (!isAuthenticated) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 })
}

return NextResponse.json({ subject, scopes, claims })
}
```
</If>

<If sdk="tanstack-react-start">
```tsx {{ filename: 'app/routes/api/example.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 { isAuthenticated, claims, scopes, subject } = await auth({
acceptsToken: 'api_key',
})

// If auth() returns null, the token is invalid
if (!isAuthenticated) {
return json({ error: 'Unauthorized' }, { status: 401 })
}

return json({ subject, scopes, claims })
},
},
},
})
```
</If>
</If>

<If sdk={["fastify", "expressjs", "react-router"]}>
In the following example, the `acceptsToken` parameter is set to only accept `api_key`s.

- If the API key is invalid or missing, `getAuth()` will return `false` for `isAuthenticated` and `null` for machine-specific properties, 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.

<If sdk="expressjs">
```ts {{ filename: 'index.ts' }}
import express from 'express'
import { clerkMiddleware, getAuth } from '@clerk/express'

const app = express()

app.use(clerkMiddleware())

app.get('/api/example', (req, res) => {
const { isAuthenticated, claims, scopes, subject } = getAuth(req, {
acceptsToken: 'api_key',
})

// If getAuth() returns null, the token is invalid
if (!isAuthenticated) {
res.status(401).json({ error: 'Unauthorized' })
return
}

res.json({ subject, scopes, claims })
})
```
</If>

<If sdk="fastify">
```ts {{ filename: 'src/routes/example.ts' }}
import Fastify from 'fastify'
import { clerkPlugin, getAuth } from '@clerk/fastify'

const fastify = Fastify()

fastify.register(clerkPlugin)

fastify.get('/api/example', (request, reply) => {
const { isAuthenticated, claims, scopes, subject } = getAuth(request, {
acceptsToken: 'api_key',
})

// If getAuth() returns null, the token is invalid
if (!isAuthenticated) {
return reply.code(401).send({ error: 'Unauthorized' })
}

return reply.send({ subject, scopes, claims })
})
```
</If>

<If sdk="react-router">
```ts {{ filename: 'app/routes/api.example.ts' }}
import { getAuth } from '@clerk/react-router/server'
import type { Route } from './+types/api.example'

export async function loader(args: Route.LoaderArgs) {
const { isAuthenticated, claims, scopes, subject } = await getAuth(args, {
acceptsToken: 'api_key',
})

// If getAuth() returns null, the token is invalid
if (!isAuthenticated) {
throw new Response('Unauthorized', { status: 401 })
}

return Response.json({ subject, scopes, claims })
}
```
</If>
</If>

<If sdk="nuxt">
In the following example, the `acceptsToken` parameter is set to only accept `api_key`s.

- If the API key is invalid or missing, `event.context.auth()` will return `false` for `isAuthenticated` and `null` for machine-specific properties, 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.

```ts {{ filename: 'server/api/example.ts' }}
export default defineEventHandler((event) => {
const { isAuthenticated, claims, scopes, subject } = event.context.auth({
acceptsToken: 'api_key',
})

// If event.context.auth() returns null, the token is invalid
if (!isAuthenticated) {
throw createError({ statusCode: 401, statusMessage: 'Unauthorized' })
}

return { subject, scopes, claims }
})
```
</If>
21 changes: 21 additions & 0 deletions docs/guides/development/verifying-api-keys.expressjs.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
---
title: Verify API keys in your Express application with Clerk
description: Learn how to use Clerk's helpers to verify API keys in your Express application.
sdk: expressjs
---

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.

Clerk's Express SDK provides a built-in [`getAuth()`](/docs/reference/express/get-auth) function that supports token validation via the `acceptsToken` parameter. This lets you specify which type(s) of token your route should accept in your Express application.

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 [`getAuth()` options documentation](/docs/reference/express/get-auth#get-auth-options).

The following examples assume that [`clerkMiddleware()`](/docs/reference/express/clerk-middleware) has been applied before the routes that call `getAuth()`.

## Example 1: Accepting a single token type

<Include src="_partials/accepting-single-token-type-examples" />

## Example 2: Accepting multiple token types

<Include src="_partials/accepting-multiple-token-types-examples" />
21 changes: 21 additions & 0 deletions docs/guides/development/verifying-api-keys.fastify.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
---
title: Verify API keys in your Fastify application with Clerk
description: Learn how to use Clerk's helpers to verify API keys in your Fastify application.
sdk: fastify
---

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.

Clerk's Fastify SDK provides a built-in [`getAuth()`](/docs/reference/fastify/get-auth) function that supports token validation via the `acceptsToken` parameter. This lets you specify which type(s) of token your route should accept in your Fastify application.

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 [`getAuth()` options documentation](/docs/reference/fastify/get-auth#get-auth-options).

The following examples assume that [`clerkPlugin()`](/docs/reference/fastify/clerk-plugin) has been registered before the routes that call `getAuth()`.

## Example 1: Accepting a single token type

<Include src="_partials/accepting-single-token-type-examples" />

## Example 2: Accepting multiple token types

<Include src="_partials/accepting-single-token-type-examples" />
Loading
Loading