Skip to main content

PasetoV4SecretMinter

Struct PasetoV4SecretMinter 

Source
pub struct PasetoV4SecretMinter { /* private fields */ }
Expand description

PASETO v4.public minter — signs claims with an Ed25519 secret key.

Origin-only: holding the secret key is minting power. Pair it with a PasetoV4PublicVerifier (the matching public key) at the edge. Because v4.public is signed but not encrypted, only mint non-secret claims this way — anyone holding the token can read them.

Implementations§

Source§

impl PasetoV4SecretMinter

Source

pub fn from_secret_key(bytes: &[u8; 64]) -> Result<Self, CodecError>

Build from a 64-byte Ed25519 secret key in PASETO’s seed || public_key layout (the V4 secret-key size). Rejects a key whose trailing public half doesn’t match the seed.

Source

pub fn generate() -> Result<(Self, PasetoV4PublicVerifier), CodecError>

Generate a fresh Ed25519 keypair, returning the origin minter and its matching edge PasetoV4PublicVerifier.

Source

pub fn verifier(&self) -> Result<PasetoV4PublicVerifier, CodecError>

Derive the matching public verifier — e.g. to publish the verify key to an edge while the secret never leaves the origin.

Source

pub fn secret_key_bytes(&self) -> &[u8] ⓘ

Raw bytes of the underlying PASETO V4 secret key — 64 bytes in the seed || public_key layout.

Origin-only, single-use affordance. The ServicePrincipalAuthority returns these bytes to a service-principal install flow exactly once at provision/rotate time (see .yah/docs/working/mcp-auth-and-ownership.md §Service principal bootstrap). Cheers’s own session signing key never reaches this accessor — it is constructed once at startup and never extracted — so leaking the cheers secret half is impossible by construction (the symmetric codecs don’t expose this affordance at all).

Source

pub fn mint_mcp( &self, claims: &McpClaims, kid: &str, ) -> Result<String, CodecError>

Sign an MCP-call token carrying McpClaims.

Wire convention (R592-B7) — the same envelope kamaji-bin’s verifier, cheers-mock, and yubaba’s mint_ownership_write_token already agree on (pinned byte-for-byte in cheers_test_support::fixtures): claims serializes directly as the token’s FLAT top-level JSON payload — no wrapping claim key, exp/ iat stay i64 Unix seconds — signed via pasetors’ LOW-LEVEL PublicToken::sign, never the high-level Claims wrapper (which hard-rejects non-string registered claims). kid rides in the PASETO footer as {"kid":"<kid>"}; the matching PasetoV4PublicVerifier::verify_mcp_at requires it.

The caller owns iat/exp (mirrors the session-claim path) — TTL policy for MCP tokens belongs upstream of this primitive. kid identifies which published key this mint used — same string a verifier’s JWKS/footer lookup keys off of.

Serializes via serde_json::Value rather than serializing claims directly: every reference wire producer (yubaba’s mint_ownership_write_token, cheers-mock’s MockIssuer::mint, cheers_test_support::fixtures::sign_fixture) builds its payload as a Value/json!{} map, whose default (non-preserve_order) BTreeMap-backed key order is alphabetical — NOT the struct’s field-declaration order #[derive(Serialize)] would emit. Routing through Value here reproduces that same alphabetical byte layout, which is what makes mint_mcp’s output byte-identical to the golden fixtures (verified in cheers-server/tests/golden_fixtures.rs). Deserialization is unaffected either way (JSON objects key-match by name), but the mint side has to match on the wire.

Trait Implementations§

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.