Skip to content

Authentication

JoKeks2023 edited this page Sep 28, 2026 · 1 revision

Authentication

The server authenticates once, at account level. Workspace access is derived from that login afterwards (see Multi-Workspace). Two options are available. If HULY_TOKEN is set it wins; otherwise email + password is used.

Option Variables For
A — Email + password HULY_EMAIL, HULY_PASSWORD Accounts with a password (recommended)
B — Token HULY_TOKEN SSO accounts (Google/GitHub) without a password

Both go to the account service at HULY_ACCOUNTS_URL (default https://account.huly.app).

Option A — Email + password

HULY_EMAIL=you@example.com
HULY_PASSWORD=your-password

Flow, from login() in src/connection.ts:

  1. An unauthenticated account client calls login(email, password).
  2. The response must contain a token (the account token) and a socialId. Otherwise login fails with "Login failed: no token returned. Check credentials." or "Login failed: no socialId returned."
  3. An account-level client is created with that account token. It is used for getUserWorkspaces() and selectWorkspace().

The password is only sent to the account service. It is never logged and never used for anything else.

Option B — HULY_TOKEN

HULY_TOKEN=eyJ...

Flow:

  1. An account client is created with HULY_TOKEN, and getLoginInfoByToken() is called.
  2. null means the token is invalid or expired: "HULY_TOKEN is invalid or expired. Please get a fresh token (npm run setup)."
  3. A socialId is required: "Token auth: no socialId returned for HULY_TOKEN."
  4. What happens next depends on the kind of token, see the next section.

Account token vs. workspace token

Huly issues two kinds of tokens:

Account token Workspace token
Identifies The account The account and one workspace
Returned by login(), validateOtp() (setup wizard) selectWorkspace(); also what the browser tab of an open workspace typically holds
getLoginInfoByToken() returns LoginInfo (no endpoint) WorkspaceLoginInfo (with workspace, workspaceUrl, endpoint)
Used in this server for Discovery (getUserWorkspaces()) and selectWorkspace() The WebSocket connection, /files requests, getWorkspaceMembers()

HULY_TOKEN as account token (recommended). Full multi-workspace discovery works. getUserWorkspaces() and selectWorkspace() run with this token, exactly like option A.

HULY_TOKEN as workspace token (e.g. copied from browser DevTools):

  • The server still tries getUserWorkspaces() with it.
  • If the account service refuses, the server falls back to the one workspace the token belongs to.
  • That workspace is used directly with the endpoint and token from getLoginInfoByToken(), without a selectWorkspace() call.
  • Other workspaces are then not available. Use the setup wizard to get an account token.

Setup wizard

npm run setup          # from a clone of the repository

scripts/setup.js:

  1. Asks for your email and sends a one-time code (loginOtp).
  2. Validates the code (validateOtp) and receives an account token.
  3. Discovery test: calls getUserWorkspaces() and prints every workspace (name, slug, id, [disabled] flag).
  4. Writes HULY_TOKEN (and HULY_ACCOUNTS_URL if not the Cloud default) to .env in the project root, which is the directory above scripts/. Run it from a clone. Via npx the file would land in the npx cache.

It does not ask for a workspace. When it rewrites .env it removes HULY_TOKEN, HULY_WORKSPACE, HULY_EMAIL, HULY_PASSWORD and HULY_ACCOUNTS_URL, then adds the new values. If HULY_WORKSPACE was present it tells you, because the server now uses all workspaces (see Legacy HULY_WORKSPACE). The token itself is never printed.

Set HULY_ACCOUNTS_URL in the environment before running the wizard against a self-hosted instance.

Tokens expire. When you get the "invalid or expired" error, run the wizard again or switch to email + password.

Where the URLs fit in

Variable Service Used for Auth
HULY_ACCOUNTS_URL Account service login, getLoginInfoByToken, getUserWorkspaces, selectWorkspace, getWorkspaceMembers Account token (discovery/selection), workspace token (members)
(from selectWorkspace) Transactor (WebSocket endpoint) All reads/writes of Huly data Workspace token
HULY_FRONT_URL Front service Document/description content, file uploads/deletes (/files) Workspace token as Authorization: Bearer header

HULY_FRONT_URL plays no part in login or workspace discovery. See Configuration and Architecture.

Session lifetime

  • Login happens lazily on the first tool call (or list_workspaces) and is cached for the life of the process.
  • A failed login is not cached: the next call tries again.
  • closeConnection() (on SIGINT/SIGTERM) closes all workspace connections and drops the session.
  • There is no automatic re-login when a token expires while the server is running. Restart the server.

Clone this wiki locally