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}