Skip to main content
Docs

Fullstack SDK

A fullstack SDK combines the and into one. A fullstack SDK is necessary for frameworks that support multiple rendering strategies (SSR, SSG, etc.), middleware, data fetching, and more. Examples of such frameworks would be Next.js or Rails.

Expected features

  • User only needs to provide their and
  • User only needs to adjust one or two files to add Clerk to their app (e.g. adding Clerk to the configuration file of that framework)
  • User can use Clerk’s components in their choice of framework (e.g. in a React-based framework you import these components as React components)
  • Give users access to , , , and properties through the framework’s choice of state management
  • User should be able to use
  • Centralized request authentication (e.g. in a middleware or plugin)
  • Give access to the instance of client (so that users can use all methods)
  • User should be able to limit access to routes by checking for roles and permissions

Optional features

  • User should be able to enforce authentication on individual routes (e.g. with a helper)
  • Use singleton pattern to only create a pre-configured instance of Clerk backend client

Implementation

See the respective and implementation instructions.

In addition to these instructions, you'll need to go through the following steps to support all required features.

Note

If you're looking for a real-world example, have a look at @clerk/nextjs.

Add handshake support

Inside your Clerk middleware, add checks for the headers on the requestState. Apply these headers to the Response and handle any existing location headers (e.g. redirects).

clerk-middleware.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'],
    })

    if (requestState.headers) {
      // This adds observability headers to the res
      requestState.headers.forEach((value, key) => context.res.headers.append(key, value))

      const locationHeader = requestState.headers.get('location')

      if (locationHeader) {
        return context.redirect(locationHeader, 307)
      } else if (requestState.status === 'handshake') {
        throw new Error('Clerk: unexpected handshake without redirect')
      }
    }

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

    await next()
  }
}

Feedback

What did you think of this content?

Last updated on