···634634 .unwrap()
635635 .expect("token must be found on first use");
636636637637- assert_eq!(row.client_id, "https://app.example.com/client-metadata.json");
637637+ assert_eq!(
638638+ row.client_id,
639639+ "https://app.example.com/client-metadata.json"
640640+ );
638641 assert_eq!(row.scope, "com.atproto.refresh");
639642 assert_eq!(row.jkt.as_deref(), Some("test-jkt-thumbprint"));
640643···642645 let second = consume_oauth_refresh_token(&pool, "consume-test-token-hash")
643646 .await
644647 .unwrap();
645645- assert!(second.is_none(), "consumed token must not be found again (AC4.2)");
648648+ assert!(
649649+ second.is_none(),
650650+ "consumed token must not be found again (AC4.2)"
651651+ );
646652 }
647653648654 #[tokio::test]
···674680 let result = consume_oauth_refresh_token(&pool, "expired-hash")
675681 .await
676682 .unwrap();
677677- assert!(result.is_none(), "expired refresh token must return None (AC4.3)");
683683+ assert!(
684684+ result.is_none(),
685685+ "expired refresh token must return None (AC4.3)"
686686+ );
678687 }
679688680689 #[tokio::test]
681690 async fn consume_oauth_refresh_token_returns_none_for_unknown_token() {
682691 let pool = test_pool().await;
683683- let result = consume_oauth_refresh_token(&pool, "nonexistent-hash").await.unwrap();
692692+ let result = consume_oauth_refresh_token(&pool, "nonexistent-hash")
693693+ .await
694694+ .unwrap();
684695 assert!(result.is_none());
685696 }
686697}
+59-42
crates/relay/src/routes/oauth_token.rs
···2121use crate::auth::{
2222 cleanup_expired_nonces, issue_nonce, validate_dpop_for_token_endpoint, DpopTokenEndpointError,
2323};
2424-use crate::db::oauth::{
2525- consume_oauth_refresh_token, store_oauth_refresh_token,
2626-};
2424+use crate::db::oauth::{consume_oauth_refresh_token, store_oauth_refresh_token};
2725use crate::routes::token::generate_token;
28262927// ── Request / response types ──────────────────────────────────────────────────
···183181184182 match grant_type {
185183 "authorization_code" => handle_authorization_code(&state, &headers, form).await,
186186- "refresh_token" => {
187187- handle_refresh_token(&state, &headers, form).await
188188- }
184184+ "refresh_token" => handle_refresh_token(&state, &headers, form).await,
189185 _ => OAuthTokenError::new(
190186 "unsupported_grant_type",
191187 "grant_type must be authorization_code or refresh_token",
···392388 state.config.public_url.trim_end_matches('/')
393389 );
394390395395- let jkt = match validate_dpop_for_token_endpoint(
396396- &dpop_token,
397397- "POST",
398398- &token_url,
399399- &state.dpop_nonces,
400400- )
401401- .await
402402- {
403403- Ok(jkt) => jkt,
404404- Err(DpopTokenEndpointError::MissingHeader) => {
405405- return OAuthTokenError::new("invalid_dpop_proof", "DPoP header required")
391391+ let jkt =
392392+ match validate_dpop_for_token_endpoint(&dpop_token, "POST", &token_url, &state.dpop_nonces)
393393+ .await
394394+ {
395395+ Ok(jkt) => jkt,
396396+ Err(DpopTokenEndpointError::MissingHeader) => {
397397+ return OAuthTokenError::new("invalid_dpop_proof", "DPoP header required")
398398+ .into_response();
399399+ }
400400+ Err(DpopTokenEndpointError::InvalidProof(msg)) => {
401401+ return OAuthTokenError::new("invalid_dpop_proof", msg).into_response();
402402+ }
403403+ Err(DpopTokenEndpointError::UseNonce(fresh_nonce)) => {
404404+ return OAuthTokenError::with_nonce(
405405+ "use_dpop_nonce",
406406+ "DPoP nonce required",
407407+ fresh_nonce,
408408+ )
406409 .into_response();
407407- }
408408- Err(DpopTokenEndpointError::InvalidProof(msg)) => {
409409- return OAuthTokenError::new("invalid_dpop_proof", msg).into_response();
410410- }
411411- Err(DpopTokenEndpointError::UseNonce(fresh_nonce)) => {
412412- return OAuthTokenError::with_nonce(
413413- "use_dpop_nonce",
414414- "DPoP nonce required",
415415- fresh_nonce,
416416- )
417417- .into_response();
418418- }
419419- };
410410+ }
411411+ };
420412421413 // Hash the presented refresh token for DB lookup.
422414 let token_hash = crate::routes::token::sha256_hex(
···451443 }
452444453445 // Issue new ES256 access token.
454454- let access_token =
455455- match issue_access_token(&state.oauth_signing_keypair, &stored.did, &stored.scope, &jkt) {
456456- Ok(t) => t,
457457- Err(e) => return e.into_response(),
458458- };
446446+ let access_token = match issue_access_token(
447447+ &state.oauth_signing_keypair,
448448+ &stored.did,
449449+ &stored.scope,
450450+ &jkt,
451451+ ) {
452452+ Ok(t) => t,
453453+ Err(e) => return e.into_response(),
454454+ };
459455460456 // Generate and store new refresh token (rotation: old token already deleted above).
461457 let new_refresh = generate_token();
···507503508504 use crate::app::{app, test_state, AppState};
509505 use crate::auth::issue_nonce;
510510- use crate::db::oauth::{register_oauth_client, store_authorization_code, store_oauth_refresh_token};
506506+ use crate::db::oauth::{
507507+ register_oauth_client, store_authorization_code, store_oauth_refresh_token,
508508+ };
511509 use crate::routes::token::generate_token;
512510513511 // ── DPoP proof test helpers ───────────────────────────────────────────────
···12181216 .await
12191217 .unwrap();
1220121812211221- assert_eq!(resp.status(), StatusCode::OK, "valid rotation must return 200");
12191219+ assert_eq!(
12201220+ resp.status(),
12211221+ StatusCode::OK,
12221222+ "valid rotation must return 200"
12231223+ );
12221224 assert!(
12231225 resp.headers().contains_key("DPoP-Nonce"),
12241226 "success response must include DPoP-Nonce header"
12251227 );
1226122812271229 let json = json_body(resp).await;
12281228- assert!(json["access_token"].is_string(), "access_token must be present");
12301230+ assert!(
12311231+ json["access_token"].is_string(),
12321232+ "access_token must be present"
12331233+ );
12291234 assert_eq!(json["token_type"], "DPoP");
12301235 assert_eq!(json["expires_in"], 300);
12311231- assert!(json["refresh_token"].is_string(), "rotated refresh_token must be present");
12361236+ assert!(
12371237+ json["refresh_token"].is_string(),
12381238+ "rotated refresh_token must be present"
12391239+ );
1232124012331241 // Rotated token must differ from the original.
12341242 let new_rt = json["refresh_token"].as_str().unwrap();
12351243 assert_ne!(
12361236- new_rt, plaintext.as_str(),
12441244+ new_rt,
12451245+ plaintext.as_str(),
12371246 "rotated refresh token must differ from original"
12381247 );
12391248 }
···12651274 .oneshot(post_token_with_dpop(&body, &dpop1))
12661275 .await
12671276 .unwrap();
12681268- assert_eq!(first_resp.status(), StatusCode::OK, "first use must succeed");
12771277+ assert_eq!(
12781278+ first_resp.status(),
12791279+ StatusCode::OK,
12801280+ "first use must succeed"
12811281+ );
1269128212701283 // Second use of the same original token: must return invalid_grant.
12711284 let nonce2 = issue_nonce(&state.dpop_nonces).await;
···12811294 .await
12821295 .unwrap();
1283129612841284- assert_eq!(resp2.status(), StatusCode::BAD_REQUEST, "second use must return 400");
12971297+ assert_eq!(
12981298+ resp2.status(),
12991299+ StatusCode::BAD_REQUEST,
13001300+ "second use must return 400"
13011301+ );
12851302 let json = json_body(resp2).await;
12861303 assert_eq!(
12871304 json["error"], "invalid_grant",