Repository navigation
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).
HULY_EMAIL=you@example.com
HULY_PASSWORD=your-passwordFlow, from login() in src/connection.ts:
- An unauthenticated account client calls
login(email, password). - 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."
- An account-level client is created with that account token. It is used for
getUserWorkspaces()andselectWorkspace().
The password is only sent to the account service. It is never logged and never used for anything else.
HULY_TOKEN=eyJ...Flow:
- An account client is created with
HULY_TOKEN, andgetLoginInfoByToken()is called. -
nullmeans the token is invalid or expired: "HULY_TOKEN is invalid or expired. Please get a fresh token (npm run setup)." - A
socialIdis required: "Token auth: no socialId returned for HULY_TOKEN." - What happens next depends on the kind of token, see the next section.
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 aselectWorkspace()call. - Other workspaces are then not available. Use the setup wizard to get an account token.
npm run setup # from a clone of the repository- Asks for your email and sends a one-time code (
loginOtp). - Validates the code (
validateOtp) and receives an account token. -
Discovery test: calls
getUserWorkspaces()and prints every workspace (name, slug, id,[disabled]flag). - Writes
HULY_TOKEN(andHULY_ACCOUNTS_URLif not the Cloud default) to.envin the project root, which is the directory abovescripts/. Run it from a clone. Vianpxthe 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.
| 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.
- 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()(onSIGINT/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.