oauth2_broker/flows/
auth_code_pkce.rs1mod session;
12
13pub use session::*;
14
15use crate::{
17 _prelude::*,
18 auth::{PrincipalId, ScopeSet, TenantId, TokenFamily, TokenRecord},
19 error::ConfigError,
20 flows::Broker,
21 http::TokenHttpClient,
22 oauth::{BasicFacade, OAuth2Facade, TransportErrorMapper},
23 obs::{self, FlowKind, FlowOutcome, FlowSpan},
24 provider::GrantType,
25 store::BrokerStore,
26};
27
28impl<C, M> Broker<C, M>
29where
30 C: ?Sized + TokenHttpClient,
31 M: ?Sized + TransportErrorMapper<C::TransportError>,
32{
33 pub fn start_authorization(
46 &self,
47 tenant: TenantId,
48 principal: PrincipalId,
49 scope: ScopeSet,
50 redirect_uri: Url,
51 ) -> Result<AuthorizationSession> {
52 const KIND: FlowKind = FlowKind::AuthorizationCode;
53
54 let _span = FlowSpan::new(KIND, "start_authorization").entered();
55
56 obs::record_flow_outcome(KIND, FlowOutcome::Attempt);
57
58 let result = (|| -> Result<AuthorizationSession> {
59 self.ensure_authorization_code_supported()?;
60 Ok(build_session(
61 &self.descriptor,
62 self.client_id.as_str(),
63 tenant,
64 principal,
65 scope,
66 redirect_uri,
67 ))
68 })();
69
70 match &result {
71 Ok(_) => obs::record_flow_outcome(KIND, FlowOutcome::Success),
72 Err(_) => obs::record_flow_outcome(KIND, FlowOutcome::Failure),
73 }
74 result
75 }
76
77 pub async fn exchange_code(
87 &self,
88 session: AuthorizationSession,
89 authorization_code: impl AsRef<str>,
90 ) -> Result<TokenRecord> {
91 const KIND: FlowKind = FlowKind::AuthorizationCode;
92
93 let span = FlowSpan::new(KIND, "exchange_code");
94
95 obs::record_flow_outcome(KIND, FlowOutcome::Attempt);
96
97 let result = span
98 .instrument(async move {
99 self.ensure_authorization_code_supported()?;
100 let (tenant, principal, requested_scope, redirect_uri, pkce) =
101 session.into_exchange_parts();
102 let mut family = TokenFamily::new(tenant, principal);
103
104 family.provider = Some(self.descriptor.id.clone());
105
106 let facade: BasicFacade<C, M> = BasicFacade::from_descriptor(
107 &self.descriptor,
108 &self.client_id,
109 self.client_secret.as_deref(),
110 Some(&redirect_uri),
111 self.http_client.clone(),
112 self.transport_mapper.clone(),
113 )?;
114 let record = facade
115 .exchange_authorization_code(
116 self.strategy.as_ref(),
117 family,
118 authorization_code.as_ref(),
119 &pkce.verifier,
120 &requested_scope,
121 &redirect_uri,
122 )
123 .await?;
124
125 <dyn BrokerStore>::save(self.store.as_ref(), record.clone())
126 .await
127 .map_err(Error::from)?;
128
129 Ok(record)
130 })
131 .await;
132
133 match &result {
134 Ok(_) => obs::record_flow_outcome(KIND, FlowOutcome::Success),
135 Err(_) => obs::record_flow_outcome(KIND, FlowOutcome::Failure),
136 }
137
138 result
139 }
140
141 fn ensure_authorization_code_supported(&self) -> Result<()> {
142 if self.descriptor.supports(GrantType::AuthorizationCode) {
143 Ok(())
144 } else {
145 Err(ConfigError::UnsupportedGrant {
146 descriptor: self.descriptor.id.to_string(),
147 grant: "authorization_code",
148 }
149 .into())
150 }
151 }
152}