From 2599113f88dc23514cb48caa8f0c5b7e98792a23 Mon Sep 17 00:00:00 2001 From: Bill Fraser Date: Thu, 2 May 2024 14:51:44 -0700 Subject: [PATCH 1/2] fix for oauth2 refresh tokens obtained using client secret They are different from tokens obtained with the PKCE flow, and need the client secret to be provided again along with the refresh token when obtaining new tokens. --- Cargo.toml | 2 +- RELEASE_NOTES.md | 6 ++++++ src/oauth2.rs | 46 ++++++++++++++++++++++++++++++++++------------ 3 files changed, 41 insertions(+), 13 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 942bb4c..0d3236f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "dropbox-sdk" -version = "0.18.0" +version = "0.18.1" authors = ["Bill Fraser "] edition = "2018" description = "Rust bindings to the Dropbox API, generated by Stone from the official spec." diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 9795da0..2bcac22 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,3 +1,9 @@ +# v0.18.1 +2024-05-02 +* fixed bug when using oauth2 refresh tokens using client secret instead of PKCE: + * See https://github.com/dropbox/dropbox-sdk-rust/issues/151 for details + * New function Authorize::from_client_secret_refresh_token() should be used for any refresh tokens previously obtained using this flow + # v0.18.0 2024-01-12 * MSRV raised to 1.65.0 diff --git a/src/oauth2.rs b/src/oauth2.rs index ce08883..179470f 100644 --- a/src/oauth2.rs +++ b/src/oauth2.rs @@ -293,6 +293,7 @@ enum AuthorizationState { }, Refresh { refresh_token: String, + client_secret: Option, }, AccessToken { client_secret: Option, @@ -365,14 +366,34 @@ impl Authorization { }) } - /// Recreate the authorization from a refresh token. + /// Recreate the authorization from a refresh token obtained using the [`Oauth2Type::PKCE`] + /// flow. pub fn from_refresh_token( client_id: String, refresh_token: String, ) -> Self { Self { client_id, - state: AuthorizationState::Refresh { refresh_token }, + state: AuthorizationState::Refresh { + refresh_token, + client_secret: None, + }, + } + } + + /// Recreate the authorization from a refresh token obtained using the + /// [`Oauth2Type::AuthorizationCode`] flow. This requires the client secret as well. + pub fn from_client_secret_refresh_token( + client_id: String, + client_secret: String, + refresh_token: String, + ) -> Self { + Self { + client_id, + state: AuthorizationState::Refresh { + refresh_token, + client_secret: Some(client_secret), + }, } } @@ -431,8 +452,11 @@ impl Authorization { auth_code = Some(code); redirect_uri = uri; } - AuthorizationState::Refresh { refresh_token: refresh } => { + AuthorizationState::Refresh { refresh_token: refresh, client_secret: secret } => { refresh_token = Some(refresh); + if let Some(secret) = secret { + client_secret = Some(secret); + } } } @@ -448,14 +472,12 @@ impl Authorization { params.append_pair("client_id", &self.client_id); - if refresh_token.is_none() { - if let Some(pkce) = pkce_code { - params.append_pair("code_verifier", &pkce); - } else { - params.append_pair( - "client_secret", - client_secret.as_ref().expect("need either PKCE code or client secret")); - } + if let Some(client_secret) = client_secret.as_deref() { + params.append_pair("client_secret", client_secret); + } + + if let Some(pkce) = pkce_code { + params.append_pair("code_verifier", &pkce); } if let Some(value) = redirect_uri { @@ -499,7 +521,7 @@ impl Authorization { match refresh_token { Some(refresh) => { - self.state = AuthorizationState::Refresh { refresh_token: refresh }; + self.state = AuthorizationState::Refresh { refresh_token: refresh, client_secret }; } None if !matches!(self.state, AuthorizationState::Refresh {..}) => { self.state = AuthorizationState::AccessToken { From 522fe7880731d4c61e9641b22ea0438845743907 Mon Sep 17 00:00:00 2001 From: Bill Fraser Date: Mon, 6 May 2024 11:18:21 -0700 Subject: [PATCH 2/2] adjust readme --- RELEASE_NOTES.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 2bcac22..4cd75fb 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -1,8 +1,9 @@ # v0.18.1 -2024-05-02 +2024-05-06 * fixed bug when using oauth2 refresh tokens using client secret instead of PKCE: * See https://github.com/dropbox/dropbox-sdk-rust/issues/151 for details * New function Authorize::from_client_secret_refresh_token() should be used for any refresh tokens previously obtained using this flow + * Thanks to Peerat Vichivanives for reporting and testing the fix # v0.18.0 2024-01-12