+3
-1
crates/jacquard-oauth/src/client.rs
+3
-1
crates/jacquard-oauth/src/client.rs
···
264
264
let client_data = ClientSessionData {
265
265
account_did: token_set.sub.clone(),
266
266
session_id: auth_req_info.state,
267
-
host_url: token_set.iss.clone(),
267
+
host_url: token_set.aud.clone(),
268
268
authserver_url: auth_req_info.authserver_url.to_cowstr(),
269
269
authserver_token_endpoint: auth_req_info.authserver_token_endpoint,
270
270
authserver_revocation_endpoint: auth_req_info.authserver_revocation_endpoint,
···
279
279
},
280
280
token_set,
281
281
};
282
+
283
+
dbg!(&client_data);
282
284
283
285
self.create_session(client_data).await
284
286
}
+1
-2
crates/jacquard-oauth/src/request.rs
+1
-2
crates/jacquard-oauth/src/request.rs
···
528
528
};
529
529
let auth_req_data = AuthRequestData {
530
530
state,
531
-
authserver_url: url::Url::parse(&metadata.server_metadata.issuer)
532
-
.expect("Failed to parse issuer URL"),
531
+
authserver_url: metadata.server_metadata.issuer.clone(),
533
532
account_did: None,
534
533
scopes,
535
534
request_uri: par_response.request_uri.to_cowstr().into_static(),
+4
-4
crates/jacquard-oauth/src/resolver.rs
+4
-4
crates/jacquard-oauth/src/resolver.rs
···
793
793
.await
794
794
.map_err(|e| ResolverError::transport(e))?;
795
795
if res.status() == StatusCode::OK {
796
-
let mut metadata = serde_json::from_slice::<OAuthAuthorizationServerMetadata>(res.body())?;
796
+
let metadata = serde_json::from_slice::<OAuthAuthorizationServerMetadata>(res.body())?;
797
797
// https://datatracker.ietf.org/doc/html/rfc8414#section-3.3
798
798
// Accept semantically equivalent issuer (normalize to the requested URL form)
799
799
if issuer_equivalent(&metadata.issuer, server.as_str()) {
800
-
metadata.issuer = server.as_str().into();
800
+
// if equivalent, keep the canonical form
801
801
Ok(metadata.into_static())
802
802
} else {
803
803
Err(ResolverError::authorization_server_metadata(
···
827
827
.await
828
828
.map_err(|e| ResolverError::transport(e))?;
829
829
if res.status() == StatusCode::OK {
830
-
let mut metadata = serde_json::from_slice::<OAuthProtectedResourceMetadata>(res.body())?;
830
+
let metadata = serde_json::from_slice::<OAuthProtectedResourceMetadata>(res.body())?;
831
831
// https://datatracker.ietf.org/doc/html/rfc8414#section-3.3
832
832
// Accept semantically equivalent resource URL (normalize to the requested URL form)
833
833
if issuer_equivalent(&metadata.resource, server.as_str()) {
834
-
metadata.resource = server.as_str().into();
834
+
// if equivalent, keep the canonical form
835
835
Ok(metadata.into_static())
836
836
} else {
837
837
Err(ResolverError::authorization_server_metadata(
+2
-3
crates/jacquard-oauth/src/session.rs
+2
-3
crates/jacquard-oauth/src/session.rs
···
22
22
use serde::{Deserialize, Serialize};
23
23
use smol_str::{SmolStr, format_smolstr};
24
24
use tokio::sync::Mutex;
25
-
use url::Url;
26
25
27
26
pub trait DpopDataSource {
28
27
fn key(&self) -> &Key;
···
148
147
pub state: CowStr<'s>,
149
148
150
149
// URL of the auth server (eg, PDS or entryway)
151
-
pub authserver_url: Url,
150
+
pub authserver_url: CowStr<'s>,
152
151
153
152
// If the flow started with an account identifier (DID or handle), it should be persisted, to verify against the initial token response.
154
153
#[serde(skip_serializing_if = "std::option::Option::is_none")]
···
186
185
pkce_verifier: self.pkce_verifier.into_static(),
187
186
dpop_data: self.dpop_data.into_static(),
188
187
state: self.state.into_static(),
189
-
authserver_url: self.authserver_url,
188
+
authserver_url: self.authserver_url.into_static(),
190
189
account_did: self.account_did.into_static(),
191
190
scopes: self.scopes.into_static(),
192
191
}
+13
-9
crates/jacquard/src/client/token.rs
+13
-9
crates/jacquard/src/client/token.rs
···
189
189
pub dpop_authserver_nonce: Option<String>,
190
190
}
191
191
192
-
impl From<AuthRequestData<'_>> for OAuthState {
193
-
fn from(value: AuthRequestData) -> Self {
194
-
OAuthState {
195
-
authserver_url: value.authserver_url,
192
+
impl TryFrom<AuthRequestData<'_>> for OAuthState {
193
+
type Error = url::ParseError;
194
+
195
+
fn try_from(value: AuthRequestData) -> Result<Self, Self::Error> {
196
+
Ok(OAuthState {
197
+
authserver_url: Url::parse(&value.authserver_url)?,
196
198
account_did: value.account_did.map(|s| s.to_string()),
197
199
scopes: value.scopes.into_iter().map(|s| s.to_string()).collect(),
198
200
request_uri: value.request_uri.to_string(),
···
204
206
dpop_key: value.dpop_data.dpop_key,
205
207
dpop_authserver_nonce: value.dpop_data.dpop_authserver_nonce.map(|s| s.to_string()),
206
208
state: value.state.to_string(),
207
-
}
209
+
})
208
210
}
209
211
}
210
212
211
213
impl From<OAuthState> for AuthRequestData<'_> {
212
214
fn from(value: OAuthState) -> Self {
213
215
AuthRequestData {
214
-
authserver_url: value.authserver_url,
216
+
authserver_url: value.authserver_url.to_cowstr(),
215
217
state: value.state.to_cowstr(),
216
218
account_did: value.account_did.map(|s| Did::from(s).into_static()),
217
219
authserver_revocation_endpoint: value
···
317
319
auth_req_info: &AuthRequestData<'_>,
318
320
) -> Result<(), SessionStoreError> {
319
321
let key = format!("authreq_{}", auth_req_info.state);
320
-
self.0
321
-
.set(key, StoredSession::OAuthState(auth_req_info.clone().into()))
322
-
.await?;
322
+
let state = auth_req_info
323
+
.clone()
324
+
.try_into()
325
+
.map_err(|e: url::ParseError| SessionStoreError::Other(Box::new(e)))?;
326
+
self.0.set(key, StoredSession::OAuthState(state)).await?;
323
327
Ok(())
324
328
}
325
329