Skip to content

Commit

Permalink
feat: session expired redirection (#582)
Browse files Browse the repository at this point in the history
  • Loading branch information
hughcrt authored Oct 2, 2024
1 parent 4ebe4c2 commit d385857
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 24 deletions.
34 changes: 17 additions & 17 deletions e2e/login.spec.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,32 @@
import { test } from "@playwright/test"
import { test } from "@playwright/test";

test("logout and back in login", async ({ page }) => {
await page.goto("/")
await page.goto("/");

await page.waitForLoadState("networkidle")
await page.waitForLoadState("networkidle");

// logout
await page.getByTestId("account-sidebar-item").click()
await page.getByTestId("logout-button").click()
await page.getByTestId("account-sidebar-item").click();
await page.getByTestId("logout-button").click();

await page.waitForURL("**/login")
await page.waitForURL("**/login*");

// log back in
await page.getByPlaceholder("Your email").click()
await page.getByPlaceholder("Your email").fill("[email protected]")
await page.getByPlaceholder("Your email").click();
await page.getByPlaceholder("Your email").fill("[email protected]");

const promise = page.waitForResponse((resp) => {
return resp.url().includes("/method")
})
return resp.url().includes("/method");
});

await page.getByTestId("continue-button").click()
await page.getByTestId("continue-button").click();

await promise
await promise;

await page.getByPlaceholder("Your password").click()
await page.getByPlaceholder("Your password").fill("testtest")
await page.getByPlaceholder("Your password").click();
await page.getByPlaceholder("Your password").fill("testtest");

await page.getByRole("button", { name: "Login" }).click()
await page.getByRole("button", { name: "Login" }).click();

await page.waitForURL("**/analytics")
})
await page.waitForURL("**/analytics*");
});
5 changes: 4 additions & 1 deletion packages/backend/src/api/v1/auth/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import * as argon2 from "argon2";
import bcrypt from "bcrypt";
import { validateUUID } from "@/src/utils/misc";
import { sendEmail, RESET_PASSWORD } from "@/src/emails";
import { JWTExpired } from "jose/errors";

export function sanitizeEmail(email: string) {
return email.toLowerCase().trim();
Expand Down Expand Up @@ -153,7 +154,6 @@ export async function authMiddleware(ctx: Context, next: Next) {
throw new Error("No bearer token provided.");
}
const { payload } = await verifyJWT<SessionData>(key);

ctx.state.userId = payload.userId;
ctx.state.orgId = payload.orgId;

Expand All @@ -176,6 +176,9 @@ export async function authMiddleware(ctx: Context, next: Next) {
}
} catch (error) {
console.error(error);
if (error instanceof JWTExpired) {
ctx.throw(401, "Session expired");
}
ctx.throw(401, "Invalid access token");
}
}
Expand Down
10 changes: 5 additions & 5 deletions packages/frontend/components/blocks/RunInputOutput.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import config from "@/utils/config";
import { useDatasets, useOrg, useRun, useUser } from "@/utils/dataHooks";
import {
Badge,
Expand All @@ -11,22 +12,21 @@ import {
Switch,
Text,
} from "@mantine/core";
import { notifications, showNotification } from "@mantine/notifications";
import { notifications } from "@mantine/notifications";
import {
IconBinaryTree2,
IconCheck,
IconPencilShare,
} from "@tabler/icons-react";
import Link from "next/link";
import { useState } from "react";
import { hasAccess } from "shared";
import SmartViewer from "../SmartViewer";
import AppUserAvatar from "./AppUserAvatar";
import CopyText, { SuperCopyButton } from "./CopyText";
import ErrorBoundary from "./ErrorBoundary";
import TokensBadge from "./TokensBadge";
import Feedbacks from "./Feedbacks";
import config from "@/utils/config";
import { useState } from "react";
import AppUserAvatar from "./AppUserAvatar";
import TokensBadge from "./TokensBadge";

const isChatMessages = (obj) => {
return Array.isArray(obj)
Expand Down
14 changes: 14 additions & 0 deletions packages/frontend/pages/login.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ function LoginPage() {
}

auth.setJwt(token);
router.push("/");
analytics.track("Login", { method: "password" });
} catch (error) {
console.error(error);
Expand Down Expand Up @@ -138,6 +139,19 @@ function LoginPage() {
if (ott) exchangeToken(ott);
}, [router.query.ott]);

useEffect(() => {
const email = router.query.email
? decodeURIComponent(router.query.email as string)
: "";
console.log(form.values.password);
if (email && !form.values.email) {
console.log("here");
form.setFieldValue("email", email);
determineAuthMethod(email);
console.log(step);
}
}, [router.query.email]);

return (
<Container pt="60" size="600">
<NextSeo title="Login" />
Expand Down
12 changes: 11 additions & 1 deletion packages/frontend/utils/auth.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
import { useLocalStorage } from "@mantine/hooks";
import { decodeJwt } from "jose";
import Router from "next/router";
import { createContext, useContext, useEffect, useMemo } from "react";

const SIGN_OUT_EVENT = "sign-out";

export async function signOut() {
const jwt = window.localStorage.getItem("auth-token");
if (jwt) {
const payload = decodeJwt(jwt);
const email = payload.email as string;
const encodedEmail = encodeURIComponent(email);
Router.push(`/login?email=${encodedEmail}`);
} else {
Router.push("/login");
}
window.localStorage.clear();
window.dispatchEvent(new Event(SIGN_OUT_EVENT));
}

interface AuthContext {
Expand Down
7 changes: 7 additions & 0 deletions packages/frontend/utils/fetcher.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import Router from "next/router";
import { signOut } from "./auth";
import { showErrorNotification } from "./errors";
import { showNotification } from "@mantine/notifications";

const BASE_URL = process.env.NEXT_PUBLIC_API_URL as string;

Expand Down Expand Up @@ -149,6 +150,12 @@ async function handleResponse(res: Response) {

const { error, message } = await res.json();

if (message === "Session expired") {
showErrorNotification(message, "Please log in again.");
return;
} else if (message === "Invalid access token") {
return;
}
showErrorNotification(error, message);
throw new Error(message);
}
Expand Down

0 comments on commit d385857

Please sign in to comment.