Skip to content

instance.json

instance.json configures how users authenticate to a NimbleBrain deployment. It lives at <workDir>/instance.json and is the single source of truth for the deployment’s auth adapter and org identity.

serve does not start without <workDir>/instance.json. It exits with an error naming the path and the two ways to write it. A missing file never selects an identity provider, because a deployment that lost its config would otherwise admit every caller as an admin.

The dev launchers (bun run dev and its variants, including dev:worktree) write the dev adapter into a workdir that has no instance.json, and leave an existing one alone. With Docker Compose, write the file next to docker-compose.yml; it is mounted into the container’s workdir.

The auth.adapter field selects the identity provider: dev, oidc, or workos.

instance.json
{
"auth": {
"adapter": "dev"
}
}

No login. Every request authenticates as one built-in identity (usr_default, org role admin), with no credential checked. Its display name and preferences are read from its stored profile, like any other user’s. It passes the same authorization checks as any other user, as an org admin and an admin of its workspaces. Use it on your own machine only: anyone who can reach the server is that admin.

Field Type Required Description
auth object Yes The auth adapter config. See per-adapter fields below.
orgId string No Stable organization identifier.
integrations object No Free-form integration config bag.
Field Type Required Description
adapter "oidc" Yes Selects the OIDC adapter.
issuer string Yes OIDC issuer URL.
clientId string Yes OAuth client id registered with the provider.
allowedDomains string[] Yes Email domains permitted to sign in. A token whose email domain isn’t listed is rejected.
jwksUri string No JWKS endpoint override. Discovered from the issuer’s .well-known when omitted.

The provider must send email_verified: true in each token. A token with email_verified: false or no email_verified claim is refused and logged, because the email decides domain admission and which pre-created user a first sign-in claims. Some providers omit the claim by default; configure yours to include it before switching to this adapter.

Each sign-in is matched to a local user by the token’s issuer and subject, and by email only to claim a user created ahead of time that no subject is bound to yet. A different subject with an email already bound to someone is refused. See Signing in with OIDC.

Field Type Required Description
adapter "workos" Yes Selects the WorkOS adapter.
clientId string Yes WorkOS Client ID (client_…).
organizationId string No WorkOS Organization ID — scopes auth to a specific customer org. Every token, whether from the web login or AuthKit, must be issued for this org (its org_id claim), and its user must be a member of it. An empty or whitespace-only value is rejected at startup. Omitting the field admits every user in the AuthKit environment, so omit it only when this instance owns the whole environment.
apiKey string No WorkOS API key. Can also come from the WORKOS_API_KEY env var.
authkitDomain string No AuthKit subdomain for MCP OAuth (e.g. "myapp" → myapp.authkit.app). When set, /mcp/<workspaceId> accepts AuthKit-issued Bearer JWTs whose audience is exactly that URL, and exposes /.well-known/oauth-protected-resource/mcp/<workspaceId> for MCP client discovery. AuthKit needs a resource indicator covering <origin>/mcp/* for each public host, or it ignores the client’s resource and every token is refused.
adminRoleSlugs string[] No WorkOS membership role slugs that map to the app admin role (case-insensitive). Omit to use the defaults ["admin", "owner"] (owner is WorkOS’s org-owner role name, so it grants app admin). An explicit list replaces the defaults and must contain at least one non-empty slug — an empty list is rejected at startup. Set this when your WorkOS org’s admin role carries a custom slug.
firstPartyClientIds string[] No Client IDs of your own apps that sign users in through AuthKit and call the REST API with the resulting token, such as a chat-channel bridge. See First-party clients. Takes effect only with authkitDomain set, since without it no token is recognized as AuthKit-issued. Omitted or empty, no AuthKit token is first-party.

The sign-in callback is always <public origin>/v1/auth/callback, built from the deployment’s public origin. Register that URL as a redirect URI in the WorkOS dashboard; instance.json has no field for it.

An AuthKit token is normally a resource token: valid only at the /mcp/<workspaceId> its audience names, and refused on every /v1/* route. An app you run yourself that obtains tokens from AuthKit without naming a resource cannot use them anywhere, so list its client ID in firstPartyClientIds.

A token whose signed client_id claim is listed is first-party, like a web login session: it is admitted on every route, and workspace membership gates what it reaches. Every other AuthKit token is unchanged.

The token’s audience never makes it first-party. A token an external MCP client refreshes without a resource carries the same audience as your app’s token, so only the client it was issued to tells them apart.

The field fails closed: missing, empty, or a client ID that isn’t listed, and the token stays a resource token.

instance.json is validated at load:

  • Missing or non-object auth throws.
  • An unknown adapter value (anything other than dev / oidc / workos) throws, naming the accepted set.
  • Each adapter’s required fields are type-checked; a missing or wrong-typed field throws with a field-specific message.
  • A malformed file, like a missing one, stops the deployment at startup. An auth misconfiguration fails loud, never open.

The file is written atomically (temp-then-rename) whenever the runtime persists changes to it.