siwa_async/auth/
auth_token.rs1use hyper::StatusCode;
3use serde::{self, Deserialize, Serialize};
4
5use crate::{
6 common::constants::{
7 APPLE_AUTH_TOKEN_ENDPOINT, APPLE_REVOKE_TOKENS_ENDPOINT,
8 },
9 error::{Error, Result},
10 object::{AppleClientSecretPayload, AuthError},
11};
12
13#[derive(Debug, Deserialize, Serialize, PartialEq, Clone)]
16pub struct AuthTokenRequest {
17 client_id: String,
19 client_secret: String,
21 code: Option<String>,
23 grant_type: AuthGrantType,
25 refresh_token: Option<String>,
27 redirect_uri: Option<String>,
29}
30
31impl AuthTokenRequest {
32 pub fn new(
35 client_id: String,
36 client_secret: AppleClientSecretPayload,
37 redirect_uri: Option<String>,
38 ) -> Result<Self> {
39 Ok(Self {
40 client_id,
41 client_secret: client_secret.encode()?,
42 redirect_uri,
43 code: None,
44 refresh_token: None,
45 grant_type: AuthGrantType::AuthorizationCode,
46 })
47 }
48 pub async fn validate_auth_code(
49 &self,
50 auth_code: &str,
51 ) -> Result<AuthTokenResponse> {
52 let mut request = self.clone();
53 request.grant_type = AuthGrantType::AuthorizationCode;
54 request.code = Some(auth_code.to_owned());
55 request.refresh_token = None;
56 request.validate().await
57 }
58
59 pub async fn validate_refresh_token(
60 &self,
61 refresh_token: &str,
62 ) -> Result<AuthTokenResponse> {
63 let mut request = self.clone();
64 request.grant_type = AuthGrantType::RefreshToken;
65 request.refresh_token = Some(refresh_token.to_owned());
66 request.code = None;
67 request.validate().await
68 }
69
70 async fn validate(&self) -> Result<AuthTokenResponse> {
71 let client = reqwest::Client::new();
72 let res = client
73 .post(APPLE_AUTH_TOKEN_ENDPOINT)
74 .form(self)
75 .send()
76 .await
77 .map_err(|e| Error::HttpError(format!("{:?}", e)))?;
78 match &res.status() {
79 &StatusCode::OK => {
80 Ok(res.json::<AuthTokenResponse>().await?)
81 }
82 _ => {
83 Err(Error::BadRequest(res.json::<AuthError>().await?))
84 }
85 }
86 }
87
88 pub async fn revoke_refresh_token(
89 &self,
90 refresh_token: String,
91 ) -> Result<()> {
92 self.revoke(refresh_token, &AuthTokenType::RefreshToken)
93 .await
94 }
95
96 pub async fn revoke_access_token(
97 &self,
98 access_token: String,
99 ) -> Result<()> {
100 self.revoke(access_token, &AuthTokenType::AccessToken).await
101 }
102
103 async fn revoke(
104 &self,
105 token: String,
106 token_type: &AuthTokenType,
107 ) -> Result<()> {
108 let client = reqwest::Client::new();
109 let params = [
110 ("client_id", self.client_id.clone()),
111 ("client_secret", self.client_secret.clone()),
112 ("token", token),
113 (
114 "token_type_hint",
115 serde_json::ser::to_string(token_type).unwrap(),
116 ),
117 ];
118 let res = client
119 .post(APPLE_REVOKE_TOKENS_ENDPOINT)
120 .form(¶ms)
121 .send()
122 .await
123 .map_err(|e| Error::HttpError(format!("{:?}", e)))?;
124
125 match &res.status() {
126 &StatusCode::OK => Ok(()),
127 _ => Err(Error::BadRequest(
128 res.json::<AuthError>().await.unwrap(),
129 )),
130 }
131 }
132}
133
134#[derive(Debug, Deserialize, Serialize, PartialEq, Clone)]
135enum AuthGrantType {
136 #[serde(rename = "authorization_code")]
138 AuthorizationCode,
139
140 #[serde(rename = "refresh_token")]
142 RefreshToken,
143}
144
145#[derive(Debug, Deserialize, Serialize, PartialEq)]
147pub struct AuthTokenResponse {
148 pub access_token: String,
149 pub expires_in: u64,
150 pub id_token: String,
151 pub refresh_token: Option<String>,
153 pub token_type: String,
155}
156
157#[derive(Debug, Deserialize, Serialize, PartialEq, Clone)]
158pub enum AuthTokenType {
159 #[serde(rename = "refresh_token")]
160 RefreshToken,
161 #[serde(rename = "access_token")]
162 AccessToken,
163}