Skip to content

Commit 96f7110

Browse files
feat: add token introspection
1 parent a1a61fe commit 96f7110

File tree

8 files changed

+62
-8
lines changed

8 files changed

+62
-8
lines changed

baffao-proxy/config/example.toml

+2-1
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,6 @@ client_id = "client_id"
66
client_secret = "client_secret"
77
authorization_redirect_uri = "http://127.0.0.1:3000/oauth/callback"
88
authorization_endpoint = "http://127.0.0.1:4444/oauth2/auth"
9-
token_endpoint = "http://127.0.0.1/oauth2/token"
9+
token_endpoint = "http://127.0.0.1:3000/oauth2/token"
10+
introspection_endpoint = "http://127.0.0.1:3000/oauth2/introspect"
1011
redirect_uri = "http://127.0.0.1:3000/"

baffao-proxy/src/main.rs

+1
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ async fn main() {
4646
let app = Router::new()
4747
.route("/oauth/authorize", get(oauth::authorize))
4848
.route("/oauth/callback", get(oauth::callback))
49+
.route("/oauth/introspect", get(oauth::introspect))
4950
.route("/session", get(session::get_session))
5051
.fallback(any(proxy::handler))
5152
.layer(

baffao-proxy/src/oauth.rs

+7
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,10 @@ pub async fn callback(
3131

3232
(updated_jar, Redirect::temporary(&url.to_string()))
3333
}
34+
35+
pub async fn introspect(
36+
jar: CookieJar,
37+
State(handler): State<OAuthHttpHandler>,
38+
) -> impl IntoResponse {
39+
handler.introspect(jar).await;
40+
}

baffao/src/handlers/introspect.rs

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
use axum_extra::extract::CookieJar;
2+
use reqwest::StatusCode;
3+
4+
use crate::oauth::{IntrospectionTokenResponse, OAuthHttpHandler};
5+
6+
pub async fn oauth2_introspect(
7+
handler: OAuthHttpHandler,
8+
jar: CookieJar,
9+
) -> (CookieJar, StatusCode, Option<IntrospectionTokenResponse>) {
10+
let (updated_jar, response) = handler.introspect(jar).await;
11+
12+
(updated_jar, response.to_owned().map_or_else(|| StatusCode::UNAUTHORIZED, |_| StatusCode::OK), response)
13+
}

baffao/src/handlers/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
pub use authorize::{oauth2_authorize, AuthorizationQuery};
22
pub use callback::{oauth2_callback, AuthorizationCallbackQuery};
33
pub use get_session::get_session_from_cookie;
4+
pub use introspect::oauth2_introspect;
45
pub use proxy::proxy;
56

67
mod authorize;
78
mod callback;
89
mod get_session;
10+
mod introspect;
911
mod proxy;

baffao/src/oauth/client.rs

+23-5
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
use anyhow::{Context, Error};
22
use oauth2::{
3-
basic::BasicClient, reqwest::async_http_client, AuthType, AuthUrl, AuthorizationCode, ClientId,
4-
ClientSecret, CsrfToken, PkceCodeChallenge, PkceCodeVerifier, RedirectUrl, RefreshToken, Scope,
5-
TokenUrl,
3+
basic::BasicClient, reqwest::async_http_client, AccessToken as OAuthAccessToken, AuthType, AuthUrl, AuthorizationCode, ClientId, ClientSecret, CsrfToken, IntrospectionUrl, PkceCodeChallenge, PkceCodeVerifier, RedirectUrl, RefreshToken, Scope, TokenUrl
64
};
75
use reqwest::Url;
86

9-
use super::{AccessToken, OAuthConfig};
7+
use super::{AccessToken, IntrospectionTokenResponse, OAuthConfig};
108

119
pub struct OAuthClient {
1210
config: OAuthConfig,
@@ -31,7 +29,7 @@ impl OAuthClient {
3129
let token_endpoint =
3230
TokenUrl::new(config.token_endpoint.clone()).context("Failed to parse token url")?;
3331

34-
let client = BasicClient::new(
32+
let mut client = BasicClient::new(
3533
ClientId::new(config.client_id.clone()),
3634
Some(ClientSecret::new(config.client_secret.clone())),
3735
auth_url,
@@ -40,6 +38,12 @@ impl OAuthClient {
4038
.set_auth_type(AuthType::RequestBody)
4139
.set_redirect_uri(redirect_uri);
4240

41+
if let Some(introspection_endpoint) = &config.introspection_endpoint {
42+
let introspection_endpoint = IntrospectionUrl::new(introspection_endpoint.clone())
43+
.context("Failed to parse introspection url")?;
44+
client = client.set_introspection_uri(introspection_endpoint);
45+
}
46+
4347
Ok(Self { config, client })
4448
}
4549

@@ -105,4 +109,18 @@ impl OAuthClient {
105109

106110
Ok(response.unwrap())
107111
}
112+
113+
pub async fn introspect_token(
114+
&self,
115+
token: String,
116+
) -> Result<IntrospectionTokenResponse, Error>
117+
{
118+
let response = self
119+
.client
120+
.introspect(&OAuthAccessToken::new(token))?
121+
.request_async(async_http_client)
122+
.await?;
123+
124+
Ok(response)
125+
}
108126
}

baffao/src/oauth/http.rs

+11-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use axum_extra::extract::CookieJar;
33
use chrono::{Duration, Utc};
44
use oauth2::TokenResponse;
55

6-
use super::OAuthConfig;
6+
use super::{IntrospectionTokenResponse, OAuthConfig};
77
use crate::cookies::new_cookie;
88
use crate::session::{update_session, Session};
99
use crate::{oauth::OAuthClient, settings::CookiesConfig};
@@ -130,4 +130,14 @@ impl OAuthHttpHandler {
130130
cookies_config: self.cookies_config.clone(),
131131
}
132132
}
133+
134+
pub async fn introspect(&self, jar: CookieJar) -> (CookieJar, Option<IntrospectionTokenResponse>) {
135+
let (updated_jar, access_token) = self.get_or_refresh_token(jar).await.unwrap();
136+
if access_token.is_none() {
137+
return (updated_jar, None)
138+
}
139+
140+
let result = self.client.introspect_token(access_token.unwrap().to_string()).await.unwrap();
141+
(updated_jar, Some(result))
142+
}
133143
}

baffao/src/oauth/mod.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ pub use http::OAuthHttpHandler;
44
mod client;
55
mod http;
66

7-
use oauth2::{basic::BasicTokenType, EmptyExtraTokenFields, StandardTokenResponse};
7+
use oauth2::{basic::BasicTokenType, EmptyExtraTokenFields, StandardTokenIntrospectionResponse, StandardTokenResponse};
88

99
use serde::Deserialize;
1010

@@ -22,8 +22,10 @@ pub struct OAuthConfig {
2222
pub authorization_redirect_uri: String,
2323
pub authorization_endpoint: String,
2424
pub token_endpoint: String,
25+
pub introspection_endpoint: Option<String>,
2526
pub redirect_uri: Option<String>,
2627
pub default_scopes: Option<Vec<String>>,
2728
}
2829

2930
pub type AccessToken = StandardTokenResponse<EmptyExtraTokenFields, BasicTokenType>;
31+
pub type IntrospectionTokenResponse = StandardTokenIntrospectionResponse<EmptyExtraTokenFields, BasicTokenType>;

0 commit comments

Comments
 (0)