Skip to main content

openauth_oidc/
options.rs

1use std::collections::BTreeMap;
2use std::fmt;
3
4use serde::{Deserialize, Serialize};
5
6/// Secret string wrapper that redacts its value in `Debug` output.
7///
8/// Serialization intentionally exposes the wrapped value so provider configs
9/// can be persisted and later used for token exchange. Do not serialize this
10/// type into logs, API responses, or other user-visible surfaces.
11#[derive(Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
12#[serde(transparent)]
13pub struct SecretString(String);
14
15impl SecretString {
16    /// Wrap a secret value.
17    pub fn new(value: impl Into<String>) -> Self {
18        Self(value.into())
19    }
20
21    /// Borrow the raw secret value.
22    pub fn expose_secret(&self) -> &str {
23        &self.0
24    }
25
26    /// Consume the wrapper and return the raw secret value.
27    pub fn into_inner(self) -> String {
28        self.0
29    }
30}
31
32impl fmt::Debug for SecretString {
33    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
34        formatter.write_str("SecretString(REDACTED)")
35    }
36}
37
38impl From<String> for SecretString {
39    fn from(value: String) -> Self {
40        Self::new(value)
41    }
42}
43
44impl From<&str> for SecretString {
45    fn from(value: &str) -> Self {
46        Self::new(value)
47    }
48}
49
50impl AsRef<str> for SecretString {
51    fn as_ref(&self) -> &str {
52        self.expose_secret()
53    }
54}
55
56#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
57#[serde(rename_all = "camelCase")]
58/// OIDC configuration for an enterprise SSO provider.
59pub struct OidcProviderConfig {
60    /// OIDC issuer URL.
61    pub issuer: String,
62    /// Whether authorization requests should use PKCE.
63    pub pkce: bool,
64    /// OAuth/OIDC client id.
65    pub client_id: String,
66    /// OAuth/OIDC client secret. Debug output is redacted.
67    pub client_secret: SecretString,
68    /// OIDC discovery document URL.
69    pub discovery_endpoint: String,
70    #[serde(skip_serializing_if = "Option::is_none")]
71    /// Explicit authorization endpoint override.
72    pub authorization_endpoint: Option<String>,
73    #[serde(skip_serializing_if = "Option::is_none")]
74    /// Explicit token endpoint override.
75    pub token_endpoint: Option<String>,
76    #[serde(skip_serializing_if = "Option::is_none")]
77    /// Explicit UserInfo endpoint override.
78    pub user_info_endpoint: Option<String>,
79    #[serde(skip_serializing_if = "Option::is_none")]
80    /// Explicit JWKS endpoint override.
81    pub jwks_endpoint: Option<String>,
82    #[serde(skip_serializing_if = "Option::is_none")]
83    /// Optional OAuth token revocation endpoint discovered from the IdP.
84    pub revocation_endpoint: Option<String>,
85    #[serde(skip_serializing_if = "Option::is_none")]
86    /// Optional OIDC end-session endpoint discovered from the IdP.
87    pub end_session_endpoint: Option<String>,
88    #[serde(skip_serializing_if = "Option::is_none")]
89    /// Optional OAuth token introspection endpoint discovered from the IdP.
90    pub introspection_endpoint: Option<String>,
91    #[serde(skip_serializing_if = "Option::is_none")]
92    /// Token endpoint authentication method.
93    pub token_endpoint_authentication: Option<TokenEndpointAuthentication>,
94    #[serde(skip_serializing_if = "Option::is_none")]
95    /// Authorization request scopes.
96    pub scopes: Option<Vec<String>>,
97    #[serde(skip_serializing_if = "Option::is_none")]
98    /// Provider claim mapping.
99    pub mapping: Option<OidcProfileMapping>,
100    /// Override existing OpenAuth user fields with mapped OIDC values on login.
101    pub override_user_info: bool,
102}
103
104/// Backward-compatible OIDC provider config alias.
105pub type OidcConfig = OidcProviderConfig;
106
107#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
108#[serde(rename_all = "snake_case")]
109/// Supported OAuth token endpoint authentication methods.
110pub enum TokenEndpointAuthentication {
111    /// Send client credentials through HTTP Basic authentication.
112    ClientSecretBasic,
113    /// Send client credentials in the token request body.
114    ClientSecretPost,
115}
116
117#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
118#[serde(rename_all = "camelCase")]
119/// Mapping from OIDC claims to OpenAuth profile fields.
120pub struct OidcProfileMapping {
121    /// Claim used as the external account id.
122    pub id: Option<String>,
123    /// Claim used as email.
124    pub email: Option<String>,
125    /// Claim used as email verification status.
126    pub email_verified: Option<String>,
127    /// Claim used as display name.
128    pub name: Option<String>,
129    /// Claim used as avatar URL.
130    pub image: Option<String>,
131    /// Additional claim mappings exposed to hooks as raw attributes.
132    pub extra_fields: Option<BTreeMap<String, String>>,
133}
134
135/// Backward-compatible OIDC mapping alias.
136pub type OidcMapping = OidcProfileMapping;