Skip to content

Add a stash-auth skill covering credentials, auth strategies, and lock context #794

Description

@coderdan

There is no skill covering how a client authenticates to CipherStash, and the guidance that does exist is scattered across skills that each mention one slice of it. The gap has already produced a wrong explanation in shipped material.

Evidence it is needed

wasm-inline.ts:665 and the stash-edge skill both state that identity-bound encryption on the edge is "configured via config.authStrategy instead" of .withLockContext(). That conflates two orthogonal mechanisms — authenticating as a user, and binding a data key to a claim. Nothing in the skill set explains the difference, so there was nowhere to check.

Auth also has the most moving parts of anything in the stack, and the deprecations are recent enough that older patterns are still findable in the wild.

Scope

  • The mental model first. Three separable concerns that keep getting merged:
    • Workspace credentials — which workspace, and the machine identity acting on it.
    • End-user identity — authenticating the client as a specific user.
    • Key binding.withLockContext({ identityClaim }), which changes key derivation. Requires the same claim on encrypt and decrypt.
  • The strategies. OidcFederationStrategy (end-user, via an IdP token — Clerk, Supabase Auth, …) and AccessKeyStrategy (service-to-service). Both are create()Result, which must be unwrapped before it reaches config.authStrategy; passing the Result itself is a known easy mistake that fails opaquely later.
  • Credential discovery vs explicit config. The native entry discovers from env / ~/.cipherstash; the WASM entry takes all four CS_* values explicitly, because neither a profile directory nor a device-code login exists in a Worker. Minting them with stash env.
  • The four CS_* variables — what each is, which are secret, and that CS_*_HOST variables are debug-only and should not appear in CI or examples.
  • Mutually exclusive options — an auth strategy and config.accessKey cannot both be set; the client rejects the combination.
  • Client lifetime. A user-scoped strategy means constructing a client per request. A module-level client binds whichever user arrived first — a cross-tenant data hazard, not a performance note.
  • What is deprecated and why. LockContext.identify() and getLockContext() (identity/index.ts:119, :185): per-operation CTS tokens were removed in protect-ffi 0.25, so the token identify() fetches is no longer consumed. Kept for compatibility, slated for removal in a future major. Anyone reading older code or docs will hit this.

Some skills currently refer to the below "credential-identity rule". However, it is not correct. A client key is associated with one or more keysets and always have a default keyset. If 2 distinct client keys are used to encrypt but do not both have the same default keyset or each specify different keysets that the other has not been granted access to, decryption will fail.

The credential-identity rule. EQL index terms derive from the ZeroKMS client key, so rows written under one credential and queried under another decrypt correctly and never match a query, silently. Currently repeated in stash-cli, stash-supabase, stash-edge, and stash-postgres — it belongs somewhere canonical, with those pointing at it.

  • Proxy. Authentication through CipherStash Proxy differs from the SDK path and is worth an explicit section rather than an omission.

Cross-references

Should become the canonical source those skills defer to, rather than each carrying a partial copy: stash-encryption (client construction), stash-edge (CS_* on the edge, and the lock-context correction tracked separately), stash-cli (stash env, auth login), stash-supabase, stash-postgres.

Note

Agents must never read ~/.cipherstash (secretkey.json, auth.json, JWTs) directly — the CLI owns that. The skill should say so explicitly, since a skill about authentication is exactly where an agent would otherwise think to look.

Lock Context

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions