Farm.js

Auth0 Integration

Use Auth0 when the identity provider should host login and enterprise connections while Farm owns the application-facing OAuth routes and local session.

The built-in flow uses Authorization Code with PKCE, validates signed state, reads the user profile, and stores that profile in a signed HTTP-only cookie.

Add Auth0

farm add integration auth0 --ui

Configure

src/lib/integrations.ts
import { auth0 } from "@farm.js/auth0";

export const appIntegrations = {
  auth: auth0({
    domain: process.env.AUTH0_DOMAIN,
    clientId: process.env.AUTH0_CLIENT_ID,
    clientSecret: process.env.AUTH0_CLIENT_SECRET,
    secret: process.env.AUTH0_SECRET,
    appBaseUrl: process.env.APP_BASE_URL,
    callbackPath: "/auth/callback",
    protectedRoutes: ["/dashboard(.*)"],
  }),
} as const;

export type AppIntegrations = typeof appIntegrations;

callbackPath stays root-relative. Farm combines it with APP_BASE_URL, or the incoming request origin, to create the callback URL sent to Auth0.

You can use callbackUrl instead, but it must be absolute:

auth0({
  callbackUrl: "https://app.example.com/auth/callback",
});

Choose route ownership

Let Farm construct the Auth0 flow

The configuration above is the default path. When instance is omitted, Farm constructs the OAuth flow from the Auth0 domain, client credentials, session secret, callback settings, and scopes. Farm then owns the login, signup, callback, logout, profile, and protected-route behavior.

Provide application-owned middleware

auth0({
  instance: {
    matcher: ["/auth(.*)", "/dashboard(.*)"],
    middleware(request) {
      return myAuth0Middleware(request);
    },
  },
});

This advanced path accepts a compatible middleware adapter rather than the Auth0 SDK itself. The supplied instance wins and Farm only mounts its middleware; it does not create the built-in login, callback, logout, or profile routes.

Environment variables

VariableRequiredPurpose
AUTH0_DOMAINYesTenant domain without a required protocol, such as tenant.us.auth0.com.
AUTH0_CLIENT_IDYesOAuth application client ID.
AUTH0_CLIENT_SECRETDepends on client typeUsed by confidential clients during code exchange.
AUTH0_SECRETProductionSigns state and local session cookies.
APP_BASE_URLRecommended in productionPublic app origin used for callbacks and protected-route redirects.

Farm provides a development-only fallback for AUTH0_SECRET. Production startup fails when no secret is configured.

Routes and methods

MethodDefault routePurpose
GET/auth/loginStarts login. Accepts returnTo.
GET/auth/signupStarts signup with Auth0's signup screen hint.
GET/auth/callbackValidates state, exchanges the code, and writes the local session.
GET/auth/logoutClears the local session and redirects through Auth0 logout.
GET/auth/profileReturns the current local profile or 401.

Every path can be changed with loginPath, signUpPath, callbackPath, logoutPath, or profilePath.

Start login

Normal document navigation redirects directly:

<a href="/auth/login?returnTo=/dashboard">Sign in</a>

The typed integration client asks for the redirect URL as JSON:

const result = await apiClient.auth.login.get({
  query: {
    returnTo: "/dashboard",
  },
});

if (result.data) {
  window.location.assign(result.data.redirectTo);
}

Signup uses the same shape through apiClient.auth.signup.get(...).

Read the profile

const result = await api.auth.profile.get();

if (result.error && "status" in result.error && result.error.status === 401) {
  // No valid local Auth0 session.
}

const user = result.data?.user;

The session cookie contains the fetched Auth0 profile and an expiry derived from the token response. The integration does not persist refresh tokens, so an expired local session requires a new login.

Protect app routes

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

A signed-out request is redirected with status 307 to:

/auth/login?returnTo=/the/original/path

Only root-relative returnTo values are accepted. Invalid or external values fall back to /dashboard.

Options

OptionDefaultUse
instanceNoneApplication-owned middleware adapter; disables the built-in flow.
domainAUTH0_DOMAINAuth0 tenant domain.
clientIdAUTH0_CLIENT_IDOAuth client ID.
clientSecretAUTH0_CLIENT_SECRETOAuth client secret for confidential clients.
secretAUTH0_SECRETCookie and state signing secret.
appBaseUrlAPP_BASE_URLPublic app origin.
callbackUrlNoneAbsolute callback URL.
callbackPath/auth/callbackCallback route when callbackUrl is not supplied.
audienceNoneOptional Auth0 API audience.
scopesopenid profile emailRequested OAuth scopes.
tokenEndpointAuthMethodautoclient_secret_basic, client_secret_post, none, or automatic selection.
protectedRoutesNoneOne matcher or a list of matchers.

Production checklist

  • Allow the exact callback URL in Auth0.
  • Allow the app origin as a logout URL.
  • Use a strong AUTH0_SECRET.
  • Set APP_BASE_URL behind proxies or custom domains.
  • Test bad state, callback errors, expired cookies, login return paths, and logout.