From fc0c516eebbf35c2562036f808401cafd4565820 Mon Sep 17 00:00:00 2001
From: Emmanuel Gautier <git@emmanuelgautier.fr>
Date: Fri, 15 Mar 2024 16:58:56 +0100
Subject: [PATCH] feat: add token introspection

---
 baffao-core/src/oauth/client.rs | 28 +++++++++++++++++++++++-----
 baffao-core/src/oauth/mod.rs    |  4 ++++
 2 files changed, 27 insertions(+), 5 deletions(-)

diff --git a/baffao-core/src/oauth/client.rs b/baffao-core/src/oauth/client.rs
index 4eb9f93..18f8731 100644
--- a/baffao-core/src/oauth/client.rs
+++ b/baffao-core/src/oauth/client.rs
@@ -1,9 +1,6 @@
 use anyhow::{Context, Error};
 use oauth2::{
-    basic::{BasicClient, BasicTokenType},
-    reqwest::async_http_client,
-    AuthType, AuthUrl, AuthorizationCode, ClientId, ClientSecret, CsrfToken, EmptyExtraTokenFields,
-    PkceCodeChallenge, PkceCodeVerifier, RedirectUrl, Scope, StandardTokenResponse, TokenUrl,
+    basic::{BasicClient, BasicTokenType}, reqwest::async_http_client, AccessToken, AuthType, AuthUrl, AuthorizationCode, ClientId, ClientSecret, CsrfToken, EmptyExtraTokenFields, IntrospectionUrl, PkceCodeChallenge, PkceCodeVerifier, RedirectUrl, Scope, StandardTokenIntrospectionResponse, StandardTokenResponse, TokenUrl
 };
 use reqwest::Url;
 
@@ -32,7 +29,7 @@ impl OAuthClient {
         let token_endpoint =
             TokenUrl::new(config.token_endpoint.clone()).context("Failed to parse token url")?;
 
-        let client = BasicClient::new(
+        let mut client = BasicClient::new(
             ClientId::new(config.client_id.clone()),
             Some(ClientSecret::new(config.client_secret.clone())),
             auth_url,
@@ -41,6 +38,12 @@ impl OAuthClient {
         .set_auth_type(AuthType::RequestBody)
         .set_redirect_uri(redirect_uri);
 
+        if let Some(introspection_endpoint) = &config.introspection_endpoint {
+            let introspection_endpoint = IntrospectionUrl::new(introspection_endpoint.clone())
+                .context("Failed to parse introspection url")?;
+            client = client.set_introspection_uri(introspection_endpoint);
+        }
+
         Ok(Self { config, client })
     }
 
@@ -87,4 +90,19 @@ impl OAuthClient {
 
         Ok(response.unwrap())
     }
+
+    pub async fn introspect_token(
+        &self,
+        token: String,
+    ) -> Result<StandardTokenIntrospectionResponse<EmptyExtraTokenFields, BasicTokenType>, Error> {
+        let response = self
+            .client
+            .introspect(&AccessToken::new(token))?
+            .request_async(async_http_client)
+            .await?;
+
+        // TODO: configure introspection request depending on auth method
+
+        Ok(response)
+    }
 }
diff --git a/baffao-core/src/oauth/mod.rs b/baffao-core/src/oauth/mod.rs
index 9eb7c16..82c1545 100644
--- a/baffao-core/src/oauth/mod.rs
+++ b/baffao-core/src/oauth/mod.rs
@@ -19,4 +19,8 @@ pub struct OAuthConfig {
     pub token_endpoint: String,
     pub redirect_uri: Option<String>,
     pub default_scopes: Option<Vec<String>>,
+
+    pub introspection_endpoint: Option<String>,
+    pub introspection_endpoint_auth_methods_supported: Option<Vec<String>>,
+    pub introspection_endpoint_auth_signing_alg_values_supported: Option<Vec<String>>,
 }