better_auth_api/plugins/api_key/
callbacks.rs1use async_trait::async_trait;
2use better_auth_core::{
3 AuthConfig, AuthContext, AuthError, AuthRequest, AuthResponse, AuthResult, AuthSchema,
4 RuntimeExtensions,
5 plugin::MetadataMap,
6 store::{ApiKeyStore, MemberStore, OrganizationStore},
7};
8use serde_json::Value;
9use std::collections::HashMap;
10
11pub type ApiKeyPermissions = HashMap<String, Vec<String>>;
13
14#[derive(Clone, Copy)]
16pub struct ApiKeyEndpoint<'a> {
17 pub request: Option<&'a AuthRequest>,
19 pub path: Option<&'a str>,
21 pub body: &'a Value,
23 pub auth_config: &'a AuthConfig,
25 pub extensions: &'a RuntimeExtensions,
27 pub metadata: &'a MetadataMap,
29 pub api_keys: &'a dyn ApiKeyStore,
31 pub organizations: &'a dyn OrganizationStore,
33 pub members: &'a dyn MemberStore,
35}
36
37impl<'a> ApiKeyEndpoint<'a> {
38 pub(super) fn new<S: AuthSchema>(
39 ctx: &'a AuthContext<S>,
40 request: Option<&'a AuthRequest>,
41 path: Option<&'a str>,
42 body: &'a Value,
43 ) -> Self {
44 Self {
45 request,
46 path,
47 body,
48 auth_config: &ctx.config,
49 extensions: &ctx.extensions,
50 metadata: &ctx.metadata,
51 api_keys: ctx.database.as_ref(),
52 organizations: ctx.database.as_ref(),
53 members: ctx.database.as_ref(),
54 }
55 }
56}
57
58#[async_trait]
60pub trait ApiKeyGenerator: Send + Sync {
61 async fn generate(&self, length: usize, prefix: Option<&str>) -> AuthResult<String>;
62}
63
64pub trait ApiKeyGetter: Send + Sync {
66 fn get(&self, ctx: ApiKeyEndpoint<'_>) -> AuthResult<Option<String>>;
67}
68
69#[async_trait]
71pub trait ApiKeyValidator: Send + Sync {
72 async fn validate(&self, key: &str, ctx: ApiKeyEndpoint<'_>) -> AuthResult<bool>;
73}
74
75#[async_trait]
77pub trait ApiKeyDefaultPermissions: Send + Sync {
78 async fn permissions(
79 &self,
80 reference_id: &str,
81 ctx: ApiKeyEndpoint<'_>,
82 ) -> AuthResult<ApiKeyPermissions>;
83}
84
85pub(super) fn callback_error(error: AuthError, request: Option<&AuthRequest>) -> AuthError {
87 if request.is_some()
88 && error.status_code() == 500
89 && !matches!(error, AuthError::Response(_) | AuthError::Upstream { .. })
90 {
91 better_auth_core::observability::logger::current().error(
92 "API key callback failed",
93 &[better_auth_core::observability::LogArgument::Error(&error)],
94 );
95 AuthResponse::new(500).into()
96 } else {
97 error
98 }
99}