From 5cdaa908db8602c596eabc6d28b671bbcac83844 Mon Sep 17 00:00:00 2001 From: Jackson Chadfield Date: Sun, 1 Oct 2023 02:17:16 +1300 Subject: [PATCH] implement logout endpoint --- backend/src/api/auth/controllers.rs | 23 ++++++++++++++++++----- backend/src/api/auth/mod.rs | 2 +- backend/src/api/auth/utils.rs | 2 +- backend/src/api/error.rs | 8 ++++---- 4 files changed, 24 insertions(+), 11 deletions(-) diff --git a/backend/src/api/auth/controllers.rs b/backend/src/api/auth/controllers.rs index 2fa76dc..2889609 100644 --- a/backend/src/api/auth/controllers.rs +++ b/backend/src/api/auth/controllers.rs @@ -1,6 +1,8 @@ use super::models::RegisterNewUserRequest; use crate::api::auth::models::{RefreshTokenRequest, UserResponse}; -use crate::api::auth::utils::{find_refresh_token, find_user_by_id}; +use crate::api::auth::utils::{ + delete_refresh_token_if_exists, find_refresh_token, find_user_by_id, +}; use crate::api::error::ErrorType::Unauthorized; use crate::api::middleware::CurrentUser; use crate::api::utils::friendly_id::{ItemIdType, ToFriendlyId}; @@ -20,7 +22,7 @@ use crate::{ db::user::NewUser, AppState, }; -use axum::{extract::State, http::StatusCode, response::IntoResponse, Extension, Json}; +use axum::{extract::State, http::StatusCode, Extension, Json}; use tracing::{error, info}; /// Register a new user @@ -113,16 +115,27 @@ pub async fn login( } /// Logout the current user +/// +/// This will invalidate the refresh token #[utoipa::path( post, path = "/auth/logout", tag = "auth", + security( + ("api_token" = []) + ), responses( - (status = 501, description = "Not Implemented") + (status = 204, description = "Logout successful"), ) )] -pub async fn logout() -> impl IntoResponse { - StatusCode::NOT_IMPLEMENTED +pub async fn logout( + State(state): State, + Extension(user): Extension, +) -> Result { + let mut conn = get_db_connection(&state.database_pool).await?; + delete_refresh_token_if_exists(&mut conn, user.id).await?; + + Ok(StatusCode::NO_CONTENT) } /// Use a refresh token to get a new access token diff --git a/backend/src/api/auth/mod.rs b/backend/src/api/auth/mod.rs index f684560..948e1fa 100644 --- a/backend/src/api/auth/mod.rs +++ b/backend/src/api/auth/mod.rs @@ -10,10 +10,10 @@ mod utils; pub fn get_router(state: AppState) -> Router { Router::new() + .route("/logout", post(logout)) .route("/user", get(get_user)) .route_layer(middleware::from_fn_with_state(state.clone(), auth)) .route("/register", post(register)) .route("/login", post(login)) - .route("/logout", post(logout)) .route("/refresh_token", post(refresh_token)) } diff --git a/backend/src/api/auth/utils.rs b/backend/src/api/auth/utils.rs index 9eb9e15..e3b8546 100644 --- a/backend/src/api/auth/utils.rs +++ b/backend/src/api/auth/utils.rs @@ -96,7 +96,7 @@ pub async fn generate_new_refresh_token( }) } -async fn delete_refresh_token_if_exists( +pub async fn delete_refresh_token_if_exists( conn: &mut Connection, user_id: Uuid, ) -> Result<(), APIError> { diff --git a/backend/src/api/error.rs b/backend/src/api/error.rs index 98795b8..4880ba0 100644 --- a/backend/src/api/error.rs +++ b/backend/src/api/error.rs @@ -5,7 +5,7 @@ use const_format::concatcp; use serde::{Serialize, Serializer}; use serde_json::Value; use std::collections::HashMap; -use std::fmt::Debug; +use std::fmt::{Debug, Display}; use thiserror::Error; use tracing::error; use utoipa::ToSchema; @@ -168,15 +168,15 @@ impl APIErrorBuilder { /// Create a new unknown error from the given error. /// /// This is a shorthand for `APIErrorBuilder::new(Unknown).cause(error)`. - pub fn from_error(error: impl Debug) -> Self { + pub fn from_error(error: impl Display) -> Self { Self::new(ErrorType::Unknown).cause(error) } /// Adds a cause field to the error. /// /// Shorthand for `with_field("cause", error.to_string().into())`. - pub fn cause(self, error: impl Debug) -> Self { - self.with_field("cause", format!("{:#?}", error).into()) + pub fn cause(self, error: impl Display) -> Self { + self.with_field("cause", format!("{}", error).into()) } /// Add additional information to the error.