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}