jquants_api_client/api/shared/
auth.rs

1//! This module contains the authentication API.
2
3use reqwest::Client;
4
5use crate::{
6    api::build_url, IdTokenRequest, IdTokenResponse, JQuantsError, JQuantsErrorResponse,
7    RefreshTokenRequest, RefreshTokenResponse,
8};
9
10pub mod id_token;
11pub mod refresh_token;
12
13/// Get a refresh token from the Refresh Token (/token/auth_user) API.
14pub(crate) async fn get_refresh_token_from_api(
15    client: &Client,
16    mail_address: &str,
17    password: &str,
18) -> Result<String, JQuantsError> {
19    let url = build_url("token/auth_user");
20    let request_body = RefreshTokenRequest {
21        mail_address: mail_address.to_string(),
22        password: password.to_string(),
23    };
24
25    let response = client.post(&url).json(&request_body).send().await?;
26    let status = response.status();
27    let status_code = status.as_u16();
28    let text = response.text().await.unwrap_or_default();
29    if status == reqwest::StatusCode::OK {
30        match serde_json::from_str::<RefreshTokenResponse>(&text) {
31            Ok(data) => Ok(data.refresh_token),
32            Err(_) => Err(JQuantsError::InvalidResponseFormat {
33                status_code,
34                body: text,
35            }),
36        }
37    } else {
38        match serde_json::from_str::<JQuantsErrorResponse>(&text) {
39            Ok(error_response) => match status {
40                reqwest::StatusCode::BAD_REQUEST | reqwest::StatusCode::FORBIDDEN => {
41                    Err(JQuantsError::InvalidCredentials {
42                        body: error_response,
43                        status_code,
44                    })
45                }
46                _ => Err(JQuantsError::ApiError {
47                    body: error_response,
48                    status_code,
49                }),
50            },
51            Err(_) => Err(JQuantsError::InvalidResponseFormat {
52                status_code,
53                body: text,
54            }),
55        }
56    }
57}
58
59/// リフレッシュトークンを使用してAPI経由でIDトークンを取得
60pub(crate) async fn get_id_token_from_api(
61    client: &Client,
62    refresh_token: &str,
63) -> Result<String, JQuantsError> {
64    let url = build_url("token/auth_refresh");
65    let request_body = IdTokenRequest {
66        refresh_token: refresh_token.to_string(),
67    };
68    let response = client.post(&url).query(&request_body).send().await?;
69    let status = response.status();
70    let status_code = status.as_u16();
71    let text = response.text().await.unwrap_or_default();
72    if status == reqwest::StatusCode::OK {
73        match serde_json::from_str::<IdTokenResponse>(&text) {
74            Ok(data) => Ok(data.id_token),
75            Err(_) => Err(JQuantsError::InvalidResponseFormat {
76                status_code,
77                body: text,
78            }),
79        }
80    } else {
81        match serde_json::from_str::<JQuantsErrorResponse>(&text) {
82            Ok(error_response) => match status {
83                reqwest::StatusCode::FORBIDDEN => Err(JQuantsError::IdTokenInvalidOrExpired {
84                    body: error_response,
85                    status_code,
86                }),
87                _ => Err(JQuantsError::ApiError {
88                    body: error_response,
89                    status_code,
90                }),
91            },
92            Err(_) => Err(JQuantsError::InvalidResponseFormat {
93                status_code,
94                body: text,
95            }),
96        }
97    }
98}