From 81ead47011d53525f3e3149206c331f9f0c3659f Mon Sep 17 00:00:00 2001 From: Rosa Gutierrez Date: Tue, 27 Jan 2026 19:21:22 +0100 Subject: [PATCH] Add JSON format support to session destroy for native API clients This is so that native API clients can get the session record deleted server-side. They still need to take care of clearing any cookies they've set in web views. Co-Authored-By: Claude Opus 4.5 --- app/controllers/sessions_controller.rb | 6 +++++- docs/API.md | 16 ++++++++++++++++ test/controllers/api_test.rb | 20 ++++++++++++++++++++ test/controllers/sessions_controller_test.rb | 11 +++++++++++ 4 files changed, 52 insertions(+), 1 deletion(-) diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb index d0de9e84cf..cabcfa143c 100644 --- a/app/controllers/sessions_controller.rb +++ b/app/controllers/sessions_controller.rb @@ -20,7 +20,11 @@ def create def destroy terminate_session - redirect_to_logout_url + + respond_to do |format| + format.html { redirect_to_logout_url } + format.json { head :no_content } + end end private diff --git a/docs/API.md b/docs/API.md index 3a68c46dde..47965372c4 100644 --- a/docs/API.md +++ b/docs/API.md @@ -118,6 +118,22 @@ __Error responses:__ | `401 Unauthorized` | Invalid `pending_authentication_token` or `code` | | `429 Too Many Requests` | Rate limit exceeded | + +#### Delete server-side session (_log out_) + +To log out and destroy the server-side session: + +```bash +curl -X DELETE \ + -H "Accept: application/json" \ + -H "Cookie: session_token=eyJfcmFpbHMi..." \ + https://app.fizzy.do/session +``` + +__Response:__ + +Returns `204 No Content` on success. + ## Caching Most endpoints return [ETag](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/ETag) and [Cache-Control](https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Cache-Control) headers. You can use these to avoid re-downloading unchanged data. diff --git a/test/controllers/api_test.rb b/test/controllers/api_test.rb index f6bf18ca60..f52bc17425 100644 --- a/test/controllers/api_test.rb +++ b/test/controllers/api_test.rb @@ -22,6 +22,26 @@ class ApiTest < ActionDispatch::IntegrationTest end end + test "logout with user credentials" do + identity = identities(:david) + + untenanted do + post session_path(format: :json), params: { email_address: identity.email_address } + magic_link = MagicLink.last + + assert_difference -> { identity.sessions.count }, +1 do + post session_magic_link_path(format: :json), params: { code: magic_link.code, pending_authentication_token: @response.parsed_body["pending_authentication_token"] } + end + assert cookies[:session_token].present? + + assert_difference -> { identity.sessions.count }, -1 do + delete session_path(format: :json) + end + assert_response :no_content + assert_not cookies[:session_token].present? + end + end + test "authenticate with valid access token" do get boards_path(format: :json), env: @davids_bearer_token assert_response :success diff --git a/test/controllers/sessions_controller_test.rb b/test/controllers/sessions_controller_test.rb index 1a0ddb0615..47f1e33a58 100644 --- a/test/controllers/sessions_controller_test.rb +++ b/test/controllers/sessions_controller_test.rb @@ -117,4 +117,15 @@ class SessionsControllerTest < ActionDispatch::IntegrationTest assert_response :unprocessable_entity end end + + test "destroy via JSON" do + sign_in_as :kevin + + untenanted do + delete session_path(format: :json) + + assert_response :no_content + assert_not cookies[:session_token].present? + end + end end