auth

Use when the user wants to authenticate to a NocoBase v2 instance, asks "how do I get a token for NocoBase", "how do I log in via API or CLI", "how do I connect an agent or MCP client", "why is my req

SKILL.md

GitHub

Authentication — NocoBase v2

NocoBase v2 accepts Authorization: Bearer <token> on every /api/ request. The OpenAPI spec declares this as the api-key security scheme (HTTP bearer). There are four ways to get a token; pick by who or what is calling:

Caller Pick
An agent or person at a terminal using the nb CLI Path 0 — nb env add / nb env auth (native; credential stored by the CLI)
Script that can store the admin password Path A — sign-in
CI job, cron, bot, MCP client — wants a static token Path B — API Key
A tool that must sign in as a person without a password (CLI on a headless host, MCP client) Path C — OAuth via the IdP: OAuth plugin
End users clicking "Sign in with Google / Keycloak / Entra" in the browser Path D — Auth: OIDC (SSO; a different plugin from Path C)

Path 0 — the CLI way (nb env add / nb env auth)

The CLI keeps a named env (API base URL plus credential) and every nb api … command uses it. No environment variables are needed.

# Save the endpoint (URL includes /api) and choose how to authenticate
nb env add prod --api-base-url https://app.example.com/api --auth-type token --access-token <api-key>
nb env add prod --api-base-url https://app.example.com/api --auth-type basic --username <user>   # password prompted in a TTY
nb env add prod --api-base-url https://app.example.com/api --auth-type oauth                     # browser / device sign-in
nb env add prod --api-base-url https://app.example.com/api --skip-auth                           # authenticate later

# Authenticate (or re-authenticate) a saved env
nb env auth prod --auth-type basic|token|oauth
nb env info prod        # shows the saved auth type; secrets masked unless --show-secrets

--auth-type oauth signs in through the IdP: OAuth plugin using the Device Authorization Grant when the server supports it: the command prints a verification URL and a code, and you approve in any browser — it works on a remote or headless server. Otherwise it falls back to a browser loopback (PKCE) flow. --auth-type oauth cannot be combined with --access-token, --username or --password. Prefer oauth or token over putting a password on the command line.

This is the native way. The NB_URL / NB_USER / NB_PASSWORD / NB_TOKEN variables below remain for curl and Node scripts and for the nocobase-dsl-reconciler scripts.

Env vars contract (REST scripts and nocobase-dsl-reconciler)

NB_URL=https://app.example.com           # required
NB_USER=admin@example.com                # required for Path A (sign-in)
NB_PASSWORD=<password>                   # required for Path A
NB_TOKEN=eyJhbGciOi...                   # optional, skips sign-in (Path B)
# NOCOBASE_API_TOKEN is a synonym for NB_TOKEN — upstream auth.ts reads either.

These names match what the upstream nocobase/skills library uses — keep them identical in your .env so hand-maintained and upstream skills agree on one truth.

Path A — Sign-in with admin credentials (upstream default for scripts)

This is what the upstream nocobase-dsl-reconciler skill uses. Username + password → auth:signIn → short-lived bearer token. Best for scripts that are OK re-logging in periodically.

export NB_URL="https://app.example.com"
export NB_USER="admin@example.com"
export NB_PASSWORD="<password>"

# 1. Sign in and capture the token
TOKEN=$(curl -sS -X POST "${NB_URL}/api/auth:signIn" \
  -H "Content-Type: application/json" \
  -d '{"account":"'"$NB_USER"'","password":"'"$NB_PASSWORD"'"}' \
  | jq -r '.data.token')

# 2. Use it as a Bearer
curl -H "Authorization: Bearer $TOKEN" \
     "${NB_URL}/api/collections:list"

The NB_USER value is whatever admin account you set during nb init --ui — the root-admin account.

Path B — Long-lived API Key (when you want a static token)

Useful when you don't want to re-login every call: cron jobs, agents, deploy hooks, third-party integrations, MCP clients.

1. Make sure the API Keys plugin is on

API keys (@nocobase/plugin-api-keys) is built in and enabled by default. If nb plugin list shows it disabled:

nb plugin enable @nocobase/plugin-api-keys

The nocobase-plugin-manage skill covers nb plugin semantics and error handling.

2. Create a token in the admin UI

Open NocoBase → Settings → API keys → Create:

  • Name — short identifier (e.g. agent-bot).
  • Role — pick the role whose permissions the key inherits. The token can do exactly what the role can; no more.
  • Expiration — date or Never.

Copy the token; it is shown only once. Put it in NB_TOKEN (or hand it to nb env add --auth-type token).

