mcpbeat Sign in

Nocobase App Plugin Authentication Agent Skill

Build authentication requirements in a NocoBase 3 application: protect API routes and pages with the session, read and refresh the session in the browser, customize the login, registration and password pages, add sign-in methods such as social login, OIDC or a custom Better Auth plugin, enable official Better Auth plugins (device login for a CLI, bearer tokens, organizations, two-factor, passkeys) with the migration their tables need, manage account lifecycle from server code, and configure secrets, cookies and shared storage for deployment.

3.1k tokens
context cost
SKILL.md, read when the skill is used
8
files
plus reference files
0
copies elsewhere
how many repositories repackaged it
24 822
stars on the repo
on the repository, not the skill itself

Install

one command, takes just this skill from the repository
npx skills add https://github.com/nocobase/nocobase --skill nocobase-app-plugin-authentication

What comes with it

59 452 bytes besides the instruction
references/adding-sign-in-methods.md
references/authentication-email.md
references/better-auth-plugins.md
references/client-session-and-pages.md
references/custom-better-auth-plugin.md
references/protecting-routes.md
references/user-lifecycle-and-deployment.md

The instruction itself

10 sections, as written by the author

Authentication development

Use this Skill when an application built on @nocobase/app-plugin-authentication

needs anything about who the caller is: protecting a route or page, reading the

current user, changing the sign-in pages, adding a sign-in method, disabling

accounts, or preparing authentication for deployment.

Do not use it for what a signed-in user may do — that is

nocobase-app-plugin-authorization — or for the user administration page,

which is nocobase-app-plugin-users. Do not modify the plugin's own source,

migrations, or dist/; everything below is done in the application.

The plugin wraps Better Auth. Application configuration is Better Auth

configuration, and every Better Auth plugin, social provider, and hook is

available through it. Read the installed Better Auth version's documentation

for option details; this Skill covers where those options go in a NocoBase

application and what the plugin adds on top.

Enable an official Better Auth plugin before writing anything of your own: device login for a CLI (deviceAuthorization() with bearer()), organizations, two-factor and passkeys all exist upstream, and each needs only configuration, an application migration for its tables, and its UI. Enabling an official Better Auth plugin covers the rule, the schema check and the migration.

Public surfaces

Server, from @nocobase/app-plugin-authentication (the root entry is the

server entry) or @nocobase/app-plugin-authentication/server:

  • authenticationToken resolves the Auth instance: required(),

optional(), getSession(headers), handler(request), signInUser(userId, request).

  • AuthEnv types a Hono router whose routes read context.get('auth').
  • userAdministrationServiceToken resolves UserAdministrationService:

list, get, create, update, disable, enable, resetPassword,

revokeSessions, withConnection; errors are UserAdministrationError.

  • AuthConfig is Better Auth's BetterAuthOptions, the type of the application's server/config/auth.ts. User initialization configuration lives separately under users.initialAdmin.
  • createAuthentication, databaseAdapter, createAuthStorage build an

instance outside the application runtime, mainly in tests.

Client, from @nocobase/app-plugin-authentication/client:

  • authentication() is the registration factory. It takes no options,

contributes no routes, and mounts one React provider.

  • useAuthentication() returns { client, session, isPending, refresh };

useAuthenticationClient() returns the Better Auth client alone.

  • RequiredAuthentication, GuestAuthentication, and

AuthenticationGuard({ mode }) gate a route subtree on the session.

  • AuthConfig is Better Auth's client options, the type of the application's

client/config/auth.ts.

  • authenticationClientToken is the client's service token, used to stub the

client in component tests.

Headless actions, from @nocobase/app-plugin-authentication/client/actions:

usePasswordLogin, usePasswordRegistration, usePasswordResetRequest,

usePasswordReset, each returning { submit, isPending, error }.

HTTP: every Better Auth endpoint is served under /api/auth/* by the plugin's

own route. A Better Auth plugin's endpoints appear there automatically. There

is no other authentication REST surface.

API document: the plugin lets a signed-in session read the App's OpenAPI document at GET /api/swagger and its Swagger UI at GET /api/swagger/docs; an anonymous request gets 401 with error.reason API_DOCS_UNAUTHENTICATED, and @nocobase/app-plugin-api-keys adds API keys as a second way in. The plugin also merges Better Auth's endpoints into that document from Better Auth's own OpenAPI generator, at their full /api/auth/... paths and tagged Authentication, so a Better Auth plugin added to auth.plugins is documented without further work. Browser-only steps are left out: /sign-in/social, /link-social, /callback/{id}, /verify-email, /reset-password/{token}, /delete-user/callback and /error. Do not add Better Auth's openAPI() plugin: it would publish its own unauthenticated /api/auth/reference page and schema route.

Choose the task path

| The task is | Read |

| -------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- |

| Require or read the session in an API route, compose with authorization, test it | protecting routes |

| Read the user in a component, sign out, gate a page, change the login pages, add SSO buttons | client session and pages |

| Add GitHub, Google, OIDC, magic link, or another sign-in method | adding sign-in methods |

| Enable any official Better Auth plugin: CLI device login, bearer tokens, organizations, 2FA | Better Auth plugins |

| The identity platform uses a protocol Better Auth cannot express | custom Better Auth plugin |

| Disable or reset an account from server code, add user fields, send reset emails, deploy | user lifecycle and deployment |

Read only the reference the task needs.

Ownership

  • The plugin owns the protocol, the user, session, account, and

verification collections and their migrations, session validation, the

guards, the headless actions, and the /api/auth/* route.

  • The application owns server/config/auth.ts, client/config/auth.ts, the

four guest routes in client/routes.ts, the pages in client/pages/auth/,

the authentication UI in client/extensions/nocobase-auth-*/, its own migrations for any

schema a sign-in method adds, and every environment variable and secret.

  • Authorization owns permissions. Users owns the administration page. The

application's own code decides which roles exist.

  • The plugin's skills/ source is authoritative. .agents/skills/ is a

synchronized copy and must not be edited.

Reversible UI customization

Prefer props and page composition in client/pages/auth/, then new application components, over editing the UI Library blocks in client/extensions/nocobase-auth-*/. Reuse the headless authentication actions in custom forms. Disabling registration or another feature should preserve its pages and components, conditionally disable the route, and hide its entry points so it can be restored. The server must still reject the disabled operation. Read client session and pages for the implementation and verification rules.

Constraints

  • Mounting under /api authenticates nothing. A route is protected only by auth.required() on it. auth.optional() accepts anonymous requests but still rejects invalid credentials and untrusted cookie write origins. Without a configured authentication base URL, cookie write checks derive the trusted origin from each request URL using Better Auth's trusted-proxy-header policy; the Origin header is checked against that origin, never used to establish trust.
  • Browser guards are navigation, not security. The server authenticates every

request independently.

  • Configuring a Better Auth plugin changes no database. Any model or field it

needs is an application migration in database/main/migrations/; never copy or

edit the plugin's migrations, and never let Better Auth alter tables.

  • Sessions and cookies are created by Better Auth only. Do not mint a second

token, store a session in localStorage, or resolve identity from a client

claim.

  • Bind an external identity by a stable issuer + subject, never by an

unverified email. Merging accounts on email is a product decision that has to

be stated explicitly before it is implemented.

  • Secrets stay in server configuration or environment. Nothing under client/

may read one.

  • Never log a password, session token, verification value, ticket, or OAuth

token. Log user ids, request ids, and outcomes.

  • A disabled account is rejected at sign-in with 403 ACCOUNT_DISABLED, and

its existing sessions and realtime connections are revoked at once. Do not

add a parallel "active" flag.

Verification

  • Anonymous requests to a protected route return 401 with the standard error body, error.reason AUTHENTICATION_REQUIRED; the same request with a session returns the route's own response.
  • An authenticated request that lacks permission returns 403 from

authorization, not 401.

  • A required route redirects an anonymous browser to /login; a guest

route redirects a signed-in browser to /.

  • After sign-out the previous cookie no longer authenticates.
  • A new sign-in method signs a new user in, signs an already bound user in,

rejects an invalid, expired, or reused credential, and creates exactly one

binding under concurrent first sign-ins.

  • A migration added for a sign-in method runs up and down against a real

test database.

  • The application passes lint, typecheck, test, and build. Skill

synchronization alone proves only that the copy matches this source.

Trusted plugin API

Auth.pluginApi<TPlugin>(pluginId) returns only the registered plugin’s API methods through Better Auth’s normal dispatch, including before and after hooks. It does not expose the full authentication context and does not authenticate a caller. Auth.forConnection(connection) binds those operations to a caller-owned transaction. Consumers still enforce authorization; HTTP-specific hooks must explicitly check for request or headers instead of accidentally denying trusted server calls.

Initial administrator

Before the first seed run, set users.initialAdmin.username, users.initialAdmin.email and users.initialAdmin.password in application configuration to customize the bootstrap account. Omitting the entire node preserves nocobase / [email protected] / admin123; an explicit node requires a nonempty password and defaults the username to nocobase and the email to [email protected]. Usernames contain 3–30 letters, digits, underscores or dots, emails must be valid addresses, and both are stored lowercase. Initialization only runs when the user table is empty, hashes the password and grants the newly created account root permission through the authorization plugin. After initialization, configuration changes do not reset accounts or rerun the recorded seeds. The root permission seed selects the administrator by the same configured username. Use the user administration service for subsequent account changes. Do not edit historical seeds or add a competing administrator seed.

Trusted server session creation

Auth.signInUser(userId, request, { clientAddress }?) creates an ordinary browser session for an existing enabled person account after trusted server code has authorized that sign-in. It returns a Response; the caller checks its status and forwards its Set-Cookie headers. Better Auth applies the configured session hooks and cookie attributes, without reading or changing the password. There is no HTTP endpoint for this method. The calling plugin owns the access policy: Demo Mode uses it only while public quick sign-in is enabled. This method does not grant permissions or replace authentication for ordinary public login routes.

How to use it

Copy the folder

Take nocobase/nocobase-app-plugin-authentication from the repository into ~/.claude/skills for personal use, or into .claude/skills inside a project.

Check the name does not clash

The agent identifies a skill by the name field in its header. Two skills with the same name cannot sit side by side — one of them will be ignored.