llms.txt
llms.txt

WorkOS Integration

Use WorkOS for B2B authentication when AuthKit, enterprise SSO, and organization-aware sessions should sit behind Farm-owned routes.

This adapter covers AuthKit sign-in and sealed sessions. Directory Sync and other WorkOS APIs remain separate application integrations.

Add WorkOS

farm add integration workos --ui

Configure

src/lib/integrations.ts
import { workos } from "@farm.js/integrations/workos";export const appIntegrations = {  auth: workos({    clientId: process.env.WORKOS_CLIENT_ID,    apiKey: process.env.WORKOS_API_KEY,    cookiePassword: process.env.WORKOS_COOKIE_PASSWORD,    callbackPath: "/callback",    protectedRoutes: ["/dashboard(.*)"],  }),} as const;export type AppIntegrations = typeof appIntegrations;

Farm builds the absolute redirect URI from the incoming request origin and callbackPath. Register that exact URL in WorkOS, for example https://app.example.com/callback.

Environment variables

Variable Required Purpose
WORKOS_CLIENT_ID Yes AuthKit client ID.
WORKOS_API_KEY Yes Server-side WorkOS API key.
WORKOS_COOKIE_PASSWORD Production Encrypts and seals the AuthKit session cookie.
FARM_WORKOS_COOKIE_PASSWORD Alternative Backward-compatible cookie password name.

Development has a local fallback cookie password. Production startup fails without an explicit password.

Choose SDK ownership

Let Farm construct WorkOS

The configuration above is the default path. When instance is omitted, Farm constructs one WorkOS client from clientId and apiKey, supplied directly or through environment variables.

Provide an application-owned instance

Pass a configured SDK through instance when the app needs WorkOS constructor options that Farm does not own. Farm uses the instance directly, so apiKey is no longer required by the integration. The AuthKit client ID can come from the instance, while the cookie password remains required because Farm owns the sealed session cookie.

When both are present, the supplied instance wins. Integration-owned route, cookie, and protection options still belong in workos(...).

import { WorkOS } from "@workos-inc/node";import { workos } from "@farm.js/integrations/workos";const workosClient = new WorkOS({  apiKey: process.env.WORKOS_API_KEY,  clientId: process.env.WORKOS_CLIENT_ID,});export const auth = workos({  instance: workosClient,  cookiePassword: process.env.WORKOS_COOKIE_PASSWORD,  protectedRoutes: ["/dashboard(.*)"],});

Routes and methods

Method Default route Purpose
GET /login Starts AuthKit sign-in.
GET /signup Starts AuthKit sign-up.
GET /callback Exchanges the code and stores the sealed session.
POST /logout Clears the cookie and redirects through WorkOS logout.
GET /auth/session Returns the authenticated user, session ID, and organization ID.

Override these routes with loginPath, signUpPath, callbackPath, logoutPath, and sessionPath.

Start an AuthKit flow

Document navigation redirects directly:

<a href="/login?returnTo=/dashboard">Sign in</a><a href="/signup?returnTo=/dashboard">Create account</a>

The typed client returns the provider URL:

const result = await apiClient.auth.login.get({  query: {    returnTo: "/dashboard",  },});if (result.data) {  window.location.assign(result.data.redirectTo);}

Read the sealed session

const result = await api.auth.session.get();if (result.error && "status" in result.error && result.error.status === 401) {  // No authenticated WorkOS session.}const organizationId = result.data?.organizationId;const user = result.data?.user;

An authenticated response contains:

{  authenticated: true;  sessionId?: string;  organizationId?: string;  user: {    id: string;    email: string;    firstName?: string | null;    lastName?: string | null;    profilePictureUrl?: string | null;  };}

The organization ID is useful for looking up your app's tenant record. Authorization roles and permissions still need to be resolved by your application.

Logout

const result = await apiClient.auth.logout.post();if (result.data) {  window.location.assign(result.data.redirectTo);}

Farm clears the local cookie first. If a sealed session exists, WorkOS supplies the final logout URL; otherwise the user returns to the app origin.

Protect app routes

workos({  protectedRoutes: ["/dashboard(.*)", "/settings(.*)"],});

Signed-out requests receive a 307 redirect to /login with the original root-relative path in returnTo.

Options

Option Default Use
instance None Existing WorkOS SDK instance.
clientId WORKOS_CLIENT_ID AuthKit client ID.
apiKey WORKOS_API_KEY Server API key when no instance is supplied.
cookiePassword WorkOS cookie env Sealed-session password.
cookieName wos-session Session cookie name.
loginPath /login Sign-in route.
signUpPath /signup Sign-up route.
callbackPath /callback AuthKit callback route.
logoutPath /logout Logout route.
sessionPath /auth/session Session JSON route.
protectedRoutes None One matcher or a list of matchers.

Production checklist

  • Register the production callback URL in WorkOS.
  • Use a strong WORKOS_COOKIE_PASSWORD.
  • Confirm the public request origin is preserved by your proxy.
  • Test personal and organization-backed sessions.
  • Map organizationId to an application tenant before authorizing tenant data.