diff --git a/site/src/pages/LoginPage/LoginPage.test.tsx b/site/src/pages/LoginPage/LoginPage.test.tsx
index 554a4be49f..6cf8a6646f 100644
--- a/site/src/pages/LoginPage/LoginPage.test.tsx
+++ b/site/src/pages/LoginPage/LoginPage.test.tsx
@@ -1,10 +1,11 @@
+import { MockUserOwner } from "testHelpers/entities";
import {
render,
renderWithRouter,
waitForLoaderToBeRemoved,
} from "testHelpers/renderHelpers";
import { server } from "testHelpers/server";
-import { fireEvent, screen } from "@testing-library/react";
+import { fireEvent, screen, waitFor } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import { HttpResponse, http } from "msw";
import { createMemoryRouter } from "react-router";
@@ -76,4 +77,147 @@ describe("LoginPage", () => {
// Then
await screen.findByText("Setup");
});
+
+ it("redirects to /oauth2/authorize via server-side redirect when signed in", async () => {
+ // Given - user is signed in
+ server.use(
+ http.get("/api/v2/users/me", () => {
+ return HttpResponse.json(MockUserOwner);
+ }),
+ );
+
+ const redirectPath =
+ "/oauth2/authorize?client_id=xxx&response_type=code&redirect_uri=https%3A%2F%2Fexample.com%2Fcallback";
+
+ // Spy on window.location.href assignment
+ const locationHrefSpy = vi.fn();
+ const originalLocation = window.location;
+ Object.defineProperty(window, "location", {
+ configurable: true,
+ value: {
+ ...originalLocation,
+ origin: originalLocation.origin,
+ set href(url: string) {
+ locationHrefSpy(url);
+ },
+ get href() {
+ return originalLocation.href;
+ },
+ },
+ });
+
+ // When
+ renderWithRouter(
+ createMemoryRouter(
+ [
+ {
+ path: "/login",
+ element: ,
+ },
+ ],
+ {
+ initialEntries: [
+ `/login?redirect=${encodeURIComponent(redirectPath)}`,
+ ],
+ },
+ ),
+ );
+
+ // Then - it should perform a server-side redirect, not a React navigate
+ await waitFor(() => {
+ expect(locationHrefSpy).toHaveBeenCalledWith(
+ expect.stringContaining("/oauth2/authorize"),
+ );
+ });
+
+ // Cleanup
+ Object.defineProperty(window, "location", {
+ configurable: true,
+ value: originalLocation,
+ });
+ });
+
+ it("redirects to /oauth2/authorize after successful login when not already signed in", async () => {
+ // Given - user is NOT signed in
+ let loggedIn = false;
+ server.use(
+ http.get("/api/v2/users/me", () => {
+ if (!loggedIn) {
+ return HttpResponse.json(
+ { message: "no user here" },
+ { status: 401 },
+ );
+ }
+ return HttpResponse.json(MockUserOwner);
+ }),
+ http.post("/api/v2/users/login", () => {
+ loggedIn = true;
+ return HttpResponse.json({
+ session_token: "test-session-token",
+ });
+ }),
+ );
+
+ const redirectPath =
+ "/oauth2/authorize?client_id=xxx&response_type=code&redirect_uri=https%3A%2F%2Fexample.com%2Fcallback";
+
+ // Spy on window.location.href
+ const originalLocation = window.location;
+ const locationHrefSpy = vi.fn();
+
+ Object.defineProperty(window, "location", {
+ configurable: true,
+ value: {
+ ...originalLocation,
+ origin: originalLocation.origin,
+ set href(url: string) {
+ locationHrefSpy(url);
+ },
+ get href() {
+ return originalLocation.href;
+ },
+ },
+ });
+
+ // When
+ renderWithRouter(
+ createMemoryRouter(
+ [
+ {
+ path: "/login",
+ element: ,
+ },
+ ],
+ {
+ initialEntries: [
+ `/login?redirect=${encodeURIComponent(redirectPath)}`,
+ ],
+ },
+ ),
+ );
+
+ await waitForLoaderToBeRemoved();
+
+ const email = screen.getByLabelText(new RegExp(Language.emailLabel));
+ const password = screen.getByLabelText(new RegExp(Language.passwordLabel));
+
+ await userEvent.type(email, "test@coder.com");
+ await userEvent.type(password, "password");
+
+ const signInButton = await screen.findByText(Language.passwordSignIn);
+ fireEvent.click(signInButton);
+
+ // Then - it should hard redirect to OAuth endpoint
+ await waitFor(() => {
+ expect(locationHrefSpy).toHaveBeenCalledWith(
+ expect.stringContaining("/oauth2/authorize"),
+ );
+ });
+
+ // Cleanup
+ Object.defineProperty(window, "location", {
+ configurable: true,
+ value: originalLocation,
+ });
+ });
});
diff --git a/site/src/pages/LoginPage/LoginPage.tsx b/site/src/pages/LoginPage/LoginPage.tsx
index 20c1d4dea3..50da94534a 100644
--- a/site/src/pages/LoginPage/LoginPage.tsx
+++ b/site/src/pages/LoginPage/LoginPage.tsx
@@ -35,7 +35,9 @@ const LoginPage: FC = () => {
// Do nothing
}
- const isApiRouteRedirect = redirectTo.startsWith("/api/v2");
+ const isApiRouteRedirect =
+ redirectTo.startsWith("/api/v2") ||
+ redirectTo.startsWith("/oauth2/authorize");
useEffect(() => {
if (!buildInfoQuery.data || isSignedIn) {