Skip to main content

systemprompt_models/profile/
security.rs

1//! Profile `security:` block: signing keys, trusted issuers, resource
2//! audiences.
3//!
4//! Copyright (c) systemprompt.io — Business Source License 1.1.
5//! See <https://systemprompt.io> for licensing details.
6
7use std::path::PathBuf;
8
9use crate::auth::JwtAudience;
10use serde::{Deserialize, Serialize};
11
12pub const GATEWAY_REQUIRED_RESOURCE_AUDIENCES: &[&str] = &["hook"];
13
14#[must_use]
15pub fn default_resource_audiences() -> Vec<String> {
16    GATEWAY_REQUIRED_RESOURCE_AUDIENCES
17        .iter()
18        .map(|aud| (*aud).to_owned())
19        .collect()
20}
21
22const fn default_allow_registration() -> bool {
23    true
24}
25
26fn default_signing_key_path() -> PathBuf {
27    PathBuf::from("signing_key.pem")
28}
29
30pub const DEFAULT_ID_JAG_TTL_SECS: i64 = 300;
31
32const fn default_id_jag_ttl_secs() -> i64 {
33    DEFAULT_ID_JAG_TTL_SECS
34}
35
36#[derive(Debug, Clone, Serialize, Deserialize, schemars::JsonSchema)]
37#[serde(deny_unknown_fields)]
38pub struct SecurityConfig {
39    #[serde(rename = "jwt_issuer")]
40    pub issuer: String,
41
42    #[serde(rename = "jwt_access_token_expiration")]
43    pub access_token_expiration: i64,
44
45    #[serde(rename = "jwt_refresh_token_expiration")]
46    pub refresh_token_expiration: i64,
47
48    #[serde(rename = "jwt_audiences")]
49    pub audiences: Vec<JwtAudience>,
50
51    #[serde(default)]
52    pub allowed_resource_audiences: Vec<String>,
53
54    #[serde(default = "default_allow_registration")]
55    pub allow_registration: bool,
56
57    #[serde(default, skip_serializing_if = "Option::is_none")]
58    pub login_page_url: Option<String>,
59
60    #[serde(default = "default_signing_key_path")]
61    pub signing_key_path: PathBuf,
62
63    #[serde(default, skip_serializing_if = "Vec::is_empty")]
64    pub trusted_issuers: Vec<TrustedIssuer>,
65
66    #[serde(default = "default_id_jag_ttl_secs")]
67    pub id_jag_ttl_secs: i64,
68}
69
70/// A federated identity provider trusted for the RFC 8693 token-exchange and
71/// EMA (Enterprise-Managed Authorization) paths.
72///
73/// `audience` holds the value the `IdP` places in `id_token.aud`; for a
74/// Salesforce Connected App that is its `client_id`, **not** a URL.
75#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, schemars::JsonSchema)]
76#[serde(deny_unknown_fields)]
77pub struct TrustedIssuer {
78    pub issuer: String,
79    pub jwks_uri: String,
80    pub audience: String,
81
82    #[serde(default, skip_serializing_if = "Vec::is_empty")]
83    pub typ_allowlist: Vec<String>,
84
85    #[serde(default, skip_serializing_if = "Vec::is_empty")]
86    pub allowed_client_ids: Vec<String>,
87
88    #[serde(default)]
89    pub can_issue_id_jag: bool,
90}