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