better_auth_api/plugins/jwt/
overrides.rs1use super::*;
2
3#[derive(Clone, Default, serde::Deserialize)]
5#[serde(rename_all = "camelCase")]
6pub struct JwtTokenOptions {
7 pub issuer: Option<String>,
8 pub audience: Option<JwtAudience>,
9 #[serde(default, deserialize_with = "input::expiration")]
10 pub expiration_time: Option<JwtExpiration>,
11 #[serde(skip)]
12 pub custom_sign: Option<JwtCustomSign>,
13}
14
15#[derive(Clone, Default, serde::Deserialize)]
17#[serde(rename_all = "camelCase")]
18pub struct JwtKeyOptions {
19 #[serde(rename = "keyPairConfig")]
20 pub key_pair: Option<JwtKeyPairConfig>,
21 pub key_pair_configs: Option<Vec<JwtKeyPairConfig>>,
22 #[serde(default, deserialize_with = "input::duration")]
23 pub rotation_interval: Option<Duration>,
24 pub disable_private_key_encryption: Option<bool>,
25}
26
27pub struct JwtCallOverrides<S: AuthSchema> {
30 pub jwt: Option<JwtTokenOptions>,
31 pub jwks: Option<JwtKeyOptions>,
32 pub adapter: Option<JwtCallbacks<S>>,
33}
34
35impl<S: AuthSchema> Default for JwtCallOverrides<S> {
36 fn default() -> Self {
37 Self {
38 jwt: None,
39 jwks: None,
40 adapter: None,
41 }
42 }
43}
44
45impl<S: AuthSchema> JwtCallOverrides<S> {
46 pub(super) fn apply(self, config: &mut JwtPluginConfig, context: &mut AuthContext<S>) -> Value {
47 let mut body = Map::new();
48 if let Some(jwt) = self.jwt {
49 let mut values = Map::new();
50 if let Some(issuer) = &jwt.issuer {
51 let _ = values.insert("issuer".into(), issuer.clone().into());
52 }
53 if let Some(audience) = &jwt.audience {
54 let _ = values.insert("audience".into(), json!(audience));
55 }
56 if let Some(expiration) = &jwt.expiration_time {
57 let value = match expiration {
58 JwtExpiration::At(value) => Value::Number(value.clone()),
59 JwtExpiration::After(duration) => {
60 format!("{}s", duration_seconds(*duration)).into()
61 }
62 };
63 let _ = values.insert("expirationTime".into(), value);
64 }
65 let _ = body.insert("jwt".into(), values.into());
66 config.issuer = jwt.issuer;
67 config.audience = jwt.audience;
68 config.expiration_time = jwt
69 .expiration_time
70 .unwrap_or(JwtExpiration::After(Duration::minutes(15)));
71 config.custom_sign = jwt.custom_sign;
72 config.define_payload = None;
73 config.get_subject = None;
74 }
75 if let Some(jwks) = self.jwks {
76 let mut values = Map::new();
77 if let Some(parameters) = jwks.key_pair {
78 let _ = values.insert("keyPairConfig".into(), key_pair(parameters));
79 }
80 if let Some(parameters) = &jwks.key_pair_configs {
81 let _ = values.insert(
82 "keyPairConfigs".into(),
83 parameters.iter().copied().map(key_pair).collect(),
84 );
85 }
86 if let Some(rotation) = jwks.rotation_interval {
87 let _ = values.insert("rotationInterval".into(), duration_seconds(rotation).into());
88 }
89 if let Some(disabled) = jwks.disable_private_key_encryption {
90 let _ = values.insert("disablePrivateKeyEncryption".into(), disabled.into());
91 }
92 let _ = body.insert("jwks".into(), values.into());
93 let primary = jwks
94 .key_pair
95 .unwrap_or(JwtKeyPairConfig::new(JwtAlgorithm::EdDsa));
96 config.algorithm = primary.algorithm;
97 config.modulus_length = primary.modulus_length;
98 config.key_pair_configs = jwks.key_pair_configs.unwrap_or_default();
99 config.rotation_interval = jwks.rotation_interval;
100 config.disable_private_key_encryption =
101 jwks.disable_private_key_encryption.unwrap_or(false);
102 }
103 if let Some(adapter) = self.adapter {
104 let _ = body.insert("adapter".into(), json!({}));
105 context.extensions.insert(std::sync::Arc::new(adapter));
106 }
107 body.into()
108 }
109}
110
111fn key_pair(parameters: JwtKeyPairConfig) -> Value {
112 json!({"alg": parameters.algorithm.name(), "modulusLength": parameters.modulus_length})
113}
114
115fn duration_seconds(duration: Duration) -> f64 {
116 duration.num_seconds() as f64 + f64::from(duration.subsec_nanos()) / 1e9
117}
118
119#[path = "override_input.rs"]
120mod input;
121
122pub(super) fn from_input<S: AuthSchema>(
123 value: &Value,
124 original: &JwtPluginConfig,
125 original_input: Option<&Value>,
126) -> AuthResult<JwtCallOverrides<S>> {
127 let object = |value: &Value| value.as_object().cloned().unwrap_or_default().into();
128 let mut jwt = value
129 .get("jwt")
130 .map(|value| serde_json::from_value::<JwtTokenOptions>(object(value)))
131 .transpose()?;
132 if let Some(jwt) = &mut jwt
133 && value.get("jwt").is_some_and(Value::is_object)
134 && original_input.and_then(|value| value.get("jwt")).is_some()
135 {
136 jwt.custom_sign = original.custom_sign.clone();
137 }
138 let jwks = value
139 .get("jwks")
140 .map(|value| serde_json::from_value::<JwtKeyOptions>(object(value)))
141 .transpose()?;
142 Ok(JwtCallOverrides {
143 jwt,
144 jwks,
145 adapter: None,
146 })
147}