API authentication

The Huudis admin API uses bearer JWT authentication. Every request carries an access token in the Authorization header:

Authorization: Bearer eyJhbGciOiJFUzI1NiIsImtpZCI6...

Tokens are ES256-signed JWTs that Huudis can verify locally — no database round-trip per request.

This page covers how to obtain a token for different audiences.

Getting a token for an interactive admin

If you're scripting against your own workspace, the easiest path is the CLI:

npm install -g @forjio/huudis-cli
huudis auth login
# Visit https://huudis.com/device and enter code A3F7-9C2D
# Signed in as you@yourcompany.com

After auth login, the CLI stashes a long-lived refresh token at ~/.config/huudis/credentials.json and silently mints fresh access tokens for every command. You can extract the current access token explicitly:

huudis auth print-token
# eyJhbGciOiJFUzI1NiIsImtpZCI6...

Useful for piping into curl:

curl https://huudis.com/api/v1/oidc-clients \
  -H "Authorization: Bearer $(huudis auth print-token)"

The token from print-token is short-lived (6 hours) — for long-running scripts, prefer the SDK which auto-refreshes.

Getting a token for a CI/CD service

For pipelines, create a service account user instead of using your personal credentials.

  1. Dashboard → Users → New service account. Pick a name and a role (typically Admin).
  2. Click Issue access key. Huudis returns:
{
  "keyId": "AKIA0123456789ABCDEF",
  "secret": "<one-time-shown secret>",
  "createdAt": "2026-05-12T03:14:00.000Z"
}
  1. Store both in your CI's secret manager as HUUDIS_KEY_ID and HUUDIS_KEY_SECRET.

  2. At pipeline start, exchange the key pair for a short-lived access token:

POST /api/v1/auth/access-key/exchange
Content-Type: application/json

{
  "keyId": "AKIA0123456789ABCDEF",
  "secret": "..."
}

Response:

{
  "data": {
    "accessToken": "eyJhbGciOiJFUzI1NiI...",
    "expiresIn": 3600,
    "tokenType": "Bearer"
  }
}
  1. Use that bearer token for the rest of the pipeline. Access keys are revocable from the dashboard — rotation is just "create new, switch CI, delete old".

Don't reuse personal credentials in CI. A service account ties pipeline actions to a non-human identity in the audit log and survives team-member turnover. The SDKs accept keyId + secret directly and do the exchange transparently.

Getting a token for a relying-party app

If you're a Forjio product (or third-party app) acting on behalf of a signed-in end user, you already have a token — it's the access_token from the OIDC /oidc/token response.

That token authenticates the end user, not your service. Use it to call endpoints the end user is allowed to call:

  • GET /api/v1/oidc/userinfo — the user's profile.
  • GET /api/v1/account/services — the services this user's account has opted into.
  • POST /api/v1/account/services/enable — opt this account into your service.

Endpoints under /ops/*, /iam/*, and workspace-level admin paths require an admin token. End-user tokens get FORBIDDEN on those.

Verifying a token

Huudis tokens are JWTs you can verify locally with the published JWKS:

import { verifyAccessToken } from '@forjio/huudis-node';

const claims = await verifyAccessToken(token, {
  jwksUrl: 'https://huudis.com/.well-known/jwks.json',
});

// claims.sub === user ID
// claims.aud === audience (your client_id)
// claims.scope === space-separated scope list
// claims.exp === expiry epoch seconds

The Python and Go SDKs expose the same helper. Cache the JWKS in-process; Huudis publishes a Cache-Control: max-age=300 header on the JWKS endpoint.

Always verify the aud claim. A token issued for one OIDC client should never be honored by a different client. The SDK helpers default to checking aud === clientId you passed at construction.

Token claims

A typical access token decodes to:

{
  "iss": "https://huudis.com",
  "sub": "usr_01KPG30SPWNKDQ9G40NET6QKA2",
  "aud": "oc_01KPG30SQTDDZ469FGR7DBE0DC",
  "iat": 1747033200,
  "exp": 1747054800,
  "scope": "openid profile email",
  "act_id": "acc_01KPG30SQTDDZ469FGR7DBE0DC",
  "mfa": true,
  "amr": ["pwd", "totp"]
}
  • act_id — the active account ID for this session.
  • mfa — whether the session passed MFA.
  • amr — authentication methods reference (pwd, totp, webauthn, google, apple, facebook).

Next