The server must have APP_KEY configured and kept stable — if APP_KEY changes, every issued API key becomes invalid.

3. Send authorised requests

export NB_URL="https://app.example.com"
export NB_TOKEN="<token-from-admin-ui>"

# List collections
curl -H "Authorization: Bearer ${NB_TOKEN}" \
     "${NB_URL}/api/collections:list"

# Create a record in the `posts` collection
curl -X POST \
     -H "Authorization: Bearer ${NB_TOKEN}" \
     -H "Content-Type: application/json" \
     -d '{"title":"hello","body":"first post"}' \
     "${NB_URL}/api/posts:create"

4. Node.js

// fetch (built into Node)
const res = await fetch(`${process.env.NB_URL}/api/collections:list`, {
  headers: { Authorization: `Bearer ${process.env.NB_TOKEN}` },
});
const data = await res.json();
// axios
import axios from "axios";

const nb = axios.create({
  baseURL: `${process.env.NB_URL}/api`,
  headers: { Authorization: `Bearer ${process.env.NB_TOKEN}` },
});

const { data } = await nb.get("/collections:list");

Rotation and revocation

  • Tokens are revoked from the same screen (Settings → API keys → Delete).
  • Rotation: create the new token first, deploy it, then delete the old one — there is no in-place rotation.
  • Tokens inherit the role at issuance. If the role is later restricted, the token is restricted on the next request.

Path C — OAuth through IdP: OAuth (NocoBase as the identity provider)

The IdP: OAuth plugin (@nocobase/plugin-idp-oauth, built in, enabled by default; OAuth 2.1 and OpenID Connect) turns NocoBase into an identity provider for other tools. It is what lets nb env auth --auth-type oauth and MCP clients sign in as a NocoBase user without an API key or a stored password. It is not the way users sign in to NocoBase with an external IdP — that is Path D.

nb plugin list                                  # confirm @nocobase/plugin-idp-oauth is enabled
nb env auth prod --auth-type oauth              # CLI: device flow on headless hosts, browser otherwise

MCP clients (Claude Code shown; the endpoint is https://<host>:<port>/api/mcp, see overview):

claude mcp add --transport http nocobase https://<host>:<port>/api/mcp
# then, inside Claude Code: /mcp  → pick the server → sign in

Permissions follow the signed-in user; if the user has several roles, choose one with the x-role request header (nb api … --role <name> sets it).

Path D — Auth: OIDC (SSO sign-in for end users)

Auth: OIDC is a separate, commercial (Professional Edition) plugin that lets people sign in to NocoBase with accounts from an external IdP (Google, Keycloak, Microsoft Entra ID, …) using the Authorization Code flow. It is not for backend scripts — use Path A, B or C for those. It is a licensed plugin and is not on public npm — licensed plugins are managed with nb license (nb license --help), then enabled like any other.

  1. Enable the Auth: OIDC plugin in the plugin manager (licensed plugin).
  2. Settings → Authentication → Add → OIDC and fill in: Issuer (the IdP's issuer / discovery URL), Client ID, Client Secret, scope (default openid email profile), and the field mapping used to bind users (email or username).
  3. Copy the Redirect URL shown in the plugin's Usage section into the IdP's client settings.
  4. Users sign in from the login page by clicking the provider button below the login form.

When testing locally use 127.0.0.1 rather than localhost — the state value is validated through a client cookie.

A browser SSO login gives a browser session. For agents and scripts, create an API key (Path B), or use Path C.

Common 401 / 403 causes

  • Missing or wrong Authorization header — value is exactly Bearer <token>, single space, case-sensitive Bearer.
  • Token expired (API Key with explicit expiration, sign-in token after TTL, OAuth access token).
  • API key issued before APP_KEY was changed — recreate it.
  • Role attached to the token has no permission — check nocobase-acl-manage.
  • Plugin providing the token type is disabled — nb plugin list to confirm @nocobase/plugin-api-keys (API keys) or @nocobase/plugin-idp-oauth (OAuth) is enabled.
  • Multi-app instance — make sure the X-App header / hostname matches the app the token was issued for.
  • Wrong --api-base-url for the CLI — it must include the /api prefix (nb env info <name> shows what is saved; nb env update <name> --api-base-url … fixes it).

OpenAPI declaration

The full spec at ${CLAUDE_PLUGIN_ROOT}/references/openapi/nocobase.json declares:

"securitySchemes": {
  "api-key": { "type": "http", "scheme": "bearer" }
}

All the paths above (CLI env, sign-in, API Key, OAuth) produce a bearer token that satisfies this scheme — the server validates the token, not its origin.