grafbase_sdk/extension/
authentication.rs

1use crate::{
2    types::{Configuration, Directive, ErrorResponse, Token},
3    wit::Headers,
4    Error,
5};
6
7use super::Extension;
8
9type InitFn = Box<dyn Fn(Vec<Directive>, Configuration) -> Result<Box<dyn Authenticator>, Box<dyn std::error::Error>>>;
10
11pub(super) static mut EXTENSION: Option<Box<dyn Authenticator>> = None;
12pub static mut INIT_FN: Option<InitFn> = None;
13
14pub(super) fn get_extension() -> Result<&'static mut dyn Authenticator, Error> {
15    // Safety: This is hidden, only called by us. Every extension call to an instance happens
16    // in a single-threaded environment. Do not call this multiple times from different threads.
17    unsafe {
18        EXTENSION.as_deref_mut().ok_or_else(|| Error {
19            message: "Resolver extension not initialized correctly.".to_string(),
20            extensions: Vec::new(),
21        })
22    }
23}
24
25/// Initializes the resolver extension with the provided directives using the closure
26/// function created with the `register_extension!` macro.
27pub(super) fn init(directives: Vec<Directive>, configuration: Configuration) -> Result<(), Box<dyn std::error::Error>> {
28    // Safety: This function is only called from the SDK macro, so we can assume that there is only one caller at a time.
29    unsafe {
30        let init = INIT_FN.as_ref().expect("Resolver extension not initialized correctly.");
31        EXTENSION = Some(init(directives, configuration)?);
32    }
33
34    Ok(())
35}
36
37/// This function gets called when the extension is registered in the user code with the `register_extension!` macro.
38///
39/// This should never be called manually by the user.
40#[doc(hidden)]
41pub fn register(f: InitFn) {
42    // Safety: This function is only called from the SDK macro, so we can assume that there is only one caller at a time.
43    unsafe {
44        INIT_FN = Some(f);
45    }
46}
47
48/// A trait that extends `Extension` and provides authentication functionality.
49pub trait Authenticator: Extension {
50    /// Authenticates the request using the provided headers.
51    ///
52    /// # Arguments
53    /// * `headers` - The request headers to authenticate with.
54    ///
55    /// # Returns
56    /// * `Ok(Token)` - A valid authentication token if successful.
57    /// * `Err(ErrorResponse)` - An error response if authentication fails.
58    fn authenticate(&mut self, headers: Headers) -> Result<Token, ErrorResponse>;
59}