Run the OIDC Client Credentials flow (for CI/automation). Reads `OPENSHELL_OIDC_CLIENT_SECRET` from the environment.
(
issuer: &str,
client_id: &str,
audience: Option<&str>,
scopes: Option<&str>,
insecure: bool,
)
| 185 | /// |
| 186 | /// Reads `OPENSHELL_OIDC_CLIENT_SECRET` from the environment. |
| 187 | pub async fn oidc_client_credentials_flow( |
| 188 | issuer: &str, |
| 189 | client_id: &str, |
| 190 | audience: Option<&str>, |
| 191 | scopes: Option<&str>, |
| 192 | insecure: bool, |
| 193 | ) -> Result<OidcTokenBundle> { |
| 194 | let client_secret = std::env::var("OPENSHELL_OIDC_CLIENT_SECRET").map_err(|_| { |
| 195 | miette::miette!( |
| 196 | "OPENSHELL_OIDC_CLIENT_SECRET environment variable is required for client credentials flow" |
| 197 | ) |
| 198 | })?; |
| 199 | |
| 200 | let discovery = discover(issuer, insecure).await?; |
| 201 | |
| 202 | let client = BasicClient::new(ClientId::new(client_id.to_string())) |
| 203 | .set_client_secret(ClientSecret::new(client_secret)) |
| 204 | .set_token_uri(TokenUrl::new(discovery.token_endpoint).into_diagnostic()?) |
| 205 | .set_auth_type(AuthType::RequestBody); |
| 206 | |
| 207 | let mut request = client.exchange_client_credentials(); |
| 208 | for scope in build_ci_scopes(scopes) { |
| 209 | request = request.add_scope(scope); |
| 210 | } |
| 211 | if let Some(aud) = audience { |
| 212 | request = request.add_extra_param("audience", aud); |
| 213 | } |
| 214 | |
| 215 | let http = http_client(insecure); |
| 216 | let token_response = request |
| 217 | .request_async(&http) |
| 218 | .await |
| 219 | .map_err(|e| miette::miette!("client credentials token exchange failed: {e}"))?; |
| 220 | |
| 221 | Ok(bundle_from_oauth2_response( |
| 222 | &token_response, |
| 223 | issuer, |
| 224 | client_id, |
| 225 | )) |
| 226 | } |
| 227 | |
| 228 | /// Refresh an OIDC token using the `refresh_token` grant. |
| 229 | /// |
no test coverage detected