backend/src/api/v1/auth/logout.rs
Radical 2fbf41ba8c
All checks were successful
ci/woodpecker/push/build-and-publish Pipeline was successful
fix: use .append() and not Set-Cookie2
web dev is too confusing..
2025-07-19 19:10:36 +02:00

75 lines
1.8 KiB
Rust

use std::sync::Arc;
use axum::{
extract::State,
http::{HeaderValue, StatusCode},
response::IntoResponse,
};
use axum_extra::extract::CookieJar;
use diesel::{ExpressionMethods, delete};
use diesel_async::RunQueryDsl;
use crate::{
AppState,
error::Error,
schema::refresh_tokens::{self, dsl},
};
/// `GET /api/v1/logout`
///
/// requires auth: kinda, needs refresh token set but no access token is technically required
///
/// ### Responses
///
/// 200 Logged out
///
/// 404 Refresh token is invalid
///
/// 401 Unauthorized (no refresh token found)
///
pub async fn res(
State(app_state): State<Arc<AppState>>,
jar: CookieJar,
) -> Result<impl IntoResponse, Error> {
let mut refresh_token_cookie = jar
.get("refresh_token")
.ok_or(Error::Unauthorized(
"request has no refresh token".to_string(),
))?
.to_owned();
let access_token_cookie = jar.get("access_token");
let refresh_token = String::from(refresh_token_cookie.value_trimmed());
let mut conn = app_state.pool.get().await?;
let deleted = delete(refresh_tokens::table)
.filter(dsl::token.eq(refresh_token))
.execute(&mut conn)
.await?;
let mut response;
if deleted == 0 {
response = StatusCode::NOT_FOUND.into_response();
} else {
response = StatusCode::OK.into_response();
}
refresh_token_cookie.make_removal();
response.headers_mut().append(
"Set-Cookie",
HeaderValue::from_str(&refresh_token_cookie.to_string())?,
);
if let Some(cookie) = access_token_cookie {
let mut cookie = cookie.clone();
cookie.make_removal();
response
.headers_mut()
.append("Set-Cookie", HeaderValue::from_str(&cookie.to_string())?);
}
Ok(response)
}