pub struct AuthDispatcher { /* private fields */ }Expand description
Central dispatcher for JWT and opaque token validation
Orchestrates key providers and claims plugins to validate tokens using a single configured plugin.
Implementations§
Source§impl AuthDispatcher
impl AuthDispatcher
Sourcepub fn new(
validation_config: ValidationConfig,
config: &AuthConfig,
registry: &PluginRegistry,
) -> Result<Self, ConfigError>
pub fn new( validation_config: ValidationConfig, config: &AuthConfig, registry: &PluginRegistry, ) -> Result<Self, ConfigError>
Create a new dispatcher with validation config and plugin.
§Errors
Returns ConfigError::UnknownPlugin if the configured provider is not in the registry.
Examples found in repository?
127async fn main() -> Result<(), Box<dyn std::error::Error>> {
128 let mut plugins = PluginRegistry::default();
129 plugins.register("demo", Arc::new(DemoClaimsPlugin));
130
131 let mut plugin_configs = HashMap::new();
132 plugin_configs.insert(
133 "demo".to_owned(),
134 PluginConfig::Oidc {
135 tenant_claim: "tenants".to_owned(),
136 roles_claim: "roles".to_owned(),
137 },
138 );
139
140 let config = AuthConfig {
141 mode: AuthModeConfig {
142 provider: "demo".to_owned(),
143 },
144 issuers: vec!["https://issuer.local".to_owned()],
145 audiences: vec!["demo-api".to_owned()],
146 plugins: plugin_configs,
147 ..AuthConfig::default()
148 };
149
150 let validation = ValidationConfig {
151 allowed_issuers: config.issuers.clone(),
152 allowed_audiences: config.audiences.clone(),
153 leeway_seconds: config.leeway_seconds,
154 require_uuid_subject: true,
155 require_uuid_tenants: true,
156 };
157
158 let subject = Uuid::new_v4();
159 let tenant = Uuid::new_v4();
160 let expires_at = OffsetDateTime::now_utc() + Duration::minutes(15);
161
162 let raw_claims = serde_json::json!({
163 "iss": "https://issuer.local",
164 "sub": subject.to_string(),
165 "aud": ["demo-api"],
166 "exp": expires_at.unix_timestamp(),
167 "tenant_id": tenant.to_string(),
168 "roles": ["viewer:read"]
169 });
170
171 let dispatcher = AuthDispatcher::new(validation, &config, &plugins)?
172 .with_key_provider(Arc::new(StaticKeyProvider::new(raw_claims)));
173
174 let claims = dispatcher.validate_jwt("demo-token").await?;
175 let perm_list = if claims.permissions.is_empty() {
176 "none".to_owned()
177 } else {
178 claims
179 .permissions
180 .iter()
181 .map(|p| format!("{}:{}", p.resource_pattern(), p.action()))
182 .collect::<Vec<_>>()
183 .join(", ")
184 };
185 println!(
186 "Validated token for subject {} with permissions {}",
187 claims.subject, perm_list
188 );
189
190 Ok(())
191}Sourcepub fn with_key_provider(self, provider: Arc<dyn KeyProvider>) -> Self
pub fn with_key_provider(self, provider: Arc<dyn KeyProvider>) -> Self
Add a key provider
Examples found in repository?
127async fn main() -> Result<(), Box<dyn std::error::Error>> {
128 let mut plugins = PluginRegistry::default();
129 plugins.register("demo", Arc::new(DemoClaimsPlugin));
130
131 let mut plugin_configs = HashMap::new();
132 plugin_configs.insert(
133 "demo".to_owned(),
134 PluginConfig::Oidc {
135 tenant_claim: "tenants".to_owned(),
136 roles_claim: "roles".to_owned(),
137 },
138 );
139
140 let config = AuthConfig {
141 mode: AuthModeConfig {
142 provider: "demo".to_owned(),
143 },
144 issuers: vec!["https://issuer.local".to_owned()],
145 audiences: vec!["demo-api".to_owned()],
146 plugins: plugin_configs,
147 ..AuthConfig::default()
148 };
149
150 let validation = ValidationConfig {
151 allowed_issuers: config.issuers.clone(),
152 allowed_audiences: config.audiences.clone(),
153 leeway_seconds: config.leeway_seconds,
154 require_uuid_subject: true,
155 require_uuid_tenants: true,
156 };
157
158 let subject = Uuid::new_v4();
159 let tenant = Uuid::new_v4();
160 let expires_at = OffsetDateTime::now_utc() + Duration::minutes(15);
161
162 let raw_claims = serde_json::json!({
163 "iss": "https://issuer.local",
164 "sub": subject.to_string(),
165 "aud": ["demo-api"],
166 "exp": expires_at.unix_timestamp(),
167 "tenant_id": tenant.to_string(),
168 "roles": ["viewer:read"]
169 });
170
171 let dispatcher = AuthDispatcher::new(validation, &config, &plugins)?
172 .with_key_provider(Arc::new(StaticKeyProvider::new(raw_claims)));
173
174 let claims = dispatcher.validate_jwt("demo-token").await?;
175 let perm_list = if claims.permissions.is_empty() {
176 "none".to_owned()
177 } else {
178 claims
179 .permissions
180 .iter()
181 .map(|p| format!("{}:{}", p.resource_pattern(), p.action()))
182 .collect::<Vec<_>>()
183 .join(", ")
184 };
185 println!(
186 "Validated token for subject {} with permissions {}",
187 claims.subject, perm_list
188 );
189
190 Ok(())
191}Sourcepub fn with_introspection_provider(
self,
provider: Arc<dyn IntrospectionProvider>,
) -> Self
pub fn with_introspection_provider( self, provider: Arc<dyn IntrospectionProvider>, ) -> Self
Add an introspection provider
Sourcepub async fn validate_jwt(&self, token: &str) -> Result<Claims, ClaimsError>
pub async fn validate_jwt(&self, token: &str) -> Result<Claims, ClaimsError>
Validate a JWT token.
Workflow:
- Try each
KeyProvideruntil one successfully validates the signature - Extract issuer from token
- Use the configured plugin to normalize claims
- Run common validation (issuer, audience, exp, nbf, UUIDs)
- Return normalized claims
§Errors
Returns ClaimsError if signature validation, claim normalization, or validation fails.
Examples found in repository?
127async fn main() -> Result<(), Box<dyn std::error::Error>> {
128 let mut plugins = PluginRegistry::default();
129 plugins.register("demo", Arc::new(DemoClaimsPlugin));
130
131 let mut plugin_configs = HashMap::new();
132 plugin_configs.insert(
133 "demo".to_owned(),
134 PluginConfig::Oidc {
135 tenant_claim: "tenants".to_owned(),
136 roles_claim: "roles".to_owned(),
137 },
138 );
139
140 let config = AuthConfig {
141 mode: AuthModeConfig {
142 provider: "demo".to_owned(),
143 },
144 issuers: vec!["https://issuer.local".to_owned()],
145 audiences: vec!["demo-api".to_owned()],
146 plugins: plugin_configs,
147 ..AuthConfig::default()
148 };
149
150 let validation = ValidationConfig {
151 allowed_issuers: config.issuers.clone(),
152 allowed_audiences: config.audiences.clone(),
153 leeway_seconds: config.leeway_seconds,
154 require_uuid_subject: true,
155 require_uuid_tenants: true,
156 };
157
158 let subject = Uuid::new_v4();
159 let tenant = Uuid::new_v4();
160 let expires_at = OffsetDateTime::now_utc() + Duration::minutes(15);
161
162 let raw_claims = serde_json::json!({
163 "iss": "https://issuer.local",
164 "sub": subject.to_string(),
165 "aud": ["demo-api"],
166 "exp": expires_at.unix_timestamp(),
167 "tenant_id": tenant.to_string(),
168 "roles": ["viewer:read"]
169 });
170
171 let dispatcher = AuthDispatcher::new(validation, &config, &plugins)?
172 .with_key_provider(Arc::new(StaticKeyProvider::new(raw_claims)));
173
174 let claims = dispatcher.validate_jwt("demo-token").await?;
175 let perm_list = if claims.permissions.is_empty() {
176 "none".to_owned()
177 } else {
178 claims
179 .permissions
180 .iter()
181 .map(|p| format!("{}:{}", p.resource_pattern(), p.action()))
182 .collect::<Vec<_>>()
183 .join(", ")
184 };
185 println!(
186 "Validated token for subject {} with permissions {}",
187 claims.subject, perm_list
188 );
189
190 Ok(())
191}Sourcepub async fn validate_opaque(&self, token: &str) -> Result<Claims, ClaimsError>
pub async fn validate_opaque(&self, token: &str) -> Result<Claims, ClaimsError>
Validate an opaque token via introspection
Workflow:
- Try each
IntrospectionProvideruntil one succeeds - Extract issuer from introspection response
- Use the configured plugin to normalize claims
- Run common validation
- Return normalized claims
§Errors
Returns ClaimsError if introspection, claim normalization, or validation fails.
Sourcepub fn validation_config(&self) -> &ValidationConfig
pub fn validation_config(&self) -> &ValidationConfig
Get validation config (for inspection/testing)
Sourcepub fn plugin(&self) -> &Arc<dyn ClaimsPlugin>
pub fn plugin(&self) -> &Arc<dyn ClaimsPlugin>
Get the configured authentication plugin (for inspection/testing)
Sourcepub async fn refresh_keys(&self) -> Result<(), Vec<ClaimsError>>
pub async fn refresh_keys(&self) -> Result<(), Vec<ClaimsError>>
Trigger key refresh for all key providers.
§Errors
Returns a vector of ClaimsError if any provider fails to refresh keys.
Trait Implementations§
Source§impl TokenValidator for AuthDispatcher
Implement TokenValidator trait for AuthDispatcher
impl TokenValidator for AuthDispatcher
Implement TokenValidator trait for AuthDispatcher