Skip to main content

origin_auth/
redirect.rs

1use async_trait::async_trait;
2use origin_domain::Result;
3use std::fmt::Debug;
4
5/// The authorization code handed back by the provider, after `state` was verified.
6#[derive(Debug, Clone)]
7pub struct AuthorizationCode(String);
8
9impl AuthorizationCode {
10    pub fn new(code: impl Into<String>) -> Self {
11        Self(code.into())
12    }
13
14    pub fn as_str(&self) -> &str {
15        &self.0
16    }
17}
18
19/// Receives the provider's redirect.
20///
21/// The implementation must be ready to receive *before* the authorization URL is
22/// opened, which is why [`RedirectListener::redirect_uri`] is available immediately —
23/// a loopback listener has already bound its port by then.
24#[async_trait]
25pub trait RedirectListener: Debug + Send + Sync {
26    /// The `redirect_uri` to send to the authorization endpoint.
27    fn redirect_uri(&self) -> String;
28
29    /// Wait for the redirect and return the code.
30    ///
31    /// Implementations must reject a response whose `state` does not match
32    /// `expected_state` — that check is what makes the flow immune to a forged
33    /// redirect — and must surface an `error` parameter (the user pressed "Deny")
34    /// rather than hanging.
35    async fn wait(&self, expected_state: &str) -> Result<AuthorizationCode>;
36}