From 2d3ab6760404596d60f299bcdd97b461e1192450 Mon Sep 17 00:00:00 2001 From: Ludvig Lundgren Date: Sat, 26 Mar 2022 19:46:16 +0100 Subject: [PATCH] feat(web): redirect to login on expired cookie (#201) * feat(web): redirect to login on expired cookie * refactor: simplify auth wrapper --- internal/http/auth.go | 6 +++--- internal/http/middleware.go | 2 +- web/src/App.tsx | 12 +++++++----- web/src/api/APIClient.ts | 16 ++++++++++++++-- 4 files changed, 25 insertions(+), 11 deletions(-) diff --git a/internal/http/auth.go b/internal/http/auth.go index 5b24cab..8178ee3 100644 --- a/internal/http/auth.go +++ b/internal/http/auth.go @@ -35,7 +35,7 @@ func newAuthHandler(encoder encoder, config domain.Config, cookieStore *sessions func (h authHandler) Routes(r chi.Router) { r.Post("/login", h.login) r.Post("/logout", h.logout) - r.Get("/test", h.test) + r.Get("/validate", h.validate) } func (h authHandler) login(w http.ResponseWriter, r *http.Request) { @@ -91,13 +91,13 @@ func (h authHandler) logout(w http.ResponseWriter, r *http.Request) { h.encoder.StatusResponse(ctx, w, nil, http.StatusNoContent) } -func (h authHandler) test(w http.ResponseWriter, r *http.Request) { +func (h authHandler) validate(w http.ResponseWriter, r *http.Request) { ctx := r.Context() session, _ := h.cookieStore.Get(r, "user_session") // Check if user is authenticated if auth, ok := session.Values["authenticated"].(bool); !ok || !auth { - http.Error(w, "Forbidden", http.StatusForbidden) + http.Error(w, "Forbidden", http.StatusUnauthorized) return } diff --git a/internal/http/middleware.go b/internal/http/middleware.go index ae4519b..a1a88ab 100644 --- a/internal/http/middleware.go +++ b/internal/http/middleware.go @@ -9,7 +9,7 @@ func (s Server) IsAuthenticated(next http.Handler) http.Handler { // Check if user is authenticated if auth, ok := session.Values["authenticated"].(bool); !ok || !auth { - http.Error(w, http.StatusText(http.StatusForbidden), http.StatusForbidden) + http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized) return } next.ServeHTTP(w, r) diff --git a/web/src/App.tsx b/web/src/App.tsx index 331e259..d508d50 100644 --- a/web/src/App.tsx +++ b/web/src/App.tsx @@ -1,5 +1,6 @@ -import { QueryClient, QueryClientProvider } from "react-query"; +import { Fragment } from "react"; import { BrowserRouter as Router, Route } from "react-router-dom"; +import { QueryClient, QueryClientProvider } from "react-query"; import { ReactQueryDevtools } from "react-query/devtools"; import { Toaster } from "react-hot-toast"; @@ -12,10 +13,10 @@ import { AuthContext, SettingsContext } from "./utils/Context"; function Protected() { return ( - <> + - + ) } @@ -24,14 +25,15 @@ export const queryClient = new QueryClient(); export function App() { const authContext = AuthContext.useValue(); const settings = SettingsContext.useValue(); + return ( {authContext.isLoggedIn ? ( - ) : ( + ) : - )} + } {settings.debug ? ( diff --git a/web/src/api/APIClient.ts b/web/src/api/APIClient.ts index f4ea14e..1f51db4 100644 --- a/web/src/api/APIClient.ts +++ b/web/src/api/APIClient.ts @@ -1,4 +1,6 @@ import {baseUrl, sseBaseUrl} from "../utils"; +import {AuthContext} from "../utils/Context"; +import {Cookies} from "react-cookie"; interface ConfigType { body?: BodyInit | Record | null; @@ -20,9 +22,19 @@ export async function HttpClient( ...customConfig } as RequestInit; + return window.fetch(`${baseUrl()}${endpoint}`, config) .then(async response => { - if ([401, 403, 404].includes(response.status)) + if (response.status === 401) { + // if 401 consider the session expired and force logout + const cookies = new Cookies(); + cookies.remove("user_session"); + AuthContext.reset() + + return Promise.reject(new Error(response.statusText)); + } + + if ([403, 404].includes(response.status)) return Promise.reject(new Error(response.statusText)); if ([201, 204].includes(response.status)) @@ -49,7 +61,7 @@ export const APIClient = { auth: { login: (username: string, password: string) => appClient.Post("api/auth/login", { username: username, password: password }), logout: () => appClient.Post("api/auth/logout", null), - test: () => appClient.Get("api/auth/test"), + validate: () => appClient.Get("api/auth/validate"), }, actions: { create: (action: Action) => appClient.Post("api/actions", action),