Skip to main content

Authentication

Almost every endpoint requires authentication (NATIVE_WAZUH_REQUIRE_AUTH=true is the default). The API accepts four mechanisms — pick whichever fits your use case.

Supported methods

MethodHeaderTypical use
API keyX-API-Key: rfk_… or Authorization: Bearer rfk_…Integrations, scripts, CI/CD.
JWT BearerAuthorization: Bearer <jwt>SPAs, user agents after login.
Session cookieCookie: ruleforge_session=<jwt>Browser hitting RuleForge itself.
OIDC/SSO3-legged flow, results in cookie/JWTOrganizations with a corporate IdP.

Rule of thumb: for anything that isn't a browser, use API keys. The lifecycle is simpler, scopes are granular and don't depend on session state.

API keys

Format

Every RuleForge API key starts with the rfk_ prefix followed by a random string. Example:

rfk_01HS2XA9CKEB7WZG8RMN2KPQV7_e6c4f2…

How to get one

A key is created by an organization admin in the UI (Settings → API keys) or via API through POST /platform/organizations/{organization_id}/api-keys. The full value appears only once at creation time — store it in a secrets manager.

See the operational guide: API keys.

How to send it

The API accepts the secret in two headers — use one of the two:

X-API-Key: rfk_01HS2XA9CKEB7WZG8RMN2KPQV7_e6c4f2…

or

Authorization: Bearer rfk_01HS2XA9CKEB7WZG8RMN2KPQV7_e6c4f2…

If the key belongs to a user who is also a member of other organizations, send X-Org-Id to pin the context. For API keys this is usually unnecessary — the key is already scoped to an organization.

Scopes

Each key has a set of scopes that restrict what it can do. Pick the smallest set sufficient for the integration.

ScopeInternal permissions
projects:readView projects, workspaces, versions.
projects:writeprojects:read + create/edit projects.
rulesets:readRead rulesets for a project.
rulesets:writerulesets:read + create workspaces and edit content.
analysis:runRun POST /analysis/validate, logtest-native, full.
cases:readList and run test cases.
cases:writecases:read + create/edit cases.
reviews:readList reviews.
reviews:writeOpen reviews, comment, approve.
versions:readList versions.
versions:writeCreate and publish versions.
admin:*Full org set (including members and integrations). Use only in controlled administrative automations.

If the key lacks the required scope, the response is 403 forbidden with code="forbidden" and a message indicating insufficient scope.

Lifecycle

  • Expiration: optional. Always use it when temporary.
  • Rotation: POST …/api-keys/{id}/rotate — generates a new secret, keeps the ID. The old key is invalidated immediately.
  • Revocation: POST …/api-keys/{id}/revoke — ends access. Irreversible.

All actions are audited in the organization.

Project restriction

A key can be created with project_id — in that case it only authorizes operations on the given project. Requests on other projects return 403.

JWT Bearer

JWT is issued by POST /auth/login:

{
"access_token": "<jwt>",
"token_type": "bearer",
"expires_at": "2026-04-25T03:30:00Z",
"user": { "...": "..." }
}

Send the token on every subsequent request:

Authorization: Bearer <jwt>
  • Default TTL: 480 minutes (8 hours), controlled by NATIVE_WAZUH_JWT_TTL_MINUTES.
  • Refresh: log in again — there is no refresh token at this time.
  • Revocation: POST /auth/logout invalidates the jti on the server; the cookie is cleared and the JWT stops being accepted even before it expires.

RuleForge JWTs do not start with rfk_. If your token starts with rfk_ you are using an API key — send it in the X-API-Key header or accept that Bearer rfk_… is treated as an API key by the server.

When login happens in a browser, the server sets the cookie:

Set-Cookie: ruleforge_session=<jwt>; HttpOnly; SameSite=Lax; Path=/

Flags controlled by envs:

  • NATIVE_WAZUH_SESSION_COOKIE_NAME (default ruleforge_session)
  • NATIVE_WAZUH_SESSION_COOKIE_SECURE (default false; true on HTTPS production)
  • NATIVE_WAZUH_SESSION_COOKIE_SAMESITE (lax, strict or none)
  • NATIVE_WAZUH_SESSION_TTL_SECONDS (default 900 s — periodic revalidation by the frontend)

Use cookies only when the client is a browser. In scripts, prefer API keys or an explicit JWT.

Corporate OIDC / SSO

Organizations with a corporate IdP (Okta, Entra ID, Google Workspace, Keycloak) may delegate login:

  1. User navigates to GET /sso/oidc/{provider_id}/login.
  2. RuleForge redirects to the IdP.
  3. IdP calls back to GET /sso/oidc/callback.
  4. A session is created (cookie) and the user is redirected to the app.

Endpoint details at SSO and operational configuration.

Roles and permissions (user session)

For authenticated users (JWT/cookie), permission comes from the role in the organization (and project-specific roles). Summary:

RoleWhat they can do
org_adminEverything in the organization, including members, integrations and identity providers.
security_content_leadContent management + approvals.
engineerCreate and edit content, run analysis, open reviews and versions.
reviewerView content, comment, approve.
read_onlyView and run analysis.

See Roles and permissions for details and the full matrix. For API keys what matters is the scope — roles don't apply.

Unauthenticated requests

Some endpoints are open by design:

  • GET /api/v1/health — liveness.
  • GET /api/v1/product/status — public product status.
  • GET /healthz — readiness probe (not under /api/v1).
  • POST /auth/bootstrap — one-time, when the platform is blank.
  • POST /auth/login — submit credentials, receive JWT.
  • GET /billing/plans/public — list publicly visible plans.
  • Inbound webhook endpoints (/webhooks/git/*, /billing/webhooks/stripe) — authenticated via HMAC signature.

Everything else requires authentication.

Authentication errors

CodeWhen it happens
401 unauthorizedMissing, invalid, expired or revoked token/key.
403 forbiddenAuthenticated but lacking permission (insufficient role or scope, organization out of context).
429 rate_limitedToo many login or registration attempts from the same IP/email.

Responses follow the standard error envelope. Generate a new key/session before retrying on 401.