Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Redirect users to login page upon 403 on getSelf #656 #662

Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion packages/api-client/src/core/client.ts
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't have this code in here. The call needs to be tapped in the platform app

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm sorry if the issue description wasn't descriptive enough!

Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,26 @@ export class APIClient {
constructor(private readonly baseUrl: string) {}

async request(url: string, options: RequestInit): Promise<Response> {
return await fetch(`${this.baseUrl}${url}`, options)
const response = await fetch(`${this.baseUrl}${url}`, options);

if (response.status === 403) {
// Clear local data and cookies
if (typeof localStorage !== 'undefined') {
localStorage.clear();
}
if (typeof document !== 'undefined' && typeof document.cookie !== 'undefined') {
document.cookie.split(";").forEach((cookie) => {
const name = cookie.split("=")[0].trim();
document.cookie = `${name}=;expires=Thu, 01 Jan 1970 00:00:00 UTC;path=/`;
});
}

// Redirect to /auth
window.location.href = "/auth";
return Promise.reject(new Error("User is not authenticated. Redirecting to /auth."));
}

return response;
}

/**
Expand Down
68 changes: 68 additions & 0 deletions packages/api-client/tests/api-client.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { APIClient } from "../src/APIClient";
import { rest } from "msw";
import { setupServer } from "msw/node";

const backendUrl = process.env.BACKEND_URL
const apiClient = new APIClient(backendUrl);

// Mock server for API requests
const server = setupServer(
rest.get(`${backendUrl}/test`, (req, res, ctx) => {
return res(ctx.status(200), ctx.json({ message: "Success" }));
}),
rest.get(`${backendUrl}/auth-required`, (req, res, ctx) => {
return res(ctx.status(403), ctx.json({ message: "Forbidden" }));
})
);

beforeAll(() => server.listen());
afterEach(() => server.resetHandlers());
afterAll(() => server.close());

describe("APIClient", () => {
beforeEach(() => {
localStorage.clear();
document.cookie = "";
});

it("should fetch data successfully", async () => {
const response = await apiClient.get("/test");
const data = await response.json();

expect(response.status).toBe(200);
expect(data.message).toBe("Success");
});

it("should clear local data and redirect on 403 Forbidden", async () => {
// Mock window.location.href
delete (window as any).location;
(window as any).location = { href: "" };

await expect(apiClient.get("/auth-required")).rejects.toThrow(
"User is not authenticated. Redirecting to /auth."
);

// Verify localStorage is cleared
expect(localStorage.length).toBe(0);

// Verify cookies are cleared
expect(document.cookie).toBe("");

// Verify redirection
expect(window.location.href).toBe("/auth");
});

it("should handle other HTTP errors gracefully", async () => {
server.use(
rest.get(`${baseUrl}/error`, (req, res, ctx) => {
return res(ctx.status(500), ctx.json({ message: "Server Error" }));
})
);

const response = await apiClient.get("/error");
expect(response.status).toBe(500);

const data = await response.json();
expect(data.message).toBe("Server Error");
});
});
Loading