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