use async_trait::async_trait;
use time::OffsetDateTime;
use crate::types::{Ppnum, PpnumId, SessionId};
#[async_trait]
pub trait BearerVerifier: Send + Sync {
async fn verify(&self, bearer_token: &str) -> Result<AuthSession, VerifyError>;
}
#[derive(Debug, Clone)]
pub struct Expectations {
pub issuer: String,
pub audience: String,
}
impl Expectations {
#[must_use]
pub fn new(issuer: impl Into<String>, audience: impl Into<String>) -> Self {
Self {
issuer: issuer.into(),
audience: audience.into(),
}
}
}
#[derive(Debug, Clone)]
pub struct AuthSession {
ppnum_id: PpnumId,
ppnum: Option<Ppnum>,
session_id: Option<SessionId>,
expires_at: OffsetDateTime,
}
impl AuthSession {
#[allow(dead_code)]
pub(crate) fn new(
ppnum_id: PpnumId,
ppnum: Option<Ppnum>,
session_id: Option<SessionId>,
expires_at: OffsetDateTime,
) -> Self {
Self {
ppnum_id,
ppnum,
session_id,
expires_at,
}
}
#[cfg(any(test, feature = "test-support"))]
#[must_use]
pub fn for_test(
ppnum_id: PpnumId,
ppnum: Option<Ppnum>,
session_id: Option<SessionId>,
expires_at: OffsetDateTime,
) -> Self {
Self::new(ppnum_id, ppnum, session_id, expires_at)
}
#[must_use]
pub fn ppnum_id(&self) -> &PpnumId {
&self.ppnum_id
}
#[must_use]
pub fn ppnum(&self) -> Option<&Ppnum> {
self.ppnum.as_ref()
}
#[must_use]
pub fn session_id(&self) -> Option<&SessionId> {
self.session_id.as_ref()
}
#[must_use]
pub fn expires_at(&self) -> OffsetDateTime {
self.expires_at
}
}
#[derive(Debug, Clone, thiserror::Error, PartialEq, Eq)]
pub enum VerifyError {
#[error("invalid bearer token format")]
InvalidFormat,
#[error("signature verification failed")]
SignatureInvalid,
#[error("token expired")]
Expired,
#[error("issuer invalid (M23)")]
IssuerInvalid,
#[error("audience invalid (M21/M22)")]
AudienceInvalid,
#[error("missing required claim: {0}")]
MissingClaim(&'static str),
#[error("keyset unavailable")]
KeysetUnavailable,
#[error("session_version stale (engine epoch port reject)")]
SessionVersionStale,
#[error("session_version lookup substrate unavailable")]
SessionVersionLookupUnavailable,
#[error("session revoked")]
SessionRevoked,
#[error("session liveness lookup substrate unavailable")]
SessionLivenessLookupUnavailable,
#[error("M73: id_token presented as Bearer — use access_token for resource access")]
IdTokenAsBearer,
#[error("verification failed: {0}")]
Other(String),
}