//! OAuth logout: clear both the session and identity cookies. use axum::extract::State; use axum::http::{header, HeaderMap}; use axum::response::{IntoResponse, Redirect, Response}; use axum::routing::post; use axum::Router; use crate::error::AppError; use crate::oauth::session::{build_clear_cookie_header, IDENTITY_COOKIE_NAME, SESSION_COOKIE_NAME}; use crate::state::AppState; /// `POST /auth/logout` -- clear both cookies and redirect home. /// /// Local only: `atproto_oauth` 0.14.5 has no token-revocation call, so /// tokens stay valid server-side until they expire. pub async fn logout(State(state): State) -> Result { let external_base = state.config.external_base(); let mut headers = HeaderMap::new(); // Surface (not swallow) a failure to clear cookies, or logout could // silently not log the user out. let clear_session = build_clear_cookie_header(SESSION_COOKIE_NAME, external_base, true) .map_err(|e| AppError::Internal(anyhow::anyhow!("cookie clear failed: {e}")))?; let clear_identity = build_clear_cookie_header(IDENTITY_COOKIE_NAME, external_base, false) .map_err(|e| AppError::Internal(anyhow::anyhow!("cookie clear failed: {e}")))?; headers.append(header::SET_COOKIE, clear_session); headers.append(header::SET_COOKIE, clear_identity); Ok((headers, Redirect::to("/")).into_response()) } /// Routes for logout. pub fn router() -> axum::Router { Router::new().route("/auth/logout", post(logout)) }