yew_oauth2/agent/client/
mod.rs

1//! Client implementations
2
3mod oauth2;
4#[cfg(feature = "openid")]
5mod openid;
6
7pub use self::oauth2::*;
8#[cfg(feature = "openid")]
9pub use openid::*;
10
11use crate::{
12    agent::{InnerConfig, LogoutOptions, OAuth2Error},
13    context::OAuth2Context,
14};
15use async_trait::async_trait;
16use js_sys::Date;
17use num_traits::ToPrimitive;
18use reqwest::Url;
19use serde::{Deserialize, Serialize, de::DeserializeOwned};
20use std::fmt::Debug;
21use std::time::Duration;
22
23#[derive(Clone, Debug, Serialize, Deserialize)]
24pub struct LoginContext<S>
25where
26    S: Serialize,
27{
28    pub url: Url,
29    pub csrf_token: String,
30    pub state: S,
31}
32
33#[async_trait(?Send)]
34pub trait Client: 'static + Sized + Clone + Debug {
35    type TokenResponse;
36    type Configuration: Clone + Debug + PartialEq;
37    type LoginState: Debug + Serialize + DeserializeOwned;
38    type SessionState: Clone + Debug;
39
40    async fn from_config(config: Self::Configuration) -> Result<Self, OAuth2Error>;
41
42    fn set_redirect_uri(self, url: Url) -> Self;
43
44    fn make_login_context(
45        &self,
46        config: &InnerConfig,
47        redirect_url: Url,
48    ) -> Result<LoginContext<Self::LoginState>, OAuth2Error>;
49
50    async fn exchange_code(
51        &self,
52        code: String,
53        login_state: Self::LoginState,
54    ) -> Result<(OAuth2Context, Self::SessionState), OAuth2Error>;
55
56    async fn exchange_refresh_token(
57        &self,
58        refresh_token: String,
59        session_state: Self::SessionState,
60    ) -> Result<(OAuth2Context, Self::SessionState), OAuth2Error>;
61
62    /// Trigger the logout of the session
63    ///
64    /// Clients may choose to contact some back-channel or redirect to a logout URL.
65    fn logout(&self, _session_state: Self::SessionState, _options: LogoutOptions) {}
66}
67
68/// Convert a duration to a timestamp, in seconds.
69fn expires(expires_in: Option<Duration>) -> Option<u64> {
70    if let Some(expires_in) = expires_in {
71        let expires = ((Date::now() / 1000f64) + expires_in.as_secs_f64())
72            .to_u64()
73            .unwrap_or(u64::MAX);
74        Some(expires)
75    } else {
76        None
77    }
78}