paypal_rust/client/
auth.rs1use std::borrow::Cow;
2use std::ops::Sub;
3
4use chrono::{DateTime, Utc};
5use reqwest::Method;
6use serde::{Deserialize, Serialize};
7use serde_with::skip_serializing_none;
8
9use crate::client::endpoint::Endpoint;
10use crate::client::request::{HttpRequestHeaders, RequestStrategy, RetryCount};
11
12#[derive(Debug, Clone, Serialize)]
13pub struct AuthRequestBody {
14 grant_type: String,
15}
16
17#[skip_serializing_none]
18#[derive(Clone, Debug, Deserialize, Default)]
19pub struct AuthResponse {
20 pub scope: Option<String>,
22
23 pub access_token: String,
25
26 pub refresh_token: Option<String>,
28
29 pub token_type: String,
31
32 pub app_id: String,
34
35 pub expires_in: i32,
37
38 pub nonce: String,
40}
41
42#[derive(Debug)]
43pub struct Authenticate {
44 pub authorization: String,
45}
46
47impl Authenticate {
48 pub const fn new(authorization: String) -> Self {
49 Self { authorization }
50 }
51}
52
53impl Endpoint for Authenticate {
54 type QueryParams = ();
55 type RequestBody = AuthRequestBody;
56 type ResponseBody = AuthResponse;
57
58 fn path(&self) -> Cow<str> {
59 Cow::Borrowed("v1/oauth2/token")
60 }
61
62 fn headers(&self) -> HttpRequestHeaders {
63 HttpRequestHeaders {
64 authorization: self.authorization.clone(),
65 content_type: "application/x-www-form-urlencoded".to_string(),
66 ..Default::default()
67 }
68 }
69
70 fn request_body(&self) -> Option<Self::RequestBody> {
71 Some(AuthRequestBody {
72 grant_type: "client_credentials".to_string(),
73 })
74 }
75
76 fn request_method(&self) -> Method {
77 Method::POST
78 }
79
80 fn request_strategy(&self) -> RequestStrategy {
81 RequestStrategy::Retry(RetryCount::from(3))
82 }
83
84 fn auth_strategy(&self) -> AuthStrategy {
85 AuthStrategy::NoTokenRefresh
86 }
87}
88
89#[derive(Debug, Default, Copy, Clone, Eq, PartialEq)]
90pub enum AuthStrategy {
92 #[default]
94 TokenRefresh,
95 NoTokenRefresh,
97}
98
99#[skip_serializing_none]
100#[derive(Debug, Clone, Default, Serialize)]
101pub struct AuthData {
102 pub access_token: String,
103 pub refresh_token: Option<String>,
104
105 pub expiry_time: Option<DateTime<Utc>>,
107}
108
109impl AuthData {
110 pub fn about_to_expire(&self) -> bool {
111 self.expiry_time.map_or(true, |expiry_time| {
112 expiry_time.sub(Utc::now()).num_seconds() < 10
113 })
114 }
115
116 pub fn update(&mut self, response: AuthResponse) {
117 self.access_token = response.access_token;
118 self.refresh_token = response.refresh_token;
119 self.expiry_time =
120 Some(Utc::now() + chrono::Duration::seconds(i64::from(response.expires_in)));
121 }
122}