mas_oidc_client/requests/client_credentials.rs
1// Copyright 2025, 2026 Element Creations Ltd.
2// Copyright 2024, 2025 New Vector Ltd.
3// Copyright 2022-2024 Kévin Commaille.
4//
5// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
6// Please see LICENSE files in the repository root for full details.
7
8//! Requests for the [Client Credentials flow].
9//!
10//! [Client Credentials flow]: https://www.rfc-editor.org/rfc/rfc6749#section-4.4
11
12use chrono::{DateTime, Utc};
13use oauth2_types::{
14 requests::{AccessTokenRequest, AccessTokenResponse, ClientCredentialsGrant},
15 scope::Scope,
16};
17use rand::RngExt;
18use url::Url;
19
20use crate::{
21 error::TokenRequestError, requests::token::request_access_token,
22 types::client_credentials::ClientCredentials,
23};
24
25/// Exchange an authorization code for an access token.
26///
27/// This should be used as the first step for logging in, and to request a
28/// token with a new scope.
29///
30/// # Arguments
31///
32/// * `http_client` - The reqwest client to use for making HTTP requests.
33///
34/// * `client_credentials` - The credentials obtained when registering the
35/// client.
36///
37/// * `token_endpoint` - The URL of the issuer's Token endpoint.
38///
39/// * `scope` - The scope to authorize.
40///
41/// * `now` - The current time.
42///
43/// * `rng` - A random number generator.
44///
45/// # Errors
46///
47/// Returns an error if the request fails or the response is invalid.
48#[tracing::instrument(skip_all, fields(token_endpoint))]
49pub async fn access_token_with_client_credentials(
50 http_client: &reqwest::Client,
51 client_credentials: ClientCredentials,
52 token_endpoint: &Url,
53 scope: Option<Scope>,
54 now: DateTime<Utc>,
55 rng: &mut impl RngExt,
56) -> Result<AccessTokenResponse, TokenRequestError> {
57 tracing::debug!("Requesting access token with client credentials...");
58
59 request_access_token(
60 http_client,
61 client_credentials,
62 token_endpoint,
63 AccessTokenRequest::ClientCredentials(ClientCredentialsGrant { scope }),
64 now,
65 rng,
66 )
67 .await
68}