forked from
tranquil.farm/tranquil-pds
Our Personal Data Server from scratch!
2.1 kB
56 lines
1mod grants;
2mod helpers;
3mod introspect;
4mod types;
5
6use axum::body::Bytes;
7use axum::{Json, extract::State, http::HeaderMap};
8use tranquil_pds::oauth::OAuthError;
9use tranquil_pds::rate_limit::{OAuthRateLimited, OAuthTokenLimit};
10use tranquil_pds::state::AppState;
11
12pub use grants::{handle_authorization_code_grant, handle_refresh_token_grant};
13pub use helpers::{TokenClaims, extract_token_claims, verify_pkce};
14pub use introspect::{
15 IntrospectRequest, IntrospectResponse, RevokeRequest, introspect_token, revoke_token,
16};
17pub use types::{
18 GrantType, RequestClientAuth, TokenGrant, TokenRequest, TokenResponse, ValidatedTokenRequest,
19};
20
21pub async fn token_endpoint(
22 State(state): State<AppState>,
23 _rate_limit: OAuthRateLimited<OAuthTokenLimit>,
24 headers: HeaderMap,
25 body: Bytes,
26) -> Result<(HeaderMap, Json<TokenResponse>), OAuthError> {
27 let content_type = headers
28 .get("content-type")
29 .and_then(|v| v.to_str().ok())
30 .unwrap_or("");
31 let request: TokenRequest = if content_type.starts_with("application/json") {
32 serde_json::from_slice(&body)
33 .map_err(|e| OAuthError::InvalidRequest(format!("Invalid JSON: {}", e)))?
34 } else if content_type.starts_with("application/x-www-form-urlencoded") {
35 serde_urlencoded::from_bytes(&body)
36 .map_err(|e| OAuthError::InvalidRequest(format!("Invalid form data: {}", e)))?
37 } else {
38 return Err(OAuthError::InvalidRequest(
39 "Content-Type must be application/json or application/x-www-form-urlencoded"
40 .to_string(),
41 ));
42 };
43 let dpop_proof = headers
44 .get(tranquil_pds::util::HEADER_DPOP)
45 .and_then(|v| v.to_str().ok())
46 .map(|s| s.to_string());
47 let validated = request.validate()?;
48 match validated.grant {
49 TokenGrant::AuthorizationCode { .. } => {
50 handle_authorization_code_grant(state, headers, validated, dpop_proof).await
51 }
52 TokenGrant::RefreshToken { .. } => {
53 handle_refresh_token_grant(state, headers, validated, dpop_proof).await
54 }
55 }
56}