use async_trait::async_trait;
use better_auth_core::{
AuthConfig, AuthContext, AuthRequest, AuthResult, AuthSchema, FieldValue, RuntimeExtensions,
plugin::MetadataMap,
store::{ApiKeyStore, MemberStore, OrganizationStore},
};
use std::collections::HashMap;
pub type ApiKeyPermissions = HashMap<String, Vec<String>>;
#[derive(Clone, Copy)]
pub struct ApiKeyEndpoint<'a> {
pub request: Option<&'a AuthRequest>,
pub headers: Option<&'a HashMap<String, String>>,
pub path: Option<&'a str>,
pub body: &'a FieldValue,
pub auth_config: &'a AuthConfig,
pub extensions: &'a RuntimeExtensions,
pub metadata: &'a MetadataMap,
pub api_keys: &'a dyn ApiKeyStore,
pub organizations: &'a dyn OrganizationStore,
pub members: &'a dyn MemberStore,
}
impl<'a> ApiKeyEndpoint<'a> {
pub(super) fn from_request<S: AuthSchema>(
ctx: &'a AuthContext<S>,
request: &'a AuthRequest,
body: &'a FieldValue,
) -> Self {
let original = request.original_request().or_else(|| {
better_auth_core::hooks::current_request_hook_context()
.is_some_and(|context| context.is_http)
.then_some(request)
});
Self {
headers: request.endpoint_headers(),
..Self::new(ctx, original, Some(request.path()), body)
}
}
pub(super) fn new<S: AuthSchema>(
ctx: &'a AuthContext<S>,
request: Option<&'a AuthRequest>,
path: Option<&'a str>,
body: &'a FieldValue,
) -> Self {
Self {
request,
headers: request.map(|request| &request.headers),
path,
body,
auth_config: &ctx.config,
extensions: &ctx.extensions,
metadata: &ctx.metadata,
api_keys: ctx.database.as_ref(),
organizations: ctx.database.as_ref(),
members: ctx.database.as_ref(),
}
}
}
#[async_trait]
pub trait ApiKeyGenerator: Send + Sync {
async fn generate(&self, length: usize, prefix: Option<&str>) -> AuthResult<String>;
}
pub trait ApiKeyGetter: Send + Sync {
fn get(&self, ctx: ApiKeyEndpoint<'_>) -> AuthResult<Option<String>>;
}
#[async_trait]
pub trait ApiKeyValidator: Send + Sync {
async fn validate(&self, key: &str, ctx: ApiKeyEndpoint<'_>) -> AuthResult<bool>;
}
#[async_trait]
pub trait ApiKeyDefaultPermissions: Send + Sync {
async fn permissions(
&self,
reference_id: &better_auth_core::FieldValue,
ctx: ApiKeyEndpoint<'_>,
) -> AuthResult<ApiKeyPermissions>;
}