Skip to main content

alibi_plugins/api_key/
callbacks.rs

1use alibi_core::{AuthConfig, AuthContext, AuthRequest, AuthResult, AuthSchema, ContextExtensions};
2use async_trait::async_trait;
3
4/// Immutable application context for trusted API-key lookup and validation.
5///
6/// HTTP authentication supplies the actual request. Programmatic verification
7/// supplies no request unless using `verify_api_key_with_request`. Applications
8/// may capture their own typed store or service in the callback implementation.
9pub struct ApiKeyCallbackContext<'a> {
10    pub request: Option<&'a AuthRequest>,
11    /// Genuine logical context when verification is dispatched as a registered endpoint.
12    /// It never manufactures a physical request for virtual calls.
13    pub endpoint: Option<alibi_core::endpoint::EndpointCall>,
14    pub auth_config: &'a AuthConfig,
15    pub extensions: &'a ContextExtensions,
16    pub configuration_id: &'a str,
17    /// Original trusted verification input, including the requested scope and
18    /// permissions. HTTP authentication callbacks have no server-only input.
19    pub verification_input: Option<&'a super::VerifyApiKey<'a>>,
20}
21
22impl std::fmt::Debug for ApiKeyCallbackContext<'_> {
23    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
24        f.debug_struct("ApiKeyCallbackContext")
25            .finish_non_exhaustive()
26    }
27}
28
29impl<'a> ApiKeyCallbackContext<'a> {
30    pub(super) fn with_endpoint(mut self, endpoint: &alibi_core::endpoint::EndpointCall) -> Self {
31        self.endpoint = Some(endpoint.clone());
32        self
33    }
34    #[must_use]
35    pub(super) fn new(
36        request: Option<&'a AuthRequest>,
37        ctx: &'a AuthContext<impl AuthSchema>,
38        configuration_id: &'a str,
39    ) -> Self {
40        Self {
41            request,
42            endpoint: alibi_core::endpoint::current_endpoint_call_context(),
43            auth_config: &ctx.config,
44            extensions: &ctx.extensions,
45            configuration_id,
46            verification_input: None,
47        }
48    }
49
50    #[must_use]
51    pub(super) const fn with_verification_input(
52        mut self,
53        input: &'a super::VerifyApiKey<'a>,
54    ) -> Self {
55        self.verification_input = Some(input);
56        self
57    }
58}
59
60/// Application lookup replaces configured API-key headers entirely.
61///
62/// `None` or an empty string leaves normal session authentication in control.
63/// A matching getter is called again when the authentication hook executes,
64/// following upstream's matcher/handler ordering.
65/// Errors during matching become the hook matcher's public 500 response;
66/// errors from the subsequent handler preserve the application API error.
67pub trait ApiKeyGetter: Send + Sync {
68    /// Look up the actual request's credential.
69    ///
70    /// # Errors
71    /// Returns an application failure from credential lookup.
72    fn get_key(&self, context: &ApiKeyCallbackContext<'_>) -> AuthResult<Option<String>>;
73}
74
75/// Trusted acceptance predicate, evaluated before key usage is consumed.
76///
77/// Explicitly scoped programmatic verification evaluates it before lookup;
78/// unscoped verification first resolves the persisted issuing configuration.
79/// A scoped callback error is returned directly. Unscoped verification catches
80/// it in the same validation phase as stored key errors.
81#[async_trait]
82pub trait ApiKeyValidator: Send + Sync {
83    /// Accept or reject a credential before consuming its usage.
84    ///
85    /// # Errors
86    /// Returns an application failure from credential validation.
87    async fn validate(&self, context: &ApiKeyCallbackContext<'_>, key: &str) -> AuthResult<bool>;
88}
89
90/// Ordered resource/action permissions, following JavaScript object insertion order.
91pub type ApiKeyPermissions = indexmap::IndexMap<String, Vec<String>>;
92
93/// Inputs passed to an application key generator; length excludes the prefix.
94pub struct ApiKeyGenerationOptions<'a> {
95    /// Raw configured number after zero/NaN fallback; custom generators own
96    /// fractional and nonfinite values without an integer coercion.
97    pub length: f64,
98    pub prefix: Option<&'a str>,
99}
100
101impl std::fmt::Debug for ApiKeyGenerationOptions<'_> {
102    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
103        f.debug_struct("ApiKeyGenerationOptions")
104            .finish_non_exhaustive()
105    }
106}
107
108/// Trusted custom secret generation. The application owns the returned full key.
109#[async_trait]
110pub trait ApiKeyGenerator: Send + Sync {
111    async fn generate_key(&self, options: &ApiKeyGenerationOptions<'_>) -> AuthResult<String>;
112}
113
114/// Trusted dynamic defaults, evaluated even when creation supplies an override.
115#[async_trait]
116pub trait ApiKeyDefaultPermissions: Send + Sync {
117    async fn default_permissions(
118        &self,
119        reference_id: &str,
120        context: &ApiKeyCallbackContext<'_>,
121    ) -> AuthResult<ApiKeyPermissions>;
122}