From 530cbb8e3723c539fdff1800288001ed03e18c63 Mon Sep 17 00:00:00 2001 From: Jens Reimann Date: Fri, 26 Jan 2024 11:49:43 +0100 Subject: [PATCH] chore: more docs and cleanups --- src/agent/client/mod.rs | 2 ++ src/agent/client/oauth2.rs | 3 ++- src/agent/client/openid.rs | 1 + src/agent/error.rs | 7 +++++++ src/agent/mod.rs | 28 +++++++++++++++++++++++++++- src/agent/ops.rs | 1 + src/components/redirect/location.rs | 14 ++++++++------ src/components/redirect/mod.rs | 4 ++-- src/components/redirect/router.rs | 11 ++++++----- src/lib.rs | 2 +- 10 files changed, 57 insertions(+), 16 deletions(-) diff --git a/src/agent/client/mod.rs b/src/agent/client/mod.rs index e270050..0aab190 100644 --- a/src/agent/client/mod.rs +++ b/src/agent/client/mod.rs @@ -1,3 +1,5 @@ +//! Client implementations + mod oauth2; #[cfg(feature = "openid")] mod openid; diff --git a/src/agent/client/oauth2.rs b/src/agent/client/oauth2.rs index 299bf4e..5f390d1 100644 --- a/src/agent/client/oauth2.rs +++ b/src/agent/client/oauth2.rs @@ -22,9 +22,10 @@ pub struct LoginState { pub pkce_verifier: String, } +/// An OAuth2 based client implementation #[derive(Clone, Debug)] pub struct OAuth2Client { - client: ::oauth2::basic::BasicClient, + client: BasicClient, } impl OAuth2Client { diff --git a/src/agent/client/openid.rs b/src/agent/client/openid.rs index 209b6c7..3dcfe27 100644 --- a/src/agent/client/openid.rs +++ b/src/agent/client/openid.rs @@ -33,6 +33,7 @@ pub struct OpenIdLoginState { const DEFAULT_POST_LOGOUT_DIRECT_NAME: &str = "post_logout_redirect_uri"; +/// An OpenID Connect based client implementation #[derive(Clone, Debug)] pub struct OpenIdClient { /// The client diff --git a/src/agent/error.rs b/src/agent/error.rs index 37b863e..b3acc7e 100644 --- a/src/agent/error.rs +++ b/src/agent/error.rs @@ -1,13 +1,20 @@ use crate::context::OAuth2Context; use core::fmt::{Display, Formatter}; +/// An error with the OAuth2 agent #[derive(Debug)] pub enum OAuth2Error { + /// Not initialized NotInitialized, + /// Configuration error Configuration(String), + /// Failed to start login StartLogin(String), + /// Failed to handle login result LoginResult(String), + /// Failing storing information Storage(String), + /// Internal error Internal(String), } diff --git a/src/agent/mod.rs b/src/agent/mod.rs index 386a1c1..dff8cdf 100644 --- a/src/agent/mod.rs +++ b/src/agent/mod.rs @@ -1,4 +1,4 @@ -//! The Yew agent, working in the background to manage the session and refresh tokens. +//! The agent, working in the background to manage the session and refresh tokens. pub mod client; mod config; @@ -42,6 +42,28 @@ use yew::Callback; /// # let url = Url::parse("https://example.com").unwrap(); /// let opts = LoginOptions::default().with_redirect_url(url); /// ``` +/// +/// ## Redirect & Post login redirect +/// +/// By default, the login process will ask the issuer to redirect back the page that was active when starting the login +/// process. In some cases, the issuer might require a more strict set of redirect URLs, and so can only redirect back +/// to a single page. This can be enabled set setting a specific URL as `redirect_url`. +/// +/// Once the user comes back from the login flow, which might actually be without any user interaction if the session +/// was still valid, the user might find himself on the redirect page. Therefore, it is possible to forward/redirect +/// the back to the original page, but only after the issuer redirected back the `redirect_url`. If, while starting the +/// login process, the currently active URL differs from the `redirect_url`, the agent will store the "current" URL and +/// redirect to it once the login process has completed. +/// +/// However, there can be different ways to redirect, and there is no common one. One might think just setting a new +/// location in the browser should work, but that would actually cause a page reload, and would then start the login +/// process again. +/// +/// Therefore, it is possible to set a "post login redirect callback", which will be triggered in such cases. Letting +/// the user of the crate implement this logic. Having the `yew-nested-router` feature enabled, it is possible to just +/// call [`LoginOptions::with_nested_router_redirect`] and let the router take care of this. +/// +/// **NOTE:** The default is to do nothing. So the user would simply end up on the page defined by `redirect_url`. #[derive(Debug, Clone, Default)] #[non_exhaustive] pub struct LoginOptions { @@ -135,6 +157,7 @@ impl LogoutOptions { } } +#[doc(hidden)] pub enum Msg where C: Client, @@ -145,6 +168,7 @@ where Refresh, } +/// The agent handling the OAuth2/OIDC state #[derive(Clone, Debug)] pub struct Agent where @@ -170,6 +194,7 @@ where } } +#[doc(hidden)] pub struct InnerAgent where C: Client, @@ -183,6 +208,7 @@ where timeout: Option, } +#[doc(hidden)] #[derive(Clone, Debug)] pub struct InnerConfig { scopes: Vec, diff --git a/src/agent/ops.rs b/src/agent/ops.rs index f26a128..5ec6599 100644 --- a/src/agent/ops.rs +++ b/src/agent/ops.rs @@ -1,6 +1,7 @@ use super::{AgentConfiguration, Client, LoginOptions, LogoutOptions}; use std::fmt::{Display, Formatter}; +/// Operation error #[derive(Clone, Debug)] pub enum Error { /// The agent cannot be reached. diff --git a/src/components/redirect/location.rs b/src/components/redirect/location.rs index 9c84f0e..55755ff 100644 --- a/src/components/redirect/location.rs +++ b/src/components/redirect/location.rs @@ -5,10 +5,10 @@ use gloo_utils::window; use yew::prelude::*; /// A redirector using the browser's location. -pub struct LocationRedirector {} +pub struct LocationRedirector; impl Redirector for LocationRedirector { - type Properties = LocationProps; + type Properties = LocationProperties; fn new(_: &Context) -> Self { Self {} @@ -21,15 +21,17 @@ impl Redirector for LocationRedirector { } #[derive(Clone, Debug, PartialEq, Properties)] -pub struct LocationProps { +pub struct LocationProperties { + /// The content to show when being logged in. #[prop_or_default] - pub children: Children, + pub children: Html, + /// The logout URL to redirect to pub logout_href: String, } -impl RedirectorProperties for LocationProps { - fn children(&self) -> &Children { +impl RedirectorProperties for LocationProperties { + fn children(&self) -> &Html { &self.children } } diff --git a/src/components/redirect/mod.rs b/src/components/redirect/mod.rs index cca455b..55b2cc4 100644 --- a/src/components/redirect/mod.rs +++ b/src/components/redirect/mod.rs @@ -19,7 +19,7 @@ pub trait Redirector: 'static { } pub trait RedirectorProperties: yew::Properties { - fn children(&self) -> &Children; + fn children(&self) -> &Html; } #[derive(Debug, Clone)] @@ -104,7 +104,7 @@ where fn view(&self, ctx: &Context) -> Html { match self.auth { None => missing_context(), - Some(OAuth2Context::Authenticated(..)) => html!({for ctx.props().children().iter()}), + Some(OAuth2Context::Authenticated(..)) => ctx.props().children().clone(), _ => html!(), } } diff --git a/src/components/redirect/router.rs b/src/components/redirect/router.rs index 4081b49..f7d164e 100644 --- a/src/components/redirect/router.rs +++ b/src/components/redirect/router.rs @@ -17,7 +17,7 @@ impl Redirector for RouterRedirector where R: Target + 'static, { - type Properties = RouterProps; + type Properties = RouterProperties; fn new(ctx: &Context) -> Self { // while the "route" can change, the "router" itself does not. @@ -43,21 +43,22 @@ where } } +/// Properties for the [`RouterRedirector`] component. #[derive(Clone, Debug, PartialEq, Properties)] -pub struct RouterProps +pub struct RouterProperties where R: Target + 'static, { #[prop_or_default] - pub children: Children, + pub children: Html, pub logout: R, } -impl RedirectorProperties for RouterProps +impl RedirectorProperties for RouterProperties where R: Target + 'static, { - fn children(&self) -> &Children { + fn children(&self) -> &Html { &self.children } } diff --git a/src/lib.rs b/src/lib.rs index 0a05685..2bae789 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,7 +10,7 @@ //! //! ## Example //! -//! **NOTE:** Also see the readme for more examples. +//! **NOTE:** Also see the [readme](https://github.com/ctron/yew-oauth2/blob/main/README.md#examples) for more examples. //! //! The following is a basic example: //!