systemprompt_api/routes/oauth/endpoints/token/
validation.rs1use super::{TokenError, TokenResult};
7use anyhow::Result;
8use systemprompt_identifiers::{AuthorizationCode, ClientId};
9use systemprompt_oauth::models::OAuthClient;
10use systemprompt_oauth::repository::{AuthCodeValidationResult, OAuthRepository};
11use systemprompt_oauth::services::validation::validate_client_credentials as validate_client_credentials_shared;
12
13pub fn extract_required_field<'a>(
14 field: Option<&'a str>,
15 field_name: &str,
16) -> TokenResult<&'a str> {
17 field.ok_or_else(|| TokenError::InvalidRequest {
18 field: field_name.to_owned(),
19 message: "is required".to_owned(),
20 })
21}
22
23pub async fn validate_client_credentials(
24 repo: &OAuthRepository,
25 client_id: &ClientId,
26 client_secret: Option<&str>,
27) -> Result<OAuthClient> {
28 validate_client_credentials_shared(repo, client_id, client_secret)
29 .await
30 .map_err(Into::into)
31}
32
33#[derive(Debug)]
34pub struct AuthCodeValidationParams<'a> {
35 pub repo: &'a OAuthRepository,
36 pub code: &'a AuthorizationCode,
37 pub client_id: &'a ClientId,
38 pub redirect_uri: Option<&'a str>,
39 pub code_verifier: Option<&'a str>,
40 pub request_resource: Option<&'a str>,
41}
42
43pub async fn validate_authorization_code(
44 params: AuthCodeValidationParams<'_>,
45) -> Result<AuthCodeValidationResult> {
46 let result = params
47 .repo
48 .validate_authorization_code(
49 params.code,
50 params.client_id,
51 params.redirect_uri,
52 params.code_verifier,
53 )
54 .await?;
55
56 if let Some(req_resource) = params.request_resource
57 && let Some(ref stored_resource) = result.resource
58 && req_resource != stored_resource
59 {
60 return Err(anyhow::anyhow!(
61 "Resource parameter mismatch: expected '{}', got '{}'",
62 stored_resource,
63 req_resource
64 ));
65 }
66
67 Ok(result)
68}