Advanced Topics

Authentication

Secure access to the dxflow engine with a private key or a single use pairing code

dxflow offers two ways to sign in, and both end in a JWT session with a configurable lifetime.

  • Private key — challenge-response with an RSA key pair, so you prove you own the key without ever sending it. The browser remembers yours, making repeat sign-ins a single click. Multiple keys are supported, each with its own permissions.
  • Pairing code — a short code printed by the engine host and approved there. Suited to a server you reach over SSH, where copying the key to your laptop would be the only alternative.

Signing in with a private key

Locate your private key

The first time an engine starts it creates a key pair for itself, writes the private half to ~/.dxflow/private-key.pem (mode 600), and authorizes the public half with MASTER. That file is the key to sign in with — copy it to the machine running the browser.

To issue an additional key, run dxflow key generate [NAME]. It writes <name>.pem (private) and <name>.pub (public) to your current directory (default name rsa); register the .pub with dxflow key register <name>.pub.

dxflow key list shows the public keys authorized on the engine (stored in ~/.dxflow/authorized_keys), not your local private key files.

Open the login page

  • Local installation: http://localhost (or your configured port)
  • Remote server: http://<your-server-ip>:<port>

Sign in

Choose Private key as the method, pick a session duration, and select your .pem or .key file. The key stays on your device.

Signing in with a pairing code

Use this when the engine runs somewhere you have shell access, such as an EC2 instance or any cloud VM. The private key stays on the server.

Ask the engine for a code

On the machine running the engine:

dxflow engine pair

It prints a code and waits:

Terminal
 Pairing
  Permissions  SHELL, ARTIFACT, RUNTIME, WORKFLOW, AGENT
  Code         K7QM3XPD
  Waiting 30s for a console to use the code

Enter the code in the console

Open the console, choose Pairing code as the method, and type the code. Opening http://<your-server-ip>:<port>/#pair=K7QM3XPD fills it in for you.

Approve the request

The terminal shows who is asking, and answering y signs the console in:

Terminal
 Pairing request
  Address      203.0.113.9
  Agent        Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)
  Approve? [y/N] y
Pairing approved: the console is signed in

Scope the session with flags on the command:

dxflow engine pair --permissions SHELL,RUNTIME   # limit what the session can do
dxflow engine pair --lifetime 24h                # 1 minute to 24 hours, default 1 hour

A code lasts 30 seconds, and you get a further 30 seconds to answer once a console claims it. It works once — approving, rejecting, and letting it expire all consume it — so every session starts with a fresh dxflow engine pair. The browser keeps nothing afterwards, which makes pairing a good fit for a shared or borrowed machine.

Key management

# List authorized keys (by IDENTITY)
dxflow key list

# Generate a new key pair (optional NAME, default "rsa")
dxflow key generate [NAME]

# Register an additional public key
dxflow key register <public-key-file>

# Remove a key
dxflow key unregister <key-identity>

Register a key with a narrower scope by passing --permissions; a key registered without them receives SHELL,ARTIFACT,RUNTIME,WORKFLOW,AGENT. See the permission model.

Session management

Sessions use JWT tokens with a lifetime of 1 minute to 24 hours (default 1 hour). They:

  • Persist across browser tabs and survive page refresh and navigation
  • Renew automatically during active use and stay in sync across tabs
  • End on logout, and expired tokens are cleaned up automatically

Calling the API directly

To authenticate from your own code, use these three endpoints. You sign the challenge with your private key, so the key is never sent.

StepEndpointWhat it returns
Request a challengeGET /api/auth/challenge/identity, nonce, lifetime
Sign and verifyPOST /api/auth/verify/A JWT token, permissions, and expires_at
Check a sessionGET /api/auth/inspect/Confirms whether the JWT (sent in the request headers) is still valid

Pairing uses one endpoint from a client's side: POST /api/auth/pair/request/ with { "code": "K7QM3XPD" }. It streams a confirmation that the code was accepted, holds the connection while the operator decides, and answers with the same token, permissions, and expires_at on approval. A rejected, unknown, expired, or already-claimed code answers 401.

Challenge response:

{
  "identity": "your-key-identity",
  "nonce": "random-challenge-string",
  "lifetime": "1m0s"
}

Verify response. Send an optional lifetime (e.g. "1h") to set the token duration. Range is 1 minute to 24 hours; out-of-range or omitted values use the 1 hour default.

{
  "token": "jwt-authentication-token",
  "permissions": ["SHELL", "ARTIFACT", "WORKFLOW"],
  "expires_at": 1640995200
}

Troubleshooting

SymptomFix
Cannot locate a private keyThe engine's own key is at ~/.dxflow/private-key.pem on the engine host. dxflow key list shows what is authorized, not local files.
The private key won't parsedxflow reads PKCS#1/PKCS#8 PEM. An ssh-keygen key needs -m PEM — convert an existing one with ssh-keygen -p -m PEM -f <key>.
Signature verification failsThe private key doesn't match any registered public key. Register it, or generate a fresh pair.
401 Unauthorized from the CLIdxflow config unset connection-token && dxflow engine ping forces a fresh token.
Authentication fails on a correct keyCheck the system clock — token validity is time-based.
invalid pairing codeThe 30-second window passed, the code was already claimed, or a character was mistyped. Run dxflow engine pair again.
pairing expired on approvalThe decision window is 30 seconds. Have the code typed in the browser before you answer.
Permission denied on an operationThe key lacks that permission, or the license does not grant the module. Check with dxflow key list and dxflow license info.
Compromised key: remove it with dxflow key unregister <identity>, register a replacement, and update anything that used the old one.