Files
dify/cli/docs/auth-storage.md

5.6 KiB

difyctl — token storage backends

How difyctl decides where to store the OAuth bearer it acquires from the Dify API service. Two backends, OS-aware probe, deterministic fallback.

Spec authority for the auth model itself: docs/specs/auth.md. This file documents the storage layer only — what backend is selected, when, and how to override it.

Backends

Backend Module When selected What's stored
OS keychain @napi-rs/keyring Probe succeeds (default) Bearer + refresh blob, opaque to disk
Encrypted file cli/src/auth/file-store.ts Probe fails or DIFY_TOKEN_STORAGE=file 0600 JSON at <config-dir>/tokens.json

The file backend is not plaintext: token bytes are sealed via a key derived from the OS user's HOME path and a process-stable salt. It exists so that difyctl works on minimal Linux containers without a Secret Service / keyctl, and on macOS hosts where Keychain access is administratively blocked.

Selection algorithm

1. read DIFY_TOKEN_STORAGE — values: keychain | file | auto (default)
2. if value == file:        use file backend, exit
3. if value == keychain:    probe; on failure exit 4 (auth_expired) + hint
4. if value == auto/unset:
     a. probe keychain
     b. if probe ok:        use keychain
     c. if probe ENOTSUP:   fall back to file (silent)
     d. if probe ESERVICE:  fall back to file + stderr warning

The probe is a no-op write of a sentinel record under the difyctl service name, followed by read-back and delete. It runs once per process; the result is cached on the bundle so command bodies do not re-probe.

Per-OS expectations

Platform Backend Notes
macOS 12+ Keychain via Keychain Services One entry per (host, subject_id) under service difyctl
Linux + GNOME / KDE / KeePassXC Secret Service via libsecret Falls back to file in headless containers
Linux + keyctl-only kernels File @napi-rs/keyring does not bind keyctl; no probe attempted
Windows 10/11 Credential Manager Service: difyctl/<host>
WSL Same as Linux The probe inherits whatever Secret Service the WSL distro provides

Prebuild matrix

@napi-rs/keyring ships native binaries for the targets the CLI distribution covers. The CI matrix below mirrors the oclif tarball matrix:

os/arch binary source
darwin-arm64 keyring.darwin-arm64.node npm package
darwin-x64 keyring.darwin-x64.node npm package
linux-x64-gnu keyring.linux-x64-gnu.node npm package
linux-arm64-gnu keyring.linux-arm64-gnu.node npm package
win32-x64 keyring.win32-x64-msvc.node npm package

If a platform / arch lacks a prebuild and @napi-rs/keyring cannot install at runtime, the file backend takes over without user intervention.

Manual override

Operators force a backend via env var:

DIFY_TOKEN_STORAGE=keychain difyctl auth login   # require keychain (fail loud)
DIFY_TOKEN_STORAGE=file     difyctl auth login   # force file backend

Use the file form on shared CI runners where the Secret Service is unavailable but you still want a per-runner token. Use keychain on developer machines to fail fast if the keychain is locked or denied.

Failure modes

Symptom Cause Recovery
auth login succeeds but auth status says "no credentials" Keychain wrote, file path probed at read time Set DIFY_TOKEN_STORAGE=file to pin one backend
keychain probe failed (errno -2) Linux container without libsecret, no fallback because DIFY_TOKEN_STORAGE=keychain Unset the env var or set =file
Multiple difyctl/<host> entries in Keychain Hosts changed but old entries not pruned auth logout --all-hosts (post-v1.0); for v1.0, prune manually
Tokens disappear on macOS after every reboot Keychain locked or in iCloud-only mode Either unlock the login keychain or fall back to file

Source pointers

  • Backend selection: cli/src/auth/storage.ts
  • Keychain wrapper: cli/src/auth/keychain.ts (uses @napi-rs/keyring)
  • File backend: cli/src/auth/file-store.ts
  • Probe gate: cli/src/auth/probe.ts