uselesskey-token 0.8.0

API key, bearer, and OAuth access-token fixture generator for tests.
Documentation
//! Stable token fixture specification.
//!
//! Defines [`TokenSpec`], the enum of supported token shapes (API key,
//! bearer, OAuth/JWT-shape) used by `uselesskey-token` and its compatibility
//! shims.

/// Specification for token fixture generation.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub enum TokenSpec {
    /// API key style token (e.g. `uk_test_<base62>`).
    ApiKey,
    /// Opaque bearer token (base64url body).
    Bearer,
    /// OAuth access token in JWT shape (`header.payload.signature`).
    OAuthAccessToken,
}

impl TokenSpec {
    /// Create an API-key spec (`uk_test_<base62>`).
    pub const fn api_key() -> Self {
        Self::ApiKey
    }

    /// Create an opaque bearer-token spec (base64url body).
    pub const fn bearer() -> Self {
        Self::Bearer
    }

    /// Create an OAuth access-token spec in JWT shape (`header.payload.signature`).
    pub const fn oauth_access_token() -> Self {
        Self::OAuthAccessToken
    }

    /// Return a short, stable name for this token kind (e.g. `"api_key"`).
    pub const fn kind_name(&self) -> &'static str {
        match self {
            Self::ApiKey => "api_key",
            Self::Bearer => "bearer",
            Self::OAuthAccessToken => "oauth_access_token",
        }
    }

    /// Stable encoding for cache keys / deterministic derivation.
    ///
    /// If you change this, bump the derivation version in `uselesskey-core`.
    pub const fn stable_bytes(&self) -> [u8; 4] {
        match self {
            Self::ApiKey => [0, 0, 0, 1],
            Self::Bearer => [0, 0, 0, 2],
            Self::OAuthAccessToken => [0, 0, 0, 3],
        }
    }

    /// HTTP authorization scheme associated with this token shape.
    pub const fn authorization_scheme(&self) -> &'static str {
        match self {
            Self::ApiKey => "ApiKey",
            Self::Bearer | Self::OAuthAccessToken => "Bearer",
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn stable_bytes_are_unique() {
        let api = TokenSpec::api_key().stable_bytes();
        let bearer = TokenSpec::bearer().stable_bytes();
        let oauth = TokenSpec::oauth_access_token().stable_bytes();

        assert_ne!(api, bearer);
        assert_ne!(api, oauth);
        assert_ne!(bearer, oauth);
    }

    #[test]
    fn kind_names_are_stable() {
        assert_eq!(TokenSpec::api_key().kind_name(), "api_key");
        assert_eq!(TokenSpec::bearer().kind_name(), "bearer");
        assert_eq!(
            TokenSpec::oauth_access_token().kind_name(),
            "oauth_access_token"
        );
    }

    #[test]
    fn authorization_schemes_are_stable() {
        assert_eq!(TokenSpec::api_key().authorization_scheme(), "ApiKey");
        assert_eq!(TokenSpec::bearer().authorization_scheme(), "Bearer");
        assert_eq!(
            TokenSpec::oauth_access_token().authorization_scheme(),
            "Bearer"
        );
    }
}