Expand description
§cheers-core — auth contract surface
Pure types and traits shared between cheers’s providers and downstream consumers (mesofact, yah-platform, …). No I/O, no platform code.
See the design doc at .yah/docs/working/cheers.md and the build plan at
.yah/docs/working/cheers-plan.md.
@yah:ticket(R019-F3, “SessionAuthority (origin) + EdgeVerifier (edge) facades + SessionPolicy TTL defaults + jti in Claims”) @yah:assignee(agent:claude) @yah:at(2026-05-26T17:52:52Z) @yah:status(review) @yah:parent(R019) @yah:next(“Add SessionAuthority { minter, refresh: RefreshStore, users: UserStore, revoke: RevocationWriter } (origin) and EdgeVerifier { verifier: TokenVerifier, revoked: RevocationReader } (edge). EdgeVerifier takes a TokenVerifier so it physically cannot mint.”) @yah:next(“Add SessionPolicy with sane TTL defaults (access ≈ minutes, refresh ≈ days) so consumers don’t pick the wrong durations.”) @yah:next(“Add a jti field to Claims (claims.rs, #[non_exhaustive] — additive) so the revocation set has a key.”) @yah:next(“Do AFTER the trait split (R019-F1), the asymmetric codec, and the revocation traits — it assembles all three into the two deployment-tier facades.”) @yah:verify(“cd external/cheers && cargo test -p cheers-core”) @yah:verify(“cd external/cheers && cargo check –workspace –all-features”) @yah:gotcha(“Claims (claims.rs) is the documented mesofact<->cheers contract and #[non_exhaustive]; adding jti is additive but coordinate with the R009/R011 mesofact resolver swap so the cookie format stays in sync.”) @arch:see(.yah/docs/working/edge-verifiable-auth.md) @yah:depends_on(R019-F1) @yah:depends_on(R019-F4) @yah:handoff(“Landed both facades in new session.rs (exported from lib.rs): SessionAuthority<M,R,U,W>{minter,refresh,users,revoke,policy} (origin) and EdgeVerifier<V,Rd>{verifier,revoked} (edge). Generic, not dyn, so the assembled capability set — and crucially the ABSENCE of a minter in EdgeVerifier — is a fact about the type, not a runtime convention. EdgeVerifier::new takes a TokenVerifier; there is no code path to mint.”) @yah:handoff(“SessionPolicy: access_ttl=15min, refresh_ttl=30d defaults + const DEFAULT_*_TTL_SECONDS + with_access_ttl/with_refresh_ttl builders. SessionAuthority methods: establish (mint access w/ fresh jti + mint_root refresh chain), rotate (RefreshRotator::rotate + fresh access, binding passed in since the refresh record doesn’t carry it), revoke_session(jti) -> RevocationWriter::revoke, revoke_device -> UserStore::revoke_device. EdgeVerifier::verify_at = signature-verify (gates the read) THEN is_revoked check -> Error::Revoked.”) @yah:handoff(“Depends on R019-F4 (RevocationReader/RevocationWriter) which I did first per maintainer ordering — it’s in review. jti landed under F4 (its revocation key); this ticket assembles it. Added Error::Refresh(#[from] RefreshError) + Error::Revoked variants (additive, #[non_exhaustive]).”) @yah:handoff(“Verified GREEN: cargo test -p cheers-core (51 unit incl. 6 session-facade tests covering establish/rotate/edge-accept-then-revoke/expired-before-revocation/policy-defaults/revoke_device, 9 proptest, 3 doctest) + cargo check –workspace –all-features. cargo doc has no new broken intra-doc links (the asymmetric/symmetric forward refs from F4 now resolve).”)
@yah:ticket(R019-F5, “Factor the no-crypto client surface (Claims + CredentialStore) so device targets do not compile the codec”)
@yah:assignee(agent:claude)
@yah:at(2026-05-27T06:02:55Z)
@yah:status(review)
@yah:parent(R019)
@yah:verify(“cd external/cheers && cargo tree -p server feature. –no-default-features yields the no-crypto client surface.”)
@yah:handoff(“Always-compiled (no-crypto) surface: claims (identity types), store traits (CredentialStore/UserStore/RefreshStore + records), revocation traits (RevocationReader/Writer), and the keyless codec traits TokenMinter/TokenVerifier/Codec + CodecError + Error/Result. A device crate can hold a dyn TokenVerifier without compiling a codec.”)
@yah:handoff(“Behind server: codec concrete impls (PasetoV4Codec, HmacBlobCodec, PasetoV4SecretMinter, PasetoV4PublicVerifier) + the pasetors From impl, the whole refresh and session modules, and error.rs’s Refresh(RefreshError) variant. codec_proptests.rs is #![cfg(feature=server)].”)
@yah:handoff(“Verified GREEN: cargo check -p cheers-core –no-default-features (crypto-free tree confirmed via cargo tree); cargo test -p cheers-core (default); cargo check –workspace + –all-features. cheers consumer needed no changes (depends on cheers-core default = server).”)
@yah:handoff(“For F6: the server/non-server feature boundary IS the target crate boundary. Promote the server-gated modules into cheers-verify (PublicVerifier+RevocationReader+EdgeVerifier) and cheers-server (SecretMinter+symmetric codecs+stores+SessionAuthority); the keyless traits stay in cheers-core so cheers-verify can name TokenVerifier.”)
@yah:relay(R020, “MCP auth and ownership — principal kinds, ownership table, mint paths, audit”) @yah:at(2026-06-04T01:34:48Z) @yah:status(open) @yah:next(“Resolve wire-envelope open question (PASETO v4.public vs JWT/Ed25519) in the -S1 spike before any mint-path ticket starts.”) @yah:next(“Land foundation tickets (principal kinds, scope vocab, ownership table) in cheers-core/cheers-server before mint paths.”) @yah:next(“Mint paths, admin endpoints, JWKS, audit can ship in parallel once the foundation is in.”) @yah:verify(“cargo test -p cheers-core && cargo test -p cheers-server && cargo test -p cheers-verify”) @yah:gotcha(“This relay PRODUCES the wire contract that yah’s kamaji consumes. Any wire-shape change here is a coordinated change with yah’s R426/R427/R428 — flag the yah-side relay in any handoff.”) @yah:gotcha(“ownership:write and audit:write are kind=service ONLY. The grant API must reject (principal_kind=user, scope=ownership:write|audit:write) at write time, not just at mint.”) @yah:assumes(“R019-F5/F6 crate split is effectively landed (in review) — MCP-token mint paths bolt onto cheers-server’s signer; cheers-verify verifies them unchanged.”) @yah:assumes(“yah-side consumer spec (W159) keeps the wire claim shapes verbatim with this doc (act, owns, camp_id, auth_strength).”) @arch:see(.yah/docs/working/mcp-auth-and-ownership.md) @arch:see(.yah/docs/working/edge-verifiable-auth.md) @yah:depends_on(R019-F6)
Re-exports§
pub use claims::Claims;pub use claims::Credential;pub use claims::DeviceBinding;pub use claims::DeviceId;pub use claims::User;pub use claims::UserId;pub use delegation::DelegationError;pub use delegation::UserDelegation;pub use codec::Codec;pub use codec::CodecError;pub use codec::TokenMinter;pub use codec::TokenVerifier;pub use error::Error;pub use error::RefreshError;pub use error::Result;pub use mcp::validate_grant;pub use mcp::Actor;pub use mcp::AuthStrength;pub use mcp::GrantError;pub use mcp::McpClaims;pub use mcp::Owns;pub use mcp::Scope;pub use mcp::ScopeParseError;pub use principal::Principal;pub use principal::PrincipalError;pub use principal::PrincipalId;pub use principal::PrincipalIdParseError;pub use principal::PrincipalKind;pub use principal::PrincipalStatus;pub use store::CredentialStore;pub use store::StoreError;
Modules§
- claims
- Identifiers, device bindings, and the
Claimscarried by a verified session token. - codec
- Session-token capability traits and the shared
CodecError. - delegation
UserDelegation— the user-signed authorization that lets cheers bind a camp principal to a user at provision time.- error
- Workspace-wide typed errors.
- mcp
- MCP wire contract — scope vocabulary, composition rules, and the
McpClaimsshape carried on a per-call token. - principal
- Principal kinds and identifier types for MCP authentication.
- store
- Client-side persistence contract —
CredentialStore+ the sharedStoreError.