facebook_access_token_api/endpoints/
helper.rs

1use facebook_access_token::{
2    AccessTokenExpiresIn, AppAccessToken, LongLivedUserAccessToken, PageAccessToken,
3    PageSessionInfoAccessToken, ShortLivedUserAccessToken, UserAccessToken,
4    UserSessionInfoAccessToken,
5};
6use facebook_graph_api_object_error::Error;
7use http_api_client::{Client, ClientRespondEndpointError};
8use http_api_client_endpoint::http::StatusCode;
9
10use crate::{
11    endpoints::{AccessTokenEndpoint, DebugTokenEndpoint, EndpointError, EndpointRet},
12    objects::{DebugTokenResult, ResponseBodyErrJson},
13};
14
15//
16// https://developers.facebook.com/docs/facebook-login/guides/access-tokens/get-long-lived#get-a-long-lived-user-access-token
17// The short_lived_user_access_token still valid after exchanged.
18//
19pub async fn get_long_lived_user_access_token<C: Client + Send + Sync>(
20    client: &C,
21    app_id: u64,
22    app_secret: impl AsRef<str>,
23    short_lived_user_access_token: impl Into<ShortLivedUserAccessToken>,
24) -> Result<
25    Result<
26        (LongLivedUserAccessToken, Option<AccessTokenExpiresIn>),
27        (StatusCode, ResponseBodyErrJson),
28    >,
29    ClientRespondEndpointError<C::RespondError, EndpointError, EndpointError>,
30> {
31    let ep = AccessTokenEndpoint::new(
32        "fb_exchange_token",
33        app_id,
34        Some(app_secret.as_ref().into()),
35        Some(short_lived_user_access_token.into().into_inner().into()),
36        None,
37    );
38
39    let ret = client.respond_endpoint(&ep).await?;
40
41    match ret {
42        EndpointRet::Ok(ok_json) => Ok(Ok((
43            ok_json.access_token.into(),
44            ok_json.expires_in.map(Into::into),
45        ))),
46        EndpointRet::Other((status_code, Ok(err_json))) => Ok(Err((status_code, err_json))),
47        EndpointRet::Other((status_code, Err(body))) => Ok(Err((
48            status_code,
49            ResponseBodyErrJson {
50                error: Error::new_with_status_code_and_body(
51                    status_code.as_u16(),
52                    String::from_utf8_lossy(&body).as_ref(),
53                ),
54            },
55        ))),
56    }
57}
58
59//
60// https://developers.facebook.com/docs/facebook-login/guides/access-tokens#generating-an-app-access-token
61//
62pub async fn gen_app_access_token<C: Client + Send + Sync>(
63    client: &C,
64    app_id: u64,
65    app_secret: impl AsRef<str>,
66) -> Result<
67    Result<AppAccessToken, (StatusCode, ResponseBodyErrJson)>,
68    ClientRespondEndpointError<C::RespondError, EndpointError, EndpointError>,
69> {
70    let ep = AccessTokenEndpoint::new(
71        "client_credentials",
72        app_id,
73        Some(app_secret.as_ref().into()),
74        None,
75        None,
76    );
77
78    let ret = client.respond_endpoint(&ep).await?;
79
80    match ret {
81        EndpointRet::Ok(ok_json) => Ok(Ok(ok_json.access_token.into())),
82        EndpointRet::Other((status_code, Ok(err_json))) => Ok(Err((status_code, err_json))),
83        EndpointRet::Other((status_code, Err(body))) => Ok(Err((
84            status_code,
85            ResponseBodyErrJson {
86                error: Error::new_with_status_code_and_body(
87                    status_code.as_u16(),
88                    String::from_utf8_lossy(&body).as_ref(),
89                ),
90            },
91        ))),
92    }
93}
94
95//
96// https://developers.facebook.com/docs/facebook-login/guides/access-tokens/get-session-info#generate-session-info-token
97//
98async fn gen_x_session_info_access_token_inner<C: Client + Send + Sync>(
99    client: &C,
100    app_id: u64,
101    x_session_info_access_token: &str,
102) -> Result<
103    Result<(String, Option<AccessTokenExpiresIn>), (StatusCode, ResponseBodyErrJson)>,
104    ClientRespondEndpointError<C::RespondError, EndpointError, EndpointError>,
105> {
106    let ep = AccessTokenEndpoint::new(
107        "fb_attenuate_token",
108        app_id,
109        None,
110        Some(x_session_info_access_token.into()),
111        None,
112    );
113
114    let ret = client.respond_endpoint(&ep).await?;
115
116    match ret {
117        EndpointRet::Ok(ok_json) => Ok(Ok((
118            ok_json.access_token.to_owned(),
119            ok_json.expires_in.map(Into::into),
120        ))),
121        EndpointRet::Other((status_code, Ok(err_json))) => Ok(Err((status_code, err_json))),
122        EndpointRet::Other((status_code, Err(body))) => Ok(Err((
123            status_code,
124            ResponseBodyErrJson {
125                error: Error::new_with_status_code_and_body(
126                    status_code.as_u16(),
127                    String::from_utf8_lossy(&body).as_ref(),
128                ),
129            },
130        ))),
131    }
132}
133
134//
135pub async fn gen_user_session_info_access_token<C: Client + Send + Sync>(
136    client: &C,
137    app_id: u64,
138    long_lived_user_access_token: impl Into<LongLivedUserAccessToken>,
139) -> Result<
140    Result<
141        (UserSessionInfoAccessToken, Option<AccessTokenExpiresIn>),
142        (StatusCode, ResponseBodyErrJson),
143    >,
144    ClientRespondEndpointError<C::RespondError, EndpointError, EndpointError>,
145> {
146    match gen_x_session_info_access_token_inner(
147        client,
148        app_id,
149        long_lived_user_access_token.into().inner(),
150    )
151    .await
152    {
153        Ok(Ok((value, expires_in))) => Ok(Ok((value.into(), expires_in))),
154        Ok(Err(x)) => Ok(Err(x)),
155        Err(err) => Err(err),
156    }
157}
158
159//
160pub async fn gen_page_session_info_access_token<C: Client + Send + Sync>(
161    client: &C,
162    app_id: u64,
163    page_access_token: impl Into<PageAccessToken>,
164) -> Result<
165    Result<
166        (PageSessionInfoAccessToken, Option<AccessTokenExpiresIn>),
167        (StatusCode, ResponseBodyErrJson),
168    >,
169    ClientRespondEndpointError<C::RespondError, EndpointError, EndpointError>,
170> {
171    match gen_x_session_info_access_token_inner(client, app_id, page_access_token.into().inner())
172        .await
173    {
174        Ok(Ok((value, expires_in))) => Ok(Ok((value.into(), expires_in))),
175        Ok(Err(x)) => Ok(Err(x)),
176        Err(err) => Err(err),
177    }
178}
179
180//
181// https://developers.facebook.com/docs/facebook-login/guides/%20access-tokens/debugging
182//
183async fn debug_x_access_token_inner<C: Client + Send + Sync>(
184    client: &C,
185    input_token: &str,
186    access_token: &str,
187) -> Result<
188    Result<DebugTokenResult, (StatusCode, ResponseBodyErrJson)>,
189    ClientRespondEndpointError<C::RespondError, EndpointError, EndpointError>,
190> {
191    let ep = DebugTokenEndpoint::new(input_token, access_token, None);
192
193    let ret = client.respond_endpoint(&ep).await?;
194
195    match ret {
196        EndpointRet::Ok(ok_json) => Ok(Ok(ok_json.data)),
197        EndpointRet::Other((status_code, Ok(err_json))) => Ok(Err((status_code, err_json))),
198        EndpointRet::Other((status_code, Err(body))) => Ok(Err((
199            status_code,
200            ResponseBodyErrJson {
201                error: Error::new_with_status_code_and_body(
202                    status_code.as_u16(),
203                    String::from_utf8_lossy(&body).as_ref(),
204                ),
205            },
206        ))),
207    }
208}
209
210//
211pub async fn debug_user_access_token<C: Client + Send + Sync>(
212    client: &C,
213    short_lived_or_long_lived_user_access_token: impl Into<UserAccessToken>,
214) -> Result<
215    Result<DebugTokenResult, (StatusCode, ResponseBodyErrJson)>,
216    ClientRespondEndpointError<C::RespondError, EndpointError, EndpointError>,
217> {
218    let token = short_lived_or_long_lived_user_access_token.into();
219    debug_x_access_token_inner(client, token.inner(), token.inner()).await
220}
221
222/*
223Sometimes, debug_user_access_token without app_access_token will
224400
225{
226    "error": {
227        "message": "(#100) You must provide an app access token, or a user access token that is an owner or developer of the app",
228        "type": "OAuthException",
229        "code": 100,
230        "fbtrace_id": "ARIDoDhBfOqF7CZBTrzBCdP"
231    }
232}
233*/
234//
235pub async fn debug_user_access_token_via_app_access_token<C: Client + Send + Sync>(
236    client: &C,
237    short_lived_or_long_lived_user_access_token: impl Into<UserAccessToken>,
238    app_access_token: impl Into<AppAccessToken>,
239) -> Result<
240    Result<DebugTokenResult, (StatusCode, ResponseBodyErrJson)>,
241    ClientRespondEndpointError<C::RespondError, EndpointError, EndpointError>,
242> {
243    let input_token = short_lived_or_long_lived_user_access_token.into();
244    let access_token = app_access_token.into();
245    debug_x_access_token_inner(client, input_token.inner(), access_token.inner()).await
246}
247
248//
249pub async fn debug_app_access_token<C: Client + Send + Sync>(
250    client: &C,
251    app_access_token: impl Into<AppAccessToken>,
252) -> Result<
253    Result<DebugTokenResult, (StatusCode, ResponseBodyErrJson)>,
254    ClientRespondEndpointError<C::RespondError, EndpointError, EndpointError>,
255> {
256    let token = app_access_token.into();
257    debug_x_access_token_inner(client, token.inner(), token.inner()).await
258}
259
260//
261pub async fn debug_page_access_token<C: Client + Send + Sync>(
262    client: &C,
263    page_access_token: impl Into<PageAccessToken>,
264) -> Result<
265    Result<DebugTokenResult, (StatusCode, ResponseBodyErrJson)>,
266    ClientRespondEndpointError<C::RespondError, EndpointError, EndpointError>,
267> {
268    let token = page_access_token.into();
269    debug_x_access_token_inner(client, token.inner(), token.inner()).await
270}
271
272//
273pub async fn debug_user_session_info_access_token_via_app_access_token<C: Client + Send + Sync>(
274    client: &C,
275    user_session_info_access_token: impl Into<UserSessionInfoAccessToken>,
276    app_access_token: impl Into<AppAccessToken>,
277) -> Result<
278    Result<DebugTokenResult, (StatusCode, ResponseBodyErrJson)>,
279    ClientRespondEndpointError<C::RespondError, EndpointError, EndpointError>,
280> {
281    let input_token = user_session_info_access_token.into();
282    let access_token = app_access_token.into();
283    debug_x_access_token_inner(client, input_token.inner(), access_token.inner()).await
284}
285
286//
287pub async fn debug_user_session_info_access_token_via_long_lived_user_access_token<
288    C: Client + Send + Sync,
289>(
290    client: &C,
291    user_session_info_access_token: impl Into<UserSessionInfoAccessToken>,
292    long_lived_user_access_token: impl Into<LongLivedUserAccessToken>,
293) -> Result<
294    Result<DebugTokenResult, (StatusCode, ResponseBodyErrJson)>,
295    ClientRespondEndpointError<C::RespondError, EndpointError, EndpointError>,
296> {
297    let input_token = user_session_info_access_token.into();
298    let access_token = long_lived_user_access_token.into();
299    debug_x_access_token_inner(client, input_token.inner(), access_token.inner()).await
300}
301
302//
303pub async fn debug_page_session_info_access_token_via_app_access_token<C: Client + Send + Sync>(
304    client: &C,
305    page_session_info_access_token: impl Into<PageSessionInfoAccessToken>,
306    app_access_token: impl Into<AppAccessToken>,
307) -> Result<
308    Result<DebugTokenResult, (StatusCode, ResponseBodyErrJson)>,
309    ClientRespondEndpointError<C::RespondError, EndpointError, EndpointError>,
310> {
311    let input_token = page_session_info_access_token.into();
312    let access_token = app_access_token.into();
313    debug_x_access_token_inner(client, input_token.inner(), access_token.inner()).await
314}
315
316//
317pub async fn debug_page_session_info_access_token_via_page_access_token<C: Client + Send + Sync>(
318    client: &C,
319    page_session_info_access_token: impl Into<PageSessionInfoAccessToken>,
320    page_access_token: impl Into<PageAccessToken>,
321) -> Result<
322    Result<DebugTokenResult, (StatusCode, ResponseBodyErrJson)>,
323    ClientRespondEndpointError<C::RespondError, EndpointError, EndpointError>,
324> {
325    let input_token = page_session_info_access_token.into();
326    let access_token = page_access_token.into();
327    debug_x_access_token_inner(client, input_token.inner(), access_token.inner()).await
328}