Record metrics for OAuth 2.0 token requests

This commit is contained in:
Quentin Gliech
2025-03-26 16:53:29 +01:00
parent 2520aff67f
commit 6c94dc4874
2 changed files with 39 additions and 2 deletions

View File

@@ -4,7 +4,7 @@
// SPDX-License-Identifier: AGPL-3.0-only
// Please see LICENSE in the repository root for full details.
use std::sync::Arc;
use std::sync::{Arc, LazyLock};
use axum::{Json, extract::State, response::IntoResponse};
use axum_extra::typed_header::TypedHeader;
@@ -40,12 +40,23 @@ use oauth2_types::{
},
scope,
};
use opentelemetry::{Key, KeyValue, metrics::Counter};
use thiserror::Error;
use tracing::{debug, info};
use ulid::Ulid;
use super::{generate_id_token, generate_token_pair};
use crate::{BoundActivityTracker, impl_from_error_for_route};
use crate::{BoundActivityTracker, METER, impl_from_error_for_route};
static TOKEN_REQUEST_COUNTER: LazyLock<Counter<u64>> = LazyLock::new(|| {
METER
.u64_counter("mas.oauth2.token_request")
.with_description("How many OAuth 2.0 token requests have gone through")
.with_unit("{request}")
.build()
});
const GRANT_TYPE: Key = Key::from_static_str("grant_type");
const RESULT: Key = Key::from_static_str("successful");
#[derive(Debug, Error)]
pub(crate) enum RouteError {
@@ -136,6 +147,8 @@ impl IntoResponse for RouteError {
fn into_response(self) -> axum::response::Response {
let event_id = sentry::capture_error(&self);
TOKEN_REQUEST_COUNTER.add(1, &[KeyValue::new(RESULT, "error")]);
let response = match self {
Self::Internal(_)
| Self::NoSuchBrowserSession
@@ -254,6 +267,8 @@ pub(crate) async fn post(
let form = client_authorization.form.ok_or(RouteError::BadRequest)?;
let grant_type = form.grant_type();
let (reply, repo) = match form {
AccessTokenRequest::AuthorizationCode(grant) => {
authorization_code_grant(
@@ -321,6 +336,14 @@ pub(crate) async fn post(
repo.save().await?;
TOKEN_REQUEST_COUNTER.add(
1,
&[
KeyValue::new(GRANT_TYPE, grant_type),
KeyValue::new(RESULT, "success"),
],
);
let mut headers = HeaderMap::new();
headers.typed_insert(CacheControl::new().with_no_store());
headers.typed_insert(Pragma::no_cache());

View File

@@ -638,6 +638,20 @@ pub enum AccessTokenRequest {
Unsupported,
}
impl AccessTokenRequest {
/// Returns the string representation of the grant type of the request.
#[must_use]
pub fn grant_type(&self) -> &'static str {
match self {
Self::AuthorizationCode(_) => "authorization_code",
Self::RefreshToken(_) => "refresh_token",
Self::ClientCredentials(_) => "client_credentials",
Self::DeviceCode(_) => "urn:ietf:params:oauth:grant-type:device_code",
Self::Unsupported => "unsupported",
}
}
}
/// A successful response from the [Token Endpoint].
///
/// [Token Endpoint]: https://www.rfc-editor.org/rfc/rfc6749#section-3.2