yew_oauth2/context/
mod.rs

1//! The Authentication Context
2
3mod utils;
4
5use std::cell::RefCell;
6use std::rc::Rc;
7pub use utils::*;
8
9#[cfg(feature = "openid")]
10pub type Claims = openidconnect::IdTokenClaims<
11    openidconnect::EmptyAdditionalClaims,
12    openidconnect::core::CoreGenderClaim,
13>;
14
15/// The authentication information
16#[derive(Clone, Debug, Default, PartialEq)]
17#[cfg_attr(not(feature = "openid"), derive(Eq))]
18pub struct Authentication {
19    /// The access token
20    pub access_token: String,
21    /// The id token
22    pub id_token: Option<String>,
23    /// An optional refresh token
24    pub refresh_token: Option<String>,
25    /// OpenID claims
26    #[cfg(feature = "openid")]
27    pub claims: Option<Rc<Claims>>,
28    /// Expiration timestamp in seconds
29    pub expires: Option<u64>,
30}
31
32/// The authentication context
33#[derive(Clone, Debug, PartialEq)]
34#[cfg_attr(not(feature = "openid"), derive(Eq))]
35pub enum OAuth2Context {
36    /// The agent is not initialized yet.
37    NotInitialized,
38    /// Not authenticated.
39    NotAuthenticated {
40        /// Reason why it is not authenticated.
41        reason: Reason,
42    },
43    /// Session is authenticated.
44    Authenticated(Authentication),
45    /// Something failed.
46    Failed(String),
47}
48
49impl OAuth2Context {
50    /// Get the optional authentication.
51    ///
52    /// Allows easy access to the authentication information. Will return [`None`] if the
53    /// context is not authenticated.
54    pub fn authentication(&self) -> Option<&Authentication> {
55        match self {
56            Self::Authenticated(auth) => Some(auth),
57            _ => None,
58        }
59    }
60
61    /// Get the access token, if the context is [`OAuth2Context::Authenticated`]
62    pub fn access_token(&self) -> Option<&str> {
63        self.authentication().map(|auth| auth.access_token.as_str())
64    }
65
66    /// Get the id token, if the context is [`OAuth2Context::Authenticated`]
67    pub fn id_token(&self) -> Option<&str> {
68        self.authentication()
69            .and_then(|auth| auth.id_token.as_deref())
70    }
71
72    /// Get the claims, if the context is [`OAuth2Context::Authenticated`]
73    #[cfg(feature = "openid")]
74    pub fn claims(&self) -> Option<&Claims> {
75        self.authentication()
76            .and_then(|auth| auth.claims.as_ref().map(|claims| claims.as_ref()))
77    }
78}
79
80/// The reason why the context is un-authenticated.
81#[derive(Clone, Copy, Debug, PartialEq, Eq)]
82pub enum Reason {
83    /// Because the user didn't log in so far.
84    NewSession,
85    /// Because there was a session, but now it expired.
86    Expired,
87    /// Because the user chose to log out.
88    Logout,
89}
90
91/// A handle to access the latest access token.
92#[derive(Clone)]
93pub struct LatestAccessToken {
94    pub(crate) access_token: Rc<RefCell<Option<String>>>,
95}
96
97impl PartialEq for LatestAccessToken {
98    fn eq(&self, other: &Self) -> bool {
99        Rc::ptr_eq(&self.access_token, &other.access_token)
100    }
101}
102
103impl LatestAccessToken {
104    /// The latest access token, if there is any.
105    pub fn access_token(&self) -> Option<String> {
106        match self.access_token.as_ref().try_borrow() {
107            Ok(token) => (*token).clone(),
108            Err(_) => None,
109        }
110    }
111
112    pub(crate) fn set_access_token(&self, access_token: Option<impl Into<String>>) {
113        *self.access_token.borrow_mut() = access_token.map(|s| s.into());
114    }
115}