Skip to main content

mas_oidc_client/requests/
token.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 Token endpoint.
9
10use chrono::{DateTime, Utc};
11use http::header::ACCEPT;
12use mas_http::RequestBuilderExt;
13use mime::APPLICATION_JSON;
14use oauth2_types::requests::{AccessTokenRequest, AccessTokenResponse};
15use rand::RngExt;
16use url::Url;
17
18use crate::{
19    error::{ResponseExt, TokenRequestError},
20    types::client_credentials::ClientCredentials,
21};
22
23/// Request an access token.
24///
25/// # Arguments
26///
27/// * `http_client` - The reqwest client to use for making HTTP requests.
28///
29/// * `client_credentials` - The credentials obtained when registering the
30///   client.
31///
32/// * `token_endpoint` - The URL of the issuer's Token endpoint.
33///
34/// * `request` - The request to make at the Token endpoint.
35///
36/// * `now` - The current time.
37///
38/// * `rng` - A random number generator.
39///
40/// # Errors
41///
42/// Returns an error if the request fails or the response is invalid.
43#[tracing::instrument(skip_all, fields(token_endpoint, request))]
44pub async fn request_access_token(
45    http_client: &reqwest::Client,
46    client_credentials: ClientCredentials,
47    token_endpoint: &Url,
48    request: AccessTokenRequest,
49    now: DateTime<Utc>,
50    rng: &mut impl RngExt,
51) -> Result<AccessTokenResponse, TokenRequestError> {
52    tracing::debug!(?request, "Requesting access token...");
53
54    let token_request = http_client
55        .post(token_endpoint.as_str())
56        .header(ACCEPT, APPLICATION_JSON.as_ref());
57
58    let token_response = client_credentials
59        .authenticated_form(token_request, &request, now, rng)?
60        .send_traced()
61        .await?
62        .error_from_oauth2_error_response()
63        .await?
64        .json()
65        .await?;
66
67    Ok(token_response)
68}