dbx-tools-auth
Provider-neutral OAuth and persistent credentials for Rust, Node, and Python.
The crate owns authorization-code login with PKCE, client-credentials OAuth,
refresh-token rotation, rejected-token comparison, and check-lock-check
coordination. Databricks-specific profile and endpoint resolution stays in
dbx-tools-databricks-auth.
TokenProvider is the Rust acquisition boundary. ProviderOptions exposes a
configurable OAuth provider through generated Node and Python bindings: provider
name, optional profile, scopes, endpoints, client identity, grant, storage, and
timeouts. dbx-tools-google-auth imports this lifecycle and its generated
contracts directly.
Shared options and provider implementations
Rust and UniFFI records do not support class inheritance. ProviderOptions.auth
and DatabricksAuthOptions.auth compose the same Rust-owned AuthOptions record;
the generated Node and Python providers import that record from shared auth.
Omit auth to use the defaults: a 30-second lock timeout, a 3600-second login
timeout, a 300-second refresh window, and the built-in callback image.
Explicit records use AuthOptions::default() in Rust, AuthOptions.create({})
in Node, and AuthOptions() in Python. Node represents the integer seconds as
bigint; Python uses int. Negative refresh windows are supported, but an
expired token is never reused simply because its refresh window is negative.
use AuthOptions;
let auth = AuthOptions ;
Rust provider wrappers implement AuthSession::auth_client to inherit login,
token lookup, login-policy dispatch, forced refresh, rejected-token comparison,
logout, and backend naming. Import AuthSession to call these trait methods.
TokenProvider deliberately requires acquisition and refresh implementations:
a default refresh that opens a browser would violate noninteractive token
lookup. Its safe default is can_authenticate_silently() == false.
CredentialStore::prepare_write defaults to a no-op, while
StorageLock::release consumes and drops an RAII lease. Lock acquisition and
credential mutation remain required. UniFFI foreign callback interfaces do not
inherit Rust default bodies: Node/Python StorageAdapter implementers must
provide every method, including an explicit no-op preflight when appropriate.
Credential identity is provider plus optional profile plus the SHA-256 hash of
trimmed, deduplicated, sorted scopes. Generic storage defaults to
~/.dbx-tools/auth; the directory can be overridden.
FileLayout.Single keeps one versioned token-cache.json and serializes refresh
for the entire file. FileLayout.PerCredential keeps one hashed credential
directory and token file per identity, with independent refresh locks. File
read-modify-write uses a separate short-held lock and atomic replacement.
Memory storage retains access tokens only for the current process while using
an in-process lock for refresh coordination.
StorageAdapter supports custom persistence without any database dependency.
For cross-package use, create a StorageHandle in this package and pass the
handle to the provider wrapper. This preserves callback ownership when separate
native libraries are loaded. Access-token results never expose refresh tokens;
custom storage receives sensitive credential JSON and must protect it.
Both create_provider_auth_with_storage and
create_persistent_auth_with_storage accept that same handle. Wrap an adapter
with create_storage_handle (Node: createStorageHandle) before passing it to
either factory.