Browse docs All docs
Docs / Add Clerk authentication to your app
Guidedeploymill://guides/auth/clerk

Add Clerk authentication to your app

You are an agent wiring Clerk 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 Clerk 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.

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

The env-var contract

Clerk needs these env vars on the app:

  • CLERK_SECRET_KEY: secret. Push it through the vault / hand-off, never into a transcript.
  • CLERK_PUBLISHABLE_KEY: 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: "CLERK_SECRET_KEY" }) → hand the returned link to the user → poll secret_request_statusbind_secret({ applicationId, name: "CLERK_SECRET_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: { CLERK_PUBLISHABLE_KEY: "pk_live_…" } }). The publishable key is not secret.

See deploymill://guides/secrets for the full vault flow.

App-side SDK snippet

A minimal Express/Node sketch using @clerk/express:

import { clerkMiddleware, requireAuth, getAuth } from "@clerk/express";

// Reads CLERK_SECRET_KEY + CLERK_PUBLISHABLE_KEY from the env DeployMill injected.
app.use(clerkMiddleware());

app.get("/me", requireAuth(), (req, res) => {
  const { userId } = getAuth(req);
  res.json({ userId });
});

(Use the matching Clerk 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": "clerk", "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.