@@ -1687,7 +1687,10 @@ impl AuthorizationManager {
16871687 debug ! ( "refresh token present, attempting refresh" ) ;
16881688
16891689 let refresh_token_value = RefreshToken :: new ( refresh_token. secret ( ) . to_string ( ) ) ;
1690- let mut refresh_request = oauth_client. exchange_refresh_token ( & refresh_token_value) ;
1690+ let mut refresh_request = oauth_client
1691+ . exchange_refresh_token ( & refresh_token_value)
1692+ // RFC 8707: the resource indicator is required on token requests, including refreshes
1693+ . add_extra_param ( "resource" , self . base_url . to_string ( ) ) ;
16911694 let mut refresh_scopes = stored_credentials. granted_scopes ;
16921695 self . add_offline_access_if_supported ( & mut refresh_scopes) ;
16931696 for scope in refresh_scopes {
@@ -5482,6 +5485,42 @@ mod tests {
54825485 assert_eq ! ( scope_parts, vec![ "read" , "write" ] ) ;
54835486 }
54845487
5488+ #[ tokio:: test]
5489+ async fn refresh_token_includes_resource_parameter ( ) {
5490+ let ( base_url, captured) = start_token_server ( ) . await ;
5491+
5492+ let mut manager = manager_with_metadata ( Some ( AuthorizationMetadata {
5493+ authorization_endpoint : format ! ( "{}/authorize" , base_url) ,
5494+ token_endpoint : format ! ( "{}/token" , base_url) ,
5495+ ..Default :: default ( )
5496+ } ) )
5497+ . await ;
5498+ manager. configure_client ( test_client_config ( ) ) . unwrap ( ) ;
5499+
5500+ let stored = StoredCredentials {
5501+ client_id : "my-client" . to_string ( ) ,
5502+ token_response : Some ( make_token_response_with_refresh (
5503+ "old-token" ,
5504+ "my-refresh-token" ,
5505+ ) ) ,
5506+ granted_scopes : vec ! [ ] ,
5507+ token_received_at : Some ( AuthorizationManager :: now_epoch_secs ( ) ) ,
5508+ } ;
5509+ manager. credential_store . save ( stored) . await . unwrap ( ) ;
5510+
5511+ manager. refresh_token ( ) . await . unwrap ( ) ;
5512+
5513+ let body = captured. lock ( ) . unwrap ( ) . take ( ) . unwrap ( ) ;
5514+ let params: std:: collections:: HashMap < _ , _ > = url:: form_urlencoded:: parse ( body. as_bytes ( ) )
5515+ . into_owned ( )
5516+ . collect ( ) ;
5517+ assert_eq ! (
5518+ params. get( "resource" ) . map( String :: as_str) ,
5519+ Some ( "http://localhost/" ) ,
5520+ "refresh requests must carry the RFC 8707 resource parameter, got body: {body}"
5521+ ) ;
5522+ }
5523+
54855524 #[ tokio:: test]
54865525 async fn refresh_token_adds_offline_access_when_as_supports_it ( ) {
54875526 let ( base_url, captured) = start_token_server ( ) . await ;
0 commit comments