feat: add refresh cookie reader
This commit is contained in:
@@ -1,11 +1,14 @@
|
||||
use axum::{
|
||||
Json,
|
||||
extract::{Extension, Request, State},
|
||||
http::{HeaderMap, StatusCode, header::AUTHORIZATION},
|
||||
http::{
|
||||
HeaderMap, StatusCode,
|
||||
header::{AUTHORIZATION, COOKIE},
|
||||
},
|
||||
middleware::Next,
|
||||
response::Response,
|
||||
};
|
||||
use platform_auth::{AccessTokenClaims, verify_access_token};
|
||||
use platform_auth::{AccessTokenClaims, read_refresh_session_token, verify_access_token};
|
||||
use serde_json::{Value, json};
|
||||
use tracing::warn;
|
||||
|
||||
@@ -20,6 +23,11 @@ pub struct AuthenticatedAccessToken {
|
||||
claims: AccessTokenClaims,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct RefreshSessionToken {
|
||||
token: String,
|
||||
}
|
||||
|
||||
impl AuthenticatedAccessToken {
|
||||
pub fn new(claims: AccessTokenClaims) -> Self {
|
||||
Self { claims }
|
||||
@@ -30,6 +38,16 @@ impl AuthenticatedAccessToken {
|
||||
}
|
||||
}
|
||||
|
||||
impl RefreshSessionToken {
|
||||
pub fn new(token: String) -> Self {
|
||||
Self { token }
|
||||
}
|
||||
|
||||
pub fn token(&self) -> &str {
|
||||
&self.token
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn require_bearer_auth(
|
||||
State(state): State<AppState>,
|
||||
mut request: Request,
|
||||
@@ -69,6 +87,44 @@ pub async fn inspect_auth_claims(
|
||||
)
|
||||
}
|
||||
|
||||
pub async fn attach_refresh_session_token(
|
||||
State(state): State<AppState>,
|
||||
mut request: Request,
|
||||
next: Next,
|
||||
) -> Response {
|
||||
if let Some(token) = request
|
||||
.headers()
|
||||
.get(COOKIE)
|
||||
.and_then(|value| value.to_str().ok())
|
||||
.and_then(|cookie_header| {
|
||||
read_refresh_session_token(cookie_header, state.refresh_cookie_config())
|
||||
})
|
||||
{
|
||||
request
|
||||
.extensions_mut()
|
||||
.insert(RefreshSessionToken::new(token));
|
||||
}
|
||||
|
||||
next.run(request).await
|
||||
}
|
||||
|
||||
pub async fn inspect_refresh_session_cookie(
|
||||
State(state): State<AppState>,
|
||||
Extension(request_context): Extension<RequestContext>,
|
||||
request: Request,
|
||||
) -> Json<Value> {
|
||||
let maybe_token = request.extensions().get::<RefreshSessionToken>();
|
||||
|
||||
json_success_body(
|
||||
Some(&request_context),
|
||||
json!({
|
||||
"cookieName": state.refresh_cookie_config().cookie_name(),
|
||||
"present": maybe_token.is_some(),
|
||||
"tokenLength": maybe_token.map(|token| token.token().len()),
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
fn extract_bearer_token(headers: &HeaderMap) -> Result<String, AppError> {
|
||||
let authorization = headers
|
||||
.get(AUTHORIZATION)
|
||||
@@ -88,7 +144,7 @@ fn extract_bearer_token(headers: &HeaderMap) -> Result<String, AppError> {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::extract_bearer_token;
|
||||
use super::{RefreshSessionToken, extract_bearer_token};
|
||||
use axum::{
|
||||
http::{HeaderMap, HeaderValue, StatusCode, header::AUTHORIZATION},
|
||||
response::IntoResponse,
|
||||
@@ -116,4 +172,11 @@ mod tests {
|
||||
|
||||
assert_eq!(error.into_response().status(), StatusCode::UNAUTHORIZED);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn refresh_session_token_retains_original_value() {
|
||||
let token = RefreshSessionToken::new("refresh-token-01".to_string());
|
||||
|
||||
assert_eq!(token.token(), "refresh-token-01");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user