Skip to content

Commit

Permalink
[Issue #3953] Logout user if session is expired (#4023)
Browse files Browse the repository at this point in the history
  • Loading branch information
acouch authored Feb 28, 2025
1 parent 8895d04 commit 541126a
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 9 deletions.
19 changes: 14 additions & 5 deletions frontend/src/app/api/auth/logout/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,19 @@ export async function POST() {
await deleteSession();
return Response.json({ message: "logout success" });
} catch (e) {
const { message, status } = readError(e as Error, 500);
return Response.json(
{ message: `Error logging out: ${message}` },
{ status },
);
const { message, status, cause } = readError(e as Error, 500);
// if token expired, delete session and return 401
if (status === 401 && cause?.message === "Token expired") {
await deleteSession();
return Response.json(
{ message: "session previously expired" },
{ status },
);
} else {
return Response.json(
{ message: `Error logging out: ${message}` },
{ status },
);
}
}
}
3 changes: 2 additions & 1 deletion frontend/src/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ export const readError = (e: Error, defaultStatus: number) => {

return {
status: Number(status),
message: cause ? JSON.stringify(cause) : message,
message,
cause: cause as FrontendErrorDetails,
};
};
22 changes: 19 additions & 3 deletions frontend/tests/api/auth/logout/route.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
*/

import { POST } from "src/app/api/auth/logout/route";
import { UnauthorizedError } from "src/errors";

const getSessionMock = jest.fn();
const deleteSessionMock = jest.fn();
Expand Down Expand Up @@ -34,7 +35,7 @@ describe("/api/auth/logout POST handler", () => {
expect(response.status).toEqual(401);
const json = (await response.json()) as { message: string };
expect(json.message).toEqual(
'Error logging out: {"type":"UnauthorizedError","searchInputs":{},"message":"No active session to logout","status":401,"details":{}}',
"Error logging out: No active session to logout",
);
});
it("calls postLogout with token from session", async () => {
Expand All @@ -61,7 +62,6 @@ describe("/api/auth/logout POST handler", () => {
const json = (await response.json()) as { message: string };
expect(json.message).toEqual("Error logging out: the API threw this error");
});

it("errors if API logout call returns nothing", async () => {
getSessionMock.mockImplementation(() => ({
token: "fakeToken",
Expand All @@ -75,7 +75,7 @@ describe("/api/auth/logout POST handler", () => {
const json = (await response.json()) as { message: string };
// const message = JSON.parse(json) as FrontendErrorDetails;
expect(json.message).toEqual(
'Error logging out: {"type":"APIRequestError","searchInputs":{},"message":"No logout response from API","status":400,"details":{}}',
"Error logging out: No logout response from API",
);
});
it("calls deleteSession", async () => {
Expand All @@ -87,6 +87,22 @@ describe("/api/auth/logout POST handler", () => {

expect(deleteSessionMock).toHaveBeenCalledTimes(1);
});
it("calls deleteSession if token expired", async () => {
getSessionMock.mockImplementation(() => ({
token: "fakeToken",
}));
postLogoutMock.mockImplementation(() => {
throw new UnauthorizedError("Token expired");
});
const response = await POST();

expect(postLogoutMock).toHaveBeenCalledTimes(1);
expect(postLogoutMock).toHaveBeenCalledWith("fakeToken");
expect(response.status).toEqual(401);
expect(deleteSessionMock).toHaveBeenCalledTimes(1);
const json = (await response.json()) as { message: string };
expect(json.message).toEqual("session previously expired");
});
it("returns sucess message on success", async () => {
getSessionMock.mockImplementation(() => ({
token: "fakeToken",
Expand Down

0 comments on commit 541126a

Please sign in to comment.