systemprompt_api/routes/oauth/endpoints/token/
mod.rs1pub mod generation;
2mod handler;
3pub mod validation;
4
5pub use handler::handle_token;
6
7use serde::{Deserialize, Serialize};
8
9pub type TokenResult<T> = Result<T, TokenError>;
10
11#[derive(Debug, Deserialize)]
12pub struct TokenRequest {
13 pub grant_type: String,
14 pub code: Option<String>,
15 pub redirect_uri: Option<String>,
16 pub client_id: Option<String>,
17 pub client_secret: Option<String>,
18 pub refresh_token: Option<String>,
19 pub scope: Option<String>,
20 pub code_verifier: Option<String>,
21 pub resource: Option<String>,
22 pub plugin_id: Option<String>,
23 pub audience: Option<String>,
24}
25
26#[derive(Debug, Serialize)]
27
28pub struct TokenResponse {
29 pub access_token: String,
30 pub token_type: String,
31 pub expires_in: i64,
32 #[serde(skip_serializing_if = "Option::is_none")]
33 pub refresh_token: Option<String>,
34 #[serde(skip_serializing_if = "Option::is_none")]
35 pub scope: Option<String>,
36}
37
38#[derive(Debug, thiserror::Error)]
39pub enum TokenError {
40 #[error("Invalid request: {field} {message}")]
41 InvalidRequest { field: String, message: String },
42
43 #[error("Unsupported grant type: {grant_type}")]
44 UnsupportedGrantType { grant_type: String },
45
46 #[error("Invalid client credentials")]
47 InvalidClient,
48
49 #[error("Invalid authorization code: {reason}")]
50 InvalidGrant { reason: String },
51
52 #[error("Invalid refresh token: {reason}")]
53 InvalidRefreshToken { reason: String },
54
55 #[error("Invalid credentials")]
56 InvalidCredentials,
57
58 #[error("Invalid client secret")]
59 InvalidClientSecret,
60
61 #[error("Authorization code expired")]
62 ExpiredCode,
63
64 #[error("Server error: {message}")]
65 ServerError { message: String },
66}
67
68#[derive(Debug, Serialize)]
69
70pub struct TokenErrorResponse {
71 pub error: String,
72 #[serde(skip_serializing_if = "Option::is_none")]
73 pub error_description: Option<String>,
74}
75
76impl From<TokenError> for TokenErrorResponse {
77 fn from(error: TokenError) -> Self {
78 let (error_type, description) = match &error {
79 TokenError::InvalidRequest { field, message } => {
80 ("invalid_request", Some(format!("{field}: {message}")))
81 },
82 TokenError::UnsupportedGrantType { grant_type } => (
83 "unsupported_grant_type",
84 Some(format!("Grant type '{grant_type}' is not supported")),
85 ),
86 TokenError::InvalidClient => (
87 "invalid_client",
88 Some("Client authentication failed".to_string()),
89 ),
90 TokenError::InvalidGrant { reason } => ("invalid_grant", Some(reason.clone())),
91 TokenError::InvalidRefreshToken { reason } => (
92 "invalid_grant",
93 Some(format!("Refresh token invalid: {reason}")),
94 ),
95 TokenError::InvalidCredentials => {
96 ("invalid_grant", Some("Invalid credentials".to_string()))
97 },
98 TokenError::InvalidClientSecret => {
99 ("invalid_client", Some("Invalid client secret".to_string()))
100 },
101 TokenError::ExpiredCode => (
102 "invalid_grant",
103 Some("Authorization code expired".to_string()),
104 ),
105 TokenError::ServerError { message } => ("server_error", Some(message.clone())),
106 };
107
108 Self {
109 error: error_type.to_string(),
110 error_description: description,
111 }
112 }
113}