# stack-auth
[](https://crates.io/crates/stack-auth)
[](https://docs.rs/stack-auth/)
[](https://cipherstash.com)
Authentication strategies for [CipherStash](https://cipherstash.com) services.
All strategies implement the [`AuthStrategy`] trait, which provides a single
[`get_token`](AuthStrategy::get_token) method that returns a valid
[`ServiceToken`]. Token caching and refresh are handled automatically.
## Strategies
| [`AutoStrategy`] | Recommended default — detects credentials automatically | `CS_CLIENT_ACCESS_KEY` + `CS_WORKSPACE_CRN`, or `~/.cipherstash/auth.json` |
| [`AccessKeyStrategy`] | Service-to-service / CI | Static access key + region |
| [`OAuthStrategy`] | Long-lived sessions with refresh | OAuth token (from device code flow or disk) |
| [`DeviceCodeStrategy`] | CLI login ([RFC 8628](https://datatracker.ietf.org/doc/html/rfc8628)) | User authorizes in browser |
| `StaticTokenStrategy` | Tests only (`test-utils` feature) | Pre-obtained token used as-is |
## Quick start
For most applications, [`AutoStrategy`] is the simplest way to get started:
```no_run
use stack_auth::AutoStrategy;
# async fn run() -> Result<(), Box<dyn std::error::Error>> {
let strategy = AutoStrategy::detect()?;
// That's it — get_token() handles the rest.
# Ok(())
# }
```
For service-to-service authentication with an access key:
```no_run
use stack_auth::AccessKeyStrategy;
use cts_common::Region;
# fn run() -> Result<(), Box<dyn std::error::Error>> {
let region = Region::aws("ap-southeast-2")?;
let key = "CSAKkeyId.keySecret".parse()?;
let strategy = AccessKeyStrategy::new(region, key)?;
# Ok(())
# }
```
## Extensibility
`stack-auth` exposes two layers that can be plugged independently:
```text
┌──────────────────────────────────────────────────┐
│ AuthStrategy ─ acquisition layer │
│ get_token() -> ServiceToken │
│ AccessKeyStrategy / OAuthStrategy / 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`](crate::auth) groups the
acquisition layer, [`stack_auth::store`](crate::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`](std::fmt::Debug) output to prevent accidental
leaks in logs.
## Token refresh
All strategies that cache tokens ([`AccessKeyStrategy`], [`OAuthStrategy`],
[`AutoStrategy`]) share the same internal refresh engine. See the
[`AuthStrategy`] trait docs for a full description of the concurrency model
and flow diagram.