ppoppo-token 0.3.0

JWT (RFC 9068, EdDSA) issuance + verification engine for the Ppoppo ecosystem. Single deep module with a small interface (issue, verify) hiding RFC 8725 mitigations M01-M45, JWKS handling, and substrate ports (epoch, session, replay).
Documentation
//! Sealed JWS signature algorithm whitelist (Phase 7 §6.8 — structural M51/M52/M54).
//!
//! Shared by both token profiles (RFC 9068 access tokens, OIDC Core 1.0 id
//! tokens) — the algorithm vocabulary is JOSE-level, not profile-level.
//! Living at the crate root so neither `access_token::*` nor `id_token::*`
//! can claim ownership.
//!
//! Only `EdDSA` exists. Consumer attempts to construct `Algorithm::HS256`
//! or any other variant fail at compile time (`variant not found`),
//! making M51/M52/M54 enforcement structural rather than lint-based.
//! `jsonwebtoken::Algorithm` is no longer re-exported — `crates/shared/ppoppo-token`
//! owns the algorithm vocabulary.
//!
//! Adding a new variant is a deliberate spec change — the matrix M02/M06
//! rows must be revisited and the negative regression in
//! `tests/jwt_negative.rs` reinstated to cover the cfg-vs-header SSOT
//! invariant.

#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Algorithm {
    /// EdDSA over Ed25519 — RFC 9068 access-token profile and (post-Phase
    /// 10.1) OIDC Core 1.0 id-token profile.
    EdDSA,
}

impl std::str::FromStr for Algorithm {
    type Err = ();

    /// Parse the `alg` header field. Anything other than `"EdDSA"` is
    /// rejected — family-level rejections (HS/RS/ES) fire earlier in
    /// `check_algorithm::run` to give audit logs the family signal.
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        match s {
            "EdDSA" => Ok(Algorithm::EdDSA),
            _ => Err(()),
        }
    }
}