all kinds of frontend sec. adaptations
Some checks failed
continuous-integration/drone/push Build is failing
Some checks failed
continuous-integration/drone/push Build is failing
This commit is contained in:
@ -1,4 +1,5 @@
|
|||||||
import { createContext, useContext, useEffect, useMemo, useState, PropsWithChildren } from 'react'
|
import { createContext, useContext, useEffect, useMemo, useState } from 'react'
|
||||||
|
import type { PropsWithChildren } from 'react'
|
||||||
import { userManager } from './oidc'
|
import { userManager } from './oidc'
|
||||||
import type { User } from 'oidc-client-ts'
|
import type { User } from 'oidc-client-ts'
|
||||||
|
|
||||||
@ -42,13 +43,19 @@ userManager.events.removeAccessTokenExpired(onExpired)
|
|||||||
|
|
||||||
|
|
||||||
// Spegla token till sessionStorage så ky kan läsa den
|
// Spegla token till sessionStorage så ky kan läsa den
|
||||||
|
// i useEffect som speglar token:
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const token = user?.access_token ?? null
|
const token = user?.access_token ?? null
|
||||||
if (token) sessionStorage.setItem('access_token', token)
|
if (token) {
|
||||||
else sessionStorage.removeItem('access_token')
|
sessionStorage.setItem('access_token', token)
|
||||||
|
console.debug('access_token set')
|
||||||
|
} else {
|
||||||
|
sessionStorage.removeItem('access_token')
|
||||||
|
}
|
||||||
}, [user])
|
}, [user])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const api: AuthCtx = useMemo(() => ({
|
const api: AuthCtx = useMemo(() => ({
|
||||||
user,
|
user,
|
||||||
isAuthenticated: !!user && !user.expired,
|
isAuthenticated: !!user && !user.expired,
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { UserManager, WebStorageStateStore, Log, type UserManagerSettings } from 'oidc-client-ts'
|
import { UserManager, WebStorageStateStore, Log, type UserManagerSettings } from 'oidc-client-ts'
|
||||||
|
|
||||||
|
console.log('AUTHORITY:', import.meta.env.VITE_OIDC_AUTHORITY)
|
||||||
const settings: UserManagerSettings = {
|
const settings: UserManagerSettings = {
|
||||||
authority: import.meta.env.VITE_OIDC_AUTHORITY!,
|
authority: import.meta.env.VITE_OIDC_AUTHORITY!,
|
||||||
client_id: import.meta.env.VITE_OIDC_CLIENT_ID!,
|
client_id: import.meta.env.VITE_OIDC_CLIENT_ID!,
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import { DueTomorrowPage } from '@/pages/DueTomorrowPage'
|
|||||||
import AuthCallbackPage from '@/pages/AuthCallbackPage'
|
import AuthCallbackPage from '@/pages/AuthCallbackPage'
|
||||||
import SilentRenewPage from '@/pages/SilentRenewPage'
|
import SilentRenewPage from '@/pages/SilentRenewPage'
|
||||||
import LogoutPage from '@/pages/LogoutPage'
|
import LogoutPage from '@/pages/LogoutPage'
|
||||||
|
import { RequireAuth } from 'auth/RequireAuth'
|
||||||
|
|
||||||
const router = createBrowserRouter([
|
const router = createBrowserRouter([
|
||||||
{ path: '/auth/callback', element: <AuthCallbackPage /> },
|
{ path: '/auth/callback', element: <AuthCallbackPage /> },
|
||||||
@ -15,7 +16,11 @@ const router = createBrowserRouter([
|
|||||||
{ path: '/logout', element: <LogoutPage /> },
|
{ path: '/logout', element: <LogoutPage /> },
|
||||||
{
|
{
|
||||||
path: '/',
|
path: '/',
|
||||||
element: <RootLayout />,
|
element: (
|
||||||
|
<RequireAuth>
|
||||||
|
<RootLayout />
|
||||||
|
</RequireAuth>
|
||||||
|
),
|
||||||
children: [
|
children: [
|
||||||
{ index: true, element: <DashboardPage /> },
|
{ index: true, element: <DashboardPage /> },
|
||||||
{ path: 'households/:householdId/board', element: <HouseholdBoardPage /> },
|
{ path: 'households/:householdId/board', element: <HouseholdBoardPage /> },
|
||||||
|
|||||||
@ -2,8 +2,16 @@ import { useQuery } from '@tanstack/react-query'
|
|||||||
import { fetchMe } from './api'
|
import { fetchMe } from './api'
|
||||||
|
|
||||||
export function MeBadge() {
|
export function MeBadge() {
|
||||||
const { data, isLoading, isError } = useQuery({ queryKey: ['me'], queryFn: fetchMe, retry: 0 })
|
const hasToken = !!sessionStorage.getItem('access_token')
|
||||||
|
const { data, isLoading, isError } = useQuery({
|
||||||
|
queryKey: ['me'],
|
||||||
|
queryFn: fetchMe,
|
||||||
|
enabled: hasToken, // 👈 vänta tills token finns
|
||||||
|
retry: 0,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!hasToken) return <span className="opacity-60">ej inloggad</span>
|
||||||
if (isLoading) return <span className="opacity-60">…</span>
|
if (isLoading) return <span className="opacity-60">…</span>
|
||||||
if (isError) return <span className="opacity-60">ej inloggad</span>
|
if (isError) return <span className="opacity-60">fel</span>
|
||||||
return <span className="opacity-80 text-sm">{data?.name || data?.preferred_username || 'me'}</span>
|
return <span className="opacity-80 text-sm">{data?.name || data?.preferred_username || 'me'}</span>
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,15 +1,29 @@
|
|||||||
import { useEffect } from 'react'
|
// src/pages/AuthCallbackPage.tsx
|
||||||
|
import { useEffect, useRef } from 'react'
|
||||||
import { useNavigate } from 'react-router-dom'
|
import { useNavigate } from 'react-router-dom'
|
||||||
import { userManager } from 'auth/oidc'
|
import { userManager } from 'auth/oidc'
|
||||||
|
|
||||||
|
|
||||||
export default function AuthCallbackPage() {
|
export default function AuthCallbackPage() {
|
||||||
const navigate = useNavigate()
|
const navigate = useNavigate()
|
||||||
useEffect(() => {
|
const handled = useRef(false)
|
||||||
userManager.signinRedirectCallback().then((res) => {
|
|
||||||
const target = (res?.state as any)?.returnTo || '/'
|
useEffect(() => {
|
||||||
navigate(target, { replace: true })
|
if (handled.current) return // 👈 skydd mot StrictMode dubbelkörning
|
||||||
})
|
handled.current = true
|
||||||
}, [navigate])
|
|
||||||
return <p>Completing sign-in…</p>
|
;(async () => {
|
||||||
}
|
try {
|
||||||
|
const res = await userManager.signinRedirectCallback()
|
||||||
|
const target = (res?.state as any)?.returnTo || '/'
|
||||||
|
// Städa bort ?code&state ur URL:en:
|
||||||
|
window.history.replaceState({}, '', target)
|
||||||
|
navigate(target, { replace: true })
|
||||||
|
} catch (err) {
|
||||||
|
console.error('signinRedirectCallback failed:', err)
|
||||||
|
navigate('/', { replace: true })
|
||||||
|
}
|
||||||
|
})()
|
||||||
|
}, [navigate])
|
||||||
|
|
||||||
|
return <p>Completing sign-in…</p>
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user