Skip to main content

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}