# delegated-redis operations guide
This guide covers production operation of [`RedisTrustState`](https://docs.rs/delegated-redis/latest/delegated_redis/struct.RedisTrustState.html),
the Redis adapter for [`delegated`](https://docs.rs/delegated) trust-state traits.
## Role in a deployment
`delegated` evaluates signed capabilities but does not persist mutable security
state. Every multi-instance verifier must share:
- atomic nonce consumption (replay protection)
- token revocation flags
- emergency agent-deny flags
`RedisTrustState` implements both [`TrustStateStore`](https://docs.rs/delegated/latest/delegated/trait.TrustStateStore.html)
and [`TrustStateAdmin`](https://docs.rs/delegated/latest/delegated/trait.TrustStateAdmin.html)
against a single Redis deployment reachable from all evaluators.
## Key layout
All keys use the configured prefix (default `delegated`):
| Nonce | `{prefix}:nonce:{issuer}:{nonce}` | `1` | `max(1s, token_expiry - now)` |
| Revocation | `{prefix}:revoked:{issuer}:{token_id}` | `1` | none |
| Emergency deny | `{prefix}:denied:{issuer}:{agent_id}` | `1` | none |
Examples with the default prefix:
```text
delegated:nonce:https://issuer.example:nonce-abc123
delegated:revoked:https://issuer.example:token-42
delegated:denied:https://issuer.example:agent:scheduler
```
Issuer, token, agent, and nonce strings are used verbatim. They must match the
identifiers present in evaluated tokens.
### Prefix selection
Use `RedisTrustState::with_prefix` when multiple services or environments share
one Redis cluster:
```rust
let state = RedisTrustState::with_prefix("redis://redis.internal:6379", "prod-calendar-api")?;
```
Choose one prefix per trust domain. Do not reuse prefixes across unrelated
authorization surfaces.
## Nonce semantics
Nonce consumption uses `SET key 1 NX EX ttl`:
- **Atomic:** concurrent evaluators receive at most one successful consumption.
- **TTL-bound:** keys expire automatically when the token would no longer be valid.
- **Fail-closed:** Redis errors propagate as `TrustStateError` and deny evaluation.
The evaluator calls `consume_nonce` only after signature verification, lifetime
checks, revocation checks, and operation binding succeed. Unauthorized requests
cannot burn a valid nonce.
### TTL cleanup
Nonce keys self-expire via Redis `EX`. No sweeper job is required for nonces.
If clocks drift between evaluators and issuers, rely on the evaluator's configured
clock leeway in the core crate; Redis TTL is derived from the host-supplied
`observed_at` and token `expires_at`.
## Revocation and deny lifecycle
Revocation and emergency-deny keys are written with unconditional `SET` and have
**no TTL**. They persist until an operator deletes the key or runs an explicit
cleanup procedure.
| `revoke_token(issuer, token_id)` | A specific capability must stop working immediately |
| `deny_agent(issuer, agent_id)` | An agent identity is compromised or suspended |
To clear a revocation or deny entry:
```bash
redis-cli DEL "delegated:revoked:https://issuer.example:token-42"
redis-cli DEL "delegated:denied:https://issuer.example:agent:scheduler"
```
Document your incident runbooks with the prefix and identifier conventions your
deployment uses.
## Connection URLs
`RedisTrustState` accepts standard Redis URLs understood by the `redis` crate:
```text
redis://127.0.0.1:6379
redis://:password@redis.internal:6379/0
rediss://user:password@redis.example:6380/0
```
### Standalone
Point every evaluator at the same logical database index. Use TLS (`rediss://`)
when traffic crosses untrusted networks.
### Sentinel
Use the Sentinel URL form supported by `redis` 0.27:
```text
redis+sentinel://sentinel-1:26379,sentinel-2:26379/mymaster/0
```
Verify failover behavior in staging: evaluators should reconnect through the
client and continue enforcing nonce atomicity against the promoted primary.
### Cluster
Cluster mode is supported when the URL targets a cluster-aware endpoint:
```text
redis://cluster-node:6379
```
All nonce, revocation, and deny keys for a given operation hash to the same slot
only when issuer and identifier strings collide across categories—they do not.
No multi-key transactions are required because each operation touches a single key.
Test concurrent evaluation from multiple application nodes against your cluster
topology before production cutover.
## Capacity and monitoring
Monitor:
- Redis command latency for `SET`, `EXISTS`, and connection errors
- Evaluator denials at stage `trust_state`
- Evaluator denials at stage `replay`
- Key count growth under the configured prefix
- Memory usage and eviction policy (avoid `allkeys-lru` for this use case)
Nonce volume scales with successful authorizations. Revocation/deny keys grow with
incident response activity and require manual or scripted cleanup.
## Failure behavior
Redis timeouts and connection failures return `TrustStateError`. The core
evaluator treats backend errors as **denial**. Do not bypass fail-closed
behavior during outages.
Recommended practices:
- Set client-side timeouts at the infrastructure layer
- Alert on sustained `trust_state` denials
- Run Redis with persistence appropriate to your recovery objectives (nonce loss
on full data loss can allow replay of otherwise valid tokens until expiry)
## Local development
The reference stack in `examples/reference-stack/` uses:
```bash
docker compose up -d
export REDIS_URL=redis://127.0.0.1:6379
```
Integration tests in this crate run against Redis when `REDIS_URL` is set.
## Related documentation
- [Integration guide (Redis section)](https://github.com/abendrothj/delegated/blob/main/docs/INTEGRATION.md#redis-trust-state-delegated-redis)
- [Core operations guide](https://github.com/abendrothj/delegated/blob/main/docs/OPERATIONS.md)
- [Threat model](https://github.com/abendrothj/delegated/blob/main/docs/THREAT_MODEL.md)