Auth

Sign in, sign out, rotate credentials, authenticate from CI, transfer datasets, and rename your handle.

Authoring works without an account. Anything that publishes or modifies a dataset needs you signed in.

Sign in

esker login

A browser window opens to esker.so. After you sign in, the CLI prints:

  signed in as you@example.com · publishing as you

That's it. Credentials are stored at ~/.esker/credentials and used automatically by every subsequent command.

If the login times out (default 5 minutes), pass --timeout 600 to extend it.

Check who you're signed in as

esker whoami
  signed in as you@example.com · publishing as you

The handle on the right is the one your pushes will publish under. Use this when:

  • You're not sure if a stale terminal still has credentials.
  • You renamed your handle and want to confirm the change took effect (it won't, locally — see Rename your handle).
  • A push failed with not signed in and you want to confirm.

whoami round-trips to the hub on every call. If the network is down or your token has been revoked server-side, you'll see the failure here.

Sign out

esker logout

Removes ~/.esker/credentials. Idempotent — running it twice is harmless.

When your token expires

Tokens expire on a schedule. A push or check after expiry fails with:

  credentials expired — run 'esker login'

Run esker login again. Same browser flow, same one-line success.

The check is local — Esker reads the JWT's expiry claim before sending the request. So you'll see the message even when offline.

Authenticate from CI

CI runners can't open a browser. The pattern is to provision the credentials file directly.

Step 1. On a workstation that's signed in, copy the credentials file:

cat ~/.esker/credentials

Step 2. Add the contents as a CI secret (e.g. ESKER_CREDENTIALS_JSON).

Step 3. In your CI job, write the secret to a file and point the SDK at it:

# GitHub Actions
- name: Configure Esker
  run: |
    mkdir -p $RUNNER_TEMP/esker
    echo "$ESKER_CREDENTIALS_JSON" > $RUNNER_TEMP/esker/credentials
    chmod 600 $RUNNER_TEMP/esker/credentials
  env:
    ESKER_CREDENTIALS_JSON: ${{ secrets.ESKER_CREDENTIALS_JSON }}

- name: Push dataset
  run: esker push my.domain
  env:
    ESKER_CREDENTIALS_PATH: ${{ runner.temp }}/esker/credentials

ESKER_CREDENTIALS_PATH overrides the default ~/.esker/credentials location. The token inside the file has the same expiry as if you ran esker login locally — rotate it before it lapses.

For machine accounts that publish on behalf of an organization, sign in once as the machine user and reuse that credentials file across all CI environments.

Rename your handle

esker config set-handle <new>

Renames the handle server-side. Old <old>/<name> URLs 301 to <new>/<name>. Lockfile-bound consumers re-resolve on their next esker sync.

Transfer dataset ownership

esker transfer <ref> <new_owner>

Hand a dataset to another handle. You'll be prompted to confirm. Old <old>/<name> URLs 301 to <new_owner>/<name> after the transfer; consumers using the lockfile re-resolve on their next esker sync.

You must own the dataset (or be an admin of the owning org) to transfer it.

Make a dataset public or private

esker visibility <ref> public

Phase 1 only supports public. Passing private exits with private not yet supported · landing in phase 2.

public does not prompt — it's safe and reversible.

What needs auth and what doesn't

commands authenticated?
push, transfer, visibility, config set-handle yes
view, pull, head, manifest, schema, search no — public reads
login, logout, whoami self-evident
list, run, test, check local only, no network

This is why esker view archie/us.sec.companies works on a fresh machine with no credentials. Read access is a property of the dataset's visibility, not of the caller.

Where credentials live

path what override
~/.esker/credentials JSON: token, email, handle, expiry ESKER_CREDENTIALS_PATH

File mode is 0600 on Unix (best-effort — failure to chmod is silently ignored). On Windows, file ACLs aren't set; treat the file as sensitive and store it accordingly.

The format is one line of JSON:

{
  "token": "<jwt>",
  "user_email": "you@example.com",
  "owner_handle": "you",
  "expires_at": "2026-06-01T00:00:00+00:00"
}

You shouldn't normally touch the file directly — esker login and esker logout manage it — but if a tool needs to copy or rotate it (CI, dotfile sync), it's a single file you can move around.

Pointing at a different hub

By default, the SDK talks to localhost:3001 (API) and localhost:3000 (web). For production, set:

export ESKER_HUB_URL=https://hub.esker.so
export ESKER_WEB_URL=https://esker.so

Set these in your shell profile (or your CI environment). There is no .env file convention — Esker reads them straight from the process environment on every call.

Different environments (staging, production, a self-hosted instance) are just different ESKER_HUB_URL values. Credentials are scoped to the hub that issued them — you can't sign into staging and push to production with the same token.

Troubleshooting

not signed in — run 'esker login' — no credentials file exists, or it's at a path the SDK isn't looking. Confirm with ls ~/.esker/credentials (or wherever ESKER_CREDENTIALS_PATH points).

credentials expired — run 'esker login' — the JWT's expiry has passed. Re-authenticate.

hub 401: <message> — the server rejected the token. Causes: the token was revoked, the handle was deleted, the hub's signing keys rotated. Re-authenticate.

RemoteDisconnected / ConnectionRefusedError — the hub isn't reachable. Check ESKER_HUB_URL and your network.

Pushes go under the wrong handle after set-handle — the local credentials file is stale. Run esker login to refresh.

See also