Skip to main content

systemprompt_models/oauth/
server.rs

1//! OAuth server settings with spec-default expiries and scopes.
2//!
3//! Copyright (c) systemprompt.io — Business Source License 1.1.
4//! See <https://systemprompt.io> for licensing details.
5
6use serde::{Deserialize, Serialize};
7
8#[derive(Debug, Clone, Serialize, Deserialize)]
9pub struct OAuthServerConfig {
10    pub issuer: String,
11    pub authorization_endpoint: String,
12    pub token_endpoint: String,
13    pub registration_endpoint: String,
14    pub supported_scopes: Vec<String>,
15    pub supported_grant_types: Vec<String>,
16    pub supported_response_types: Vec<String>,
17    #[serde(default)]
18    pub supported_code_challenge_methods: Vec<String>,
19    #[serde(default = "default_auth_method")]
20    pub token_endpoint_auth_method: String,
21    #[serde(default = "default_scope")]
22    pub default_scope: String,
23    #[serde(default = "default_auth_code_expiry")]
24    pub auth_code_expiry_seconds: i32,
25    #[serde(default = "default_access_token_expiry")]
26    pub access_token_expiry_seconds: i32,
27}
28
29fn default_auth_method() -> String {
30    "client_secret_basic".to_owned()
31}
32
33fn default_scope() -> String {
34    "openid".to_owned()
35}
36
37const fn default_auth_code_expiry() -> i32 {
38    600
39}
40
41const fn default_access_token_expiry() -> i32 {
42    3600
43}
44
45impl OAuthServerConfig {
46    pub fn new(issuer: impl Into<String>) -> Self {
47        Self {
48            issuer: issuer.into(),
49            authorization_endpoint: String::new(),
50            token_endpoint: String::new(),
51            registration_endpoint: String::new(),
52            supported_scopes: Vec::new(),
53            supported_grant_types: Vec::new(),
54            supported_response_types: Vec::new(),
55            supported_code_challenge_methods: Vec::new(),
56            token_endpoint_auth_method: default_auth_method(),
57            default_scope: default_scope(),
58            auth_code_expiry_seconds: default_auth_code_expiry(),
59            access_token_expiry_seconds: default_access_token_expiry(),
60        }
61    }
62
63    pub fn from_api_server_url(api_server_url: &str) -> Self {
64        Self {
65            issuer: api_server_url.to_owned(),
66            authorization_endpoint: format!("{api_server_url}/api/v1/core/oauth/authorize"),
67            token_endpoint: format!("{api_server_url}/api/v1/core/oauth/token"),
68            registration_endpoint: format!("{api_server_url}/api/v1/core/oauth/register"),
69            supported_scopes: vec!["user".to_owned(), "admin".to_owned()],
70            supported_response_types: vec!["code".to_owned()],
71            supported_grant_types: vec![
72                "authorization_code".to_owned(),
73                "refresh_token".to_owned(),
74                "urn:ietf:params:oauth:grant-type:token-exchange".to_owned(),
75            ],
76            supported_code_challenge_methods: vec!["S256".to_owned()],
77            token_endpoint_auth_method: "client_secret_post".to_owned(),
78            default_scope: "user".to_owned(),
79            auth_code_expiry_seconds: 600,
80            access_token_expiry_seconds: 3600,
81        }
82    }
83}
84
85impl Default for OAuthServerConfig {
86    fn default() -> Self {
87        Self::from_api_server_url("http://localhost:8080")
88    }
89}