Browse docs All docs
Docs / Add WorkOS authentication to your app
Guidedeploymill://guides/auth/workos

Add WorkOS authentication to your app

You are an agent wiring WorkOS (AuthKit) as the external identity provider for end-user login / accounts in a DeployMill-managed app. Read this together with the general deploymill://guides/auth reference (the four platform facts about auth on DeployMill still apply) and deploymill://guides/secrets (the secret hand-off).

DeployMill operates nothing here

This is bring-your-own auth. DeployMill does not run a user store, a login UI, or any token validation for you. What it does is small and explicit:

  • It records your choice in the auth block of .deploymill/project.json (provider-neutral config).
  • It hands off the WorkOS secret values the normal way (set_env_vars / request_secret) so the agent never sees them.
  • On reconcile_project it runs a read-only presence-check that the expected env-var names are set on the app, and emits a typed auth_secret_missing hint (with this guide's URI) when they are not. It reads key names only, never the values.

WorkOS / AuthKit holds your users, sessions, and login pages. Your app talks to WorkOS with its SDK.

The env-var contract

WorkOS needs these env vars on the app:

  • WORKOS_API_KEY: secret. Push it through the vault / hand-off, never into a transcript.
  • WORKOS_CLIENT_ID: not secret, safe to set_env_vars.

These are the exact names the reconcile presence-check looks for. If either is missing, reconcile_project returns applied.auth.hint === "auth_secret_missing" with the missing name(s) in applied.auth.missingEnvKeys and a pointer to this guide.

The secret hand-off (agent never sees values)

  1. request_secret({ name: "WORKOS_API_KEY" }) → hand the returned link to the user → poll secret_request_statusbind_secret({ applicationId, name: "WORKOS_API_KEY" }) (or declare it under secrets in project.json and reconcile). The value is resolved server-side. It never appears in chat.
  2. set_env_vars({ applicationId, vars: { WORKOS_CLIENT_ID: "client_…" } }). The client id is not secret.

Add the app's prod host and every preview host to the WorkOS redirect-URI allow-list. See deploymill://guides/secrets for the full vault flow.

App-side SDK snippet

A minimal Node sketch using @workos-inc/node (AuthKit hosted login):

import { WorkOS } from "@workos-inc/node";

// Reads WORKOS_API_KEY + WORKOS_CLIENT_ID from the env DeployMill injected.
const workos = new WorkOS(process.env.WORKOS_API_KEY);

app.get("/login", (_req, res) => {
  const url = workos.userManagement.getAuthorizationUrl({
    clientId: process.env.WORKOS_CLIENT_ID!,
    provider: "authkit",
    redirectUri: `${process.env.APP_BASE_URL}/callback`, // host-pinned per environment
  });
  res.redirect(url);
});

(Use the matching WorkOS SDK for your framework. The env-var names are the same.)

The auth project.json block

Declare the provider so reconcile records it and runs the presence-check:

{
  "version": 2,
  "auth": { "provider": "workos", "audience": "users" }
}

audience is optional and only "users" today (end-user login). Then reconcile_project. If the keys are wired you get applied.auth.hint === null. If not, fix the missing names it reports and reconcile again.