Skip to main content

authn_resolver/
module.rs

1//! `AuthN` resolver module.
2
3use std::sync::{Arc, OnceLock};
4
5use async_trait::async_trait;
6use authn_resolver_sdk::{AuthNResolverClient, AuthNResolverPluginSpecV1};
7use modkit::Module;
8use modkit::context::ModuleCtx;
9use tracing::info;
10use types_registry_sdk::{RegisterResult, TypesRegistryClient};
11
12use crate::config::AuthNResolverConfig;
13use crate::domain::{AuthNResolverLocalClient, Service};
14
15/// `AuthN` Resolver module.
16///
17/// This module:
18/// 1. Registers the plugin schema in types-registry
19/// 2. Discovers plugin instances via types-registry
20/// 3. Routes requests to the selected plugin based on vendor configuration
21///
22/// Plugin discovery is lazy: happens on first API call after types-registry
23/// is ready.
24#[modkit::module(
25    name = "authn-resolver",
26    deps = ["types-registry"],
27    capabilities = []
28)]
29pub(crate) struct AuthNResolver {
30    service: OnceLock<Arc<Service>>,
31}
32
33impl Default for AuthNResolver {
34    fn default() -> Self {
35        Self {
36            service: OnceLock::new(),
37        }
38    }
39}
40
41#[async_trait]
42impl Module for AuthNResolver {
43    #[tracing::instrument(skip_all, fields(vendor))]
44    async fn init(&self, ctx: &ModuleCtx) -> anyhow::Result<()> {
45        let cfg: AuthNResolverConfig = ctx.config()?;
46        tracing::Span::current().record("vendor", cfg.vendor.as_str());
47        info!(vendor = %cfg.vendor, "Initializing authn_resolver");
48
49        // Register plugin schema in types-registry
50        let registry = ctx.client_hub().get::<dyn TypesRegistryClient>()?;
51        let schema_str = AuthNResolverPluginSpecV1::gts_schema_with_refs_as_string();
52        let schema_json: serde_json::Value = serde_json::from_str(&schema_str)?;
53        let results = registry.register(vec![schema_json]).await?;
54        RegisterResult::ensure_all_ok(&results)?;
55        info!(
56            schema_id = %AuthNResolverPluginSpecV1::gts_schema_id(),
57            "Registered plugin schema in types-registry"
58        );
59
60        // Create service
61        let hub = ctx.client_hub();
62        let svc = Arc::new(Service::new(hub, cfg.vendor));
63
64        // Register client in ClientHub
65        let api: Arc<dyn AuthNResolverClient> =
66            Arc::new(AuthNResolverLocalClient::new(svc.clone()));
67        ctx.client_hub().register::<dyn AuthNResolverClient>(api);
68
69        self.service
70            .set(svc)
71            .map_err(|_| anyhow::anyhow!("Service already initialized"))?;
72
73        Ok(())
74    }
75}