Complete the authorization flow by exchanging the authorization code for tokens.
(&self, code: &str, state: &str)
| 167 | /// Complete the authorization flow by exchanging the authorization code |
| 168 | /// for tokens. |
| 169 | pub async fn finish_auth(&self, code: &str, state: &str) -> Result<(), OAuthError> { |
| 170 | // Recover verifier + expected state. |
| 171 | let (verifier_secret, expected_state) = { |
| 172 | let pending = self.pending.read().await; |
| 173 | match pending.as_ref() { |
| 174 | Some(p) => (p.pkce_verifier.clone(), p.csrf_state.clone()), |
| 175 | None => { |
| 176 | let entry = auth::get(&self.mcp_name) |
| 177 | .await |
| 178 | .ok_or(OAuthError::NoPendingAuth)?; |
| 179 | let v = entry.code_verifier.ok_or(OAuthError::NoPendingAuth)?; |
| 180 | let s = entry.oauth_state.ok_or(OAuthError::NoPendingAuth)?; |
| 181 | (v, s) |
| 182 | } |
| 183 | } |
| 184 | }; |
| 185 | |
| 186 | if state != expected_state { |
| 187 | return Err(OAuthError::StateMismatch); |
| 188 | } |
| 189 | |
| 190 | let (client_id, client_secret, auth_url, token_url, redirect_url) = self.parsed_config()?; |
| 191 | |
| 192 | let mut client = oauth2::basic::BasicClient::new(client_id) |
| 193 | .set_auth_uri(auth_url) |
| 194 | .set_token_uri(token_url) |
| 195 | .set_redirect_uri(redirect_url); |
| 196 | |
| 197 | if let Some(secret) = client_secret { |
| 198 | client = client.set_client_secret(secret); |
| 199 | } |
| 200 | |
| 201 | let http_client = reqwest::Client::new(); |
| 202 | |
| 203 | let token_result = client |
| 204 | .exchange_code(AuthorizationCode::new(code.to_string())) |
| 205 | .set_pkce_verifier(PkceCodeVerifier::new(verifier_secret)) |
| 206 | .request_async(&http_client) |
| 207 | .await |
| 208 | .map_err(|e| OAuthError::TokenExchange(e.to_string()))?; |
| 209 | |
| 210 | self.save_token_result(&token_result).await?; |
| 211 | |
| 212 | // Clean up transient state. |
| 213 | auth::clear_code_verifier(&self.mcp_name).await.ok(); |
| 214 | auth::clear_oauth_state(&self.mcp_name).await.ok(); |
| 215 | { |
| 216 | let mut pending = self.pending.write().await; |
| 217 | *pending = None; |
| 218 | } |
| 219 | |
| 220 | Ok(()) |
| 221 | } |
| 222 | /// Refresh an expired access token using the stored refresh token. |
| 223 | pub async fn refresh_token(&self) -> Result<(), OAuthError> { |
| 224 | let entry = auth::get_for_url(&self.mcp_name, &self.server_url) |
nothing calls this directly
no test coverage detected