this repo has no description
1mod grants;
2mod helpers;
3mod introspect;
4mod types;
5
6use axum::{
7 Form, Json,
8 extract::State,
9 http::HeaderMap,
10};
11
12use crate::state::{AppState, RateLimitKind};
13use crate::oauth::OAuthError;
14
15pub use grants::{handle_authorization_code_grant, handle_refresh_token_grant};
16pub use helpers::{create_access_token, extract_token_claims, verify_pkce, TokenClaims};
17pub use introspect::{
18 introspect_token, revoke_token, IntrospectRequest, IntrospectResponse, RevokeRequest,
19};
20pub use types::{TokenRequest, TokenResponse};
21
22fn extract_client_ip(headers: &HeaderMap) -> String {
23 if let Some(forwarded) = headers.get("x-forwarded-for") {
24 if let Ok(value) = forwarded.to_str() {
25 if let Some(first_ip) = value.split(',').next() {
26 return first_ip.trim().to_string();
27 }
28 }
29 }
30 if let Some(real_ip) = headers.get("x-real-ip") {
31 if let Ok(value) = real_ip.to_str() {
32 return value.trim().to_string();
33 }
34 }
35 "unknown".to_string()
36}
37
38pub async fn token_endpoint(
39 State(state): State<AppState>,
40 headers: HeaderMap,
41 Form(request): Form<TokenRequest>,
42) -> Result<(HeaderMap, Json<TokenResponse>), OAuthError> {
43 let client_ip = extract_client_ip(&headers);
44 if !state.check_rate_limit(RateLimitKind::OAuthToken, &client_ip).await {
45 tracing::warn!(ip = %client_ip, "OAuth token rate limit exceeded");
46 return Err(OAuthError::InvalidRequest(
47 "Too many requests. Please try again later.".to_string(),
48 ));
49 }
50
51 let dpop_proof = headers
52 .get("DPoP")
53 .and_then(|v| v.to_str().ok())
54 .map(|s| s.to_string());
55
56 match request.grant_type.as_str() {
57 "authorization_code" => {
58 handle_authorization_code_grant(state, headers, request, dpop_proof).await
59 }
60 "refresh_token" => {
61 handle_refresh_token_grant(state, headers, request, dpop_proof).await
62 }
63 _ => Err(OAuthError::UnsupportedGrantType(format!(
64 "Unsupported grant_type: {}",
65 request.grant_type
66 ))),
67 }
68}