Refresh an OIDC token using the `refresh_token` grant. Preserves the existing refresh token if the server does not return a new one (per OAuth 2.0 spec, the refresh response may omit `refresh_token`).
(
bundle: &OidcTokenBundle,
insecure: bool,
)
| 230 | /// Preserves the existing refresh token if the server does not return a new |
| 231 | /// one (per OAuth 2.0 spec, the refresh response may omit `refresh_token`). |
| 232 | pub async fn oidc_refresh_token( |
| 233 | bundle: &OidcTokenBundle, |
| 234 | insecure: bool, |
| 235 | ) -> Result<OidcTokenBundle> { |
| 236 | let refresh_token = bundle.refresh_token.as_deref().ok_or_else(|| { |
| 237 | miette::miette!( |
| 238 | "no refresh token available — re-authenticate with: openshell gateway login" |
| 239 | ) |
| 240 | })?; |
| 241 | |
| 242 | let discovery = discover(&bundle.issuer, insecure).await?; |
| 243 | |
| 244 | let client = BasicClient::new(ClientId::new(bundle.client_id.clone())) |
| 245 | .set_token_uri(TokenUrl::new(discovery.token_endpoint).into_diagnostic()?); |
| 246 | |
| 247 | let http = http_client(insecure); |
| 248 | let token_response = client |
| 249 | .exchange_refresh_token(&RefreshToken::new(refresh_token.to_string())) |
| 250 | .request_async(&http) |
| 251 | .await |
| 252 | .map_err(|e| miette::miette!("token refresh failed: {e}"))?; |
| 253 | |
| 254 | let mut refreshed = |
| 255 | bundle_from_oauth2_response(&token_response, &bundle.issuer, &bundle.client_id); |
| 256 | if refreshed.refresh_token.is_none() { |
| 257 | refreshed.refresh_token.clone_from(&bundle.refresh_token); |
| 258 | } |
| 259 | Ok(refreshed) |
| 260 | } |
| 261 | |
| 262 | /// Ensure we have a valid OIDC token for the given gateway, refreshing if needed. |
| 263 | /// |
no test coverage detected