Skip to main content

toolkit_security/
authenticator.rs

1//! Transport-agnostic bearer-token authentication abstraction.
2//!
3//! [`BearerAuthenticator`] decouples the HTTP/gRPC transport layers from the
4//! concrete `AuthN` Resolver client. The transport only needs to hand a raw
5//! bearer token to an implementation and receive a reconstructed
6//! [`SecurityContext`] back. The concrete `AuthNResolverClient` adapter is
7//! injected at the gear/bootstrap layer so neither `toolkit-http` nor
8//! `toolkit-transport-grpc` need to depend on the full `ToolKit` framework.
9//!
10//! This lives in `toolkit-security` (not `toolkit-http`) so it stays
11//! transport-agnostic and reusable by the gRPC path — it returns
12//! [`SecurityContext`], which `toolkit-security` already owns, and
13//! `toolkit-security` has no dependency on any transport crate.
14
15use std::future::Future;
16
17use crate::context::SecurityContext;
18
19/// Neutral authentication error returned by a [`BearerAuthenticator`].
20///
21/// Intentionally coarse-grained and transport-agnostic: it never carries the
22/// token or any provider-specific detail so it is safe to surface at a trust
23/// boundary. Concrete adapters map their own error types into these variants.
24#[derive(Debug, thiserror::Error)]
25#[non_exhaustive]
26pub enum AuthNError {
27    /// The token was syntactically present but failed validation
28    /// (invalid signature, expired, malformed claims, etc.).
29    #[error("invalid or expired token")]
30    InvalidToken,
31    /// The authentication backend could not be reached or returned a
32    /// transient failure. Callers may choose to retry or surface a 503.
33    #[error("authentication backend unavailable")]
34    Unavailable,
35    /// Any other authentication failure. The message must not contain the
36    /// token or other sensitive material.
37    #[error("authentication failed: {0}")]
38    Other(String),
39}
40
41/// Re-validates a raw bearer token and reconstructs a [`SecurityContext`].
42///
43/// Implementations perform a full validation on every call — there is no
44/// trusted-peer fast path (zero-trust; see `cpt-cf-adr-two-plane-auth`). The transport layer
45/// stays generic over this trait; the concrete `AuthNResolverClient` adapter
46/// is supplied at the gear/bootstrap layer.
47///
48/// The returned future is `Send` so the trait can be used from Axum/Tower
49/// middleware running on a multi-threaded runtime.
50pub trait BearerAuthenticator: Send + Sync {
51    /// Validate `token` and reconstruct the corresponding [`SecurityContext`].
52    ///
53    /// # Errors
54    ///
55    /// Returns [`AuthNError`] if the token is invalid, the backend is
56    /// unavailable, or authentication otherwise fails.
57    fn authenticate(
58        &self,
59        token: &str,
60    ) -> impl Future<Output = Result<SecurityContext, AuthNError>> + Send;
61}