Skip to main content

Crate stack_auth

Crate stack_auth 

Source
Expand description

§stack-auth

Crates.io Version docs.rs Built by CipherStash

Website | Docs | Discord

Authentication strategies for CipherStash services.

All strategies implement the AuthStrategy trait, which provides a single get_token method that returns a valid ServiceToken. Token caching and refresh are handled automatically.

§Strategies

StrategyUse caseCredentials
AutoStrategyRecommended default — detects credentials automaticallyCS_CLIENT_ACCESS_KEY + CS_WORKSPACE_CRN, or ~/.cipherstash/auth.json
AccessKeyStrategyService-to-service / CIStatic access key + workspace CRN
DeviceSessionStrategyLong-lived sessions with refreshOAuth token (from device code flow or disk)
DeviceCodeStrategyCLI login (RFC 8628)User authorizes in browser
StaticTokenStrategyTests only (test-utils feature)Pre-obtained token used as-is

§Quick start

For most applications, AutoStrategy is the simplest way to get started:

use stack_auth::AutoStrategy;

let strategy = AutoStrategy::detect()?;
// That's it — get_token() handles the rest.

For service-to-service authentication with an access key:

use stack_auth::AccessKeyStrategy;
use cts_common::Crn;

let crn: Crn = "crn:ap-southeast-2.aws:ZVATKW3VHMFG27DY".parse()?;
let key = "CSAKkeyId.keySecret".parse()?;
let strategy = AccessKeyStrategy::new(crn, key)?;

§Error handling

Every fallible operation returns AuthError, a structured enum in which each variant wraps a dedicated error struct. Errors are designed to tell the developer exactly what to do next:

  • Stable machine-readable codesAuthError::error_code returns a SCREAMING_CASE identifier (e.g. NOT_AUTHENTICATED, WORKSPACE_MISMATCH) suitable for logs, metrics, and programmatic handling. The same taxonomy crosses the FFI boundary: the @cipherstash/auth npm package surfaces these codes as the type discriminant of its typed AuthFailure union.
  • Actionable help — every variant implements miette::Diagnostic, so help() (and url() when present) carry remediation guidance, e.g. NOT_AUTHENTICATED says Log in with `stash login`, or set `CS_CLIENT_ACCESS_KEY` for service-to-service auth. Applications that render errors through miette (like the Stash CLI) show this automatically.
  • Structured payload — variants carry typed fields rather than pre-formatted strings; e.g. WorkspaceMismatch exposes expected_workspace and token_workspace so callers can act on the values, not parse a message.
use miette::Diagnostic;
use stack_auth::{AuthError, AutoStrategy};

fn report(err: &AuthError) {
    eprintln!("[{}] {err}", err.error_code());
    if let Some(help) = err.help() {
        eprintln!("  help: {help}");
    }
    if let Some(url) = err.url() {
        eprintln!("  more: {url}");
    }
    if let AuthError::WorkspaceMismatch(m) = err {
        eprintln!(
            "  token belongs to {}, strategy expects {}",
            m.token_workspace, m.expected_workspace
        );
    }
}

match AutoStrategy::detect() {
    Ok(_strategy) => { /* authenticated */ }
    Err(err) => report(&err),
}

§Extensibility

stack-auth exposes two layers that can be plugged independently:

            ┌──────────────────────────────────────────────────┐
            │  AuthStrategy ─ acquisition layer                │
            │  get_token() -> ServiceToken                     │
            │  AccessKeyStrategy / DeviceSessionStrategy / AutoStrategy│
            │  ── or ──                                        │
            │  AuthStrategyFn (closure → AuthStrategy)         │
            └────────────────────────┬─────────────────────────┘
                                     │ uses
            ┌────────────────────────▼─────────────────────────┐
            │  TokenStore ─ persistence layer                  │
            │  load() / save() of Token                        │
            │  InMemoryTokenStore / NoStore                    │
            │  ── or ──                                        │
            │  TokenStoreFn (closures → TokenStore)            │
            └──────────────────────────────────────────────────┘

Use TokenStoreFn when you want stack-auth’s own strategies to handle HTTP/refresh, but you need to plug in custom persistence (a cookie, a KV blob, Redis). Wire it via the strategy’s builder.

Use AuthStrategyFn when you want to bring your own token acquisition end-to-end — typically because the strategy lives across an FFI boundary (e.g. a JS getToken() reached via protect-ffi). The closure runs every time a token is needed.

Module paths mirror this split: stack_auth::auth groups the acquisition layer, stack_auth::store groups the persistence layer. All items are also re-exported at the crate root.

§Security

Sensitive values (SecretToken) are automatically zeroized when dropped and are masked in Debug output to prevent accidental leaks in logs.

§Token refresh

All strategies that cache tokens (AccessKeyStrategy, DeviceSessionStrategy, AutoStrategy) share the same internal refresh engine. See the AuthStrategy trait docs for a full description of the concurrency model and flow diagram.

Modules§

auth
Token acquisition — strategies that produce a ServiceToken.
store
Token persistence — pluggable backends for the service-token cache.

Structs§

AccessDenied
The user denied the authorization request.
AccessKey
A CipherStash access key.
AccessKeyStrategy
An AuthStrategy that uses a static access key to authenticate against a specific workspace.
AccessKeyStrategyBuilder
Builder for AccessKeyStrategy.
AlreadyConsumed
A consumable handle (e.g. a device-code poll) was used after it had already been consumed. A caller bug rather than an auth outcome, but surfaced as an AuthError so it flows through the Result contract rather than throwing across the FFI boundary.
AuthStrategyFn
AuthStrategy backed by a user-supplied async closure that returns a ServiceToken.
AutoStrategyBuilder
Builder for configuring credential resolution before calling detect().
DeviceCodeStrategy
Authenticates with CipherStash using the device code flow (RFC 8628).
DeviceCodeStrategyBuilder
Builder for DeviceCodeStrategy.
DeviceIdentity
Persistent identity for a CLI installation.
DeviceSessionStrategy
An AuthStrategy that renews a CTS session minted by an interactive OAuth login (the device-code flow), using its OAuth refresh token.
DeviceSessionStrategyBuilder
Builder for DeviceSessionStrategy.
InMemoryTokenStore
In-process token store. Useful for tests and as a shared cache across multiple strategy instances in the same process (e.g. a worker pool).
InternalError
An internal invariant was violated (e.g. a poisoned lock). Should not occur in correct usage; surfaced rather than panicking so it crosses the FFI boundary as a Result failure.
InvalidAccessKeyError
The access key string is malformed (e.g. missing CSAK prefix or .).
InvalidClient
The client ID is not recognized.
InvalidCrn
The workspace CRN could not be parsed.
InvalidGrant
The grant type was rejected by the server.
InvalidToken
The JWT could not be decoded or its claims are malformed.
InvalidUrl
A URL could not be parsed.
InvalidWorkspaceId
The workspace ID could not be parsed.
MissingWorkspaceCrn
An access key was provided but the workspace CRN is missing.
NoStore
Zero-sized default for AutoRefresh<R, S = NoStore>load returns None, save is a no-op. Carries no per-instance cost.
NotAuthenticated
No credentials are available (e.g. not logged in, no access key configured).
OidcFederationStrategy
An AuthStrategy that federates a third-party OIDC JWT (Clerk, Supabase, Auth0, …) into a CipherStash CTS service token via POST /api/authorise.
OidcFederationStrategyBuilder
Builder for OidcFederationStrategy.
OidcProviderFn
OidcProvider backed by a user-supplied async closure.
PendingDeviceCode
A device code flow that is waiting for the user to authorize.
RequestError
The HTTP request to the auth server failed (network error, timeout, etc.).
SecretToken
A sensitive token string that is zeroized on drop and hidden from debug output.
ServerError
An unexpected error was returned by the auth server.
ServiceToken
A CipherStash service token returned by an AuthStrategy.
StoreError
A token store operation failed.
Token
An access token returned by a successful authentication flow.
TokenExpired
A token (access token or device code) has expired.
TokenStoreFn
TokenStore backed by user-supplied load and save async closures.
UnsupportedRegion
The requested region is not supported.
WorkspaceMismatch
The token issued by the auth server is for a different workspace than the one configured on the strategy. Surfaces when the access key was minted for a different workspace, or when the wrong CRN was passed.

Enums§

AuthError
Errors that can occur during an authentication flow.
AutoStrategy
An AuthStrategy that automatically detects available credentials and delegates to the appropriate inner strategy.
DeviceClientError
Errors that can occur during device client provisioning.
InvalidAccessKey
Error returned when parsing an invalid access key string.

Traits§

AuthErrorKind
Behaviour shared by every concrete error wrapped in an AuthError variant.
AuthStrategy
A strategy for obtaining access tokens.
AuthStrategyBounds
Marker trait alias for the bounds an owned AuthStrategy-providing credential type C must satisfy when held inside a long-lived client (e.g. cipherstash_client::ZeroKMS<C> shared across requests).
OidcProvider
Asynchronously supplies the current third-party OIDC JWT to federate.
TokenStore
Pluggable persistent cache for service tokens.

Functions§

bind_client_device
Provision a device client after login.

Type Aliases§

OAuthStrategyDeprecated
Deprecated alias for DeviceSessionStrategy.
OAuthStrategyBuilderDeprecated
Deprecated alias for DeviceSessionStrategyBuilder.