Skip to main content

alibi_plugins/oauth_provider/
post_login.rs

1use alibi_core::{AuthResult, SessionView, UserView};
2use async_trait::async_trait;
3use std::{collections::HashMap, sync::Arc};
4
5/// Authenticated post-login policy input. The pinned callback does not receive
6/// a client argument; admission has already validated the requesting client.
7pub struct OAuthInteractionContext<'a> {
8    pub headers: &'a HashMap<String, String>,
9    pub user: &'a UserView,
10    pub session: &'a SessionView,
11    pub scopes: &'a [String],
12}
13
14pub type OAuthPostLoginContext<'a> = OAuthInteractionContext<'a>;
15
16#[async_trait]
17pub trait OAuthPostLoginPolicy: Send + Sync + std::fmt::Debug {
18    async fn should_redirect(&self, input: OAuthPostLoginContext<'_>) -> AuthResult<bool>;
19}
20
21/// Consent authority selection after post-login interaction. No request headers
22/// or client are supplied by the pinned callback contract.
23pub struct OAuthConsentReferenceContext<'a> {
24    pub user: &'a UserView,
25    pub session: &'a SessionView,
26    pub scopes: &'a [String],
27}
28
29#[async_trait]
30pub trait OAuthConsentReference: Send + Sync + std::fmt::Debug {
31    async fn consent_reference_id(
32        &self,
33        input: OAuthConsentReferenceContext<'_>,
34    ) -> AuthResult<Option<String>>;
35}
36
37/// Application interaction after signup policy and before consent.
38#[derive(Debug, Clone)]
39pub struct OAuthPostLoginConfig {
40    pub page: String,
41    pub should_redirect: Arc<dyn OAuthPostLoginPolicy>,
42    /// Select an additional consent partition within the authenticated user's
43    /// grants. `None` or an empty returned string omits the reference filter;
44    /// neither changes user ownership of consent-management operations.
45    pub consent_reference_id: Option<Arc<dyn OAuthConsentReference>>,
46}
47
48impl super::OAuthProviderPlugin {
49    pub(super) async fn consent_reference_id(
50        &self,
51        user: &UserView,
52        session: &SessionView,
53        scopes: &[String],
54    ) -> AuthResult<Option<String>> {
55        let Some(reference) = self
56            .config
57            .post_login
58            .as_ref()
59            .and_then(|config| config.consent_reference_id.as_ref())
60        else {
61            return Ok(None);
62        };
63        reference
64            .consent_reference_id(OAuthConsentReferenceContext {
65                user,
66                session,
67                scopes,
68            })
69            .await
70            .map_err(|error| {
71                if alibi_core::endpoint::is_endpoint_api_error(&error) {
72                    error
73                } else {
74                    alibi_core::AuthError::CallbackFailure(Box::new(error))
75                }
76            })
77    }
78}