refactor: auth stuff

This commit is contained in:
2025-09-18 11:39:29 -04:00
parent c82abe88e4
commit 3cc4b570d5
9 changed files with 93 additions and 44 deletions

View File

@@ -1,7 +1,7 @@
<script setup lang="ts">
const props = defineProps<{ showLabels: boolean }>();
const { loggedIn } = useUserSession();
const label = computed(() => props.showLabels ? (loggedIn ? "Déconnexion" : "Connexion") : undefined);
const label = computed(() => props.showLabels ? (loggedIn.value ? "Déconnexion" : "Connexion") : undefined);
</script>
<template>

View File

@@ -3,8 +3,8 @@ import { ThePage, TheArticle, TheEvent, TheLocation, TheMembership, TheProject,
export async function useNodeByUri(uri: string) {
const { data, error } = await useAsyncGraphqlQuery("nodeByUri", { uri }, { graphqlCaching: { client: true } });
if (error.value) {
throw createError({ statusCode: 500, statusMessage: "Erreur serveur", message: error.value.message });
if (error.value || data.value?.errors.length) {
throw createError({ statusCode: 500, statusMessage: "Erreur serveur", message: "Une erreur est survenue." });
}
const node = data.value?.data.nodeByUri;
const breadcrumbs = node?.breadcrumbs?.map(({ label, to }) => ({ label, to: to || undefined })) || [];

View File

@@ -3,7 +3,7 @@ export function useUserSwitching() {
const { fetch: refreshUserSession } = useUserSession();
const { session } = useUserSession();
const isUserSwitched = computed(() => Boolean(session.value?.switchedBy));
const isUserSwitched = computed(() => Boolean(session.value?.isSwitchedTo));
async function userSwitchTo(userId: string | number) {
try {

View File

@@ -25,6 +25,7 @@
"@nuxtjs/robots": "5.5.0",
"@nuxtjs/sitemap": "7.4.3",
"@vueuse/nuxt": "13.7.0",
"es-toolkit": "^1.39.10",
"nuxt": "^4.1.2",
"nuxt-auth-utils": "0.5.23",
"nuxt-graphql-middleware": "5.2.0",

View File

@@ -35,6 +35,9 @@ importers:
'@vueuse/nuxt':
specifier: 13.7.0
version: 13.7.0(magicast@0.3.5)(nuxt@4.1.2(@netlify/blobs@9.1.2)(@parcel/watcher@2.5.1)(@types/node@24.4.0)(@vue/compiler-sfc@3.5.21)(db0@0.3.2)(eslint@9.35.0(jiti@2.5.1))(ioredis@5.7.0)(lightningcss@1.30.1)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.50.2)(terser@5.44.0)(typescript@5.9.2)(vite@7.1.5(@types/node@24.4.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1))(vue-tsc@3.0.7(typescript@5.9.2))(yaml@2.8.1))(vue@3.5.21(typescript@5.9.2))
es-toolkit:
specifier: ^1.39.10
version: 1.39.10
nuxt:
specifier: ^4.1.2
version: 4.1.2(@netlify/blobs@9.1.2)(@parcel/watcher@2.5.1)(@types/node@24.4.0)(@vue/compiler-sfc@3.5.21)(db0@0.3.2)(eslint@9.35.0(jiti@2.5.1))(ioredis@5.7.0)(lightningcss@1.30.1)(magicast@0.3.5)(optionator@0.9.4)(rollup@4.50.2)(terser@5.44.0)(typescript@5.9.2)(vite@7.1.5(@types/node@24.4.0)(jiti@2.5.1)(lightningcss@1.30.1)(terser@5.44.0)(yaml@2.8.1))(vue-tsc@3.0.7(typescript@5.9.2))(yaml@2.8.1)
@@ -3305,6 +3308,9 @@ packages:
resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==}
engines: {node: '>= 0.4'}
es-toolkit@1.39.10:
resolution: {integrity: sha512-E0iGnTtbDhkeczB0T+mxmoVlT4YNweEKBLq7oaU4p11mecdsZpNWOglI4895Vh4usbQ+LsJiuLuI2L0Vdmfm2w==}
esbuild@0.25.4:
resolution: {integrity: sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q==}
engines: {node: '>=18'}
@@ -9767,6 +9773,8 @@ snapshots:
es-errors: 1.3.0
optional: true
es-toolkit@1.39.10: {}
esbuild@0.25.4:
optionalDependencies:
'@esbuild/aix-ppc64': 0.25.4

View File

@@ -2,8 +2,7 @@ import { defineEventHandler } from "h3";
export default defineEventHandler(async (event) => {
try {
// TODO: Switch back to the previous user.
await clearUserSession(event);
await handleSwitchBack(event);
return { success: true };
}
catch (error) {

View File

@@ -32,44 +32,15 @@ export default defineGraphqlServerOptions({
return { headers: { ...headers, Authorization: `Bearer ${session.secure.authToken}` } };
},
onServerResponse(event, response, _operation, operationName) {
// Handle login mutation
if (operationName === "login") {
const loginData = response._data as LoginRootMutation;
if (loginData?.login) {
const { authToken, refreshToken, user } = loginData.login;
setUserSession(event, {
user: {
id: user?.id,
email: user?.email,
},
secure: {
authToken,
refreshToken,
},
});
}
async onServerResponse(event, response, _operation, operationName) {
switch (operationName) {
case "login":
await handleLogin(event, response._data!.data as LoginRootMutation);
break;
case "userSwitchTo":
await handleSwitchTo(event, response._data!.data as UserSwitchToRootMutation);
break;
}
// Handle user switch mutations
if (operationName === "userSwitchTo") {
const switchData = response._data as UserSwitchToRootMutation;
if (switchData?.userSwitchTo?.authToken) {
const { authToken, refreshToken, user } = switchData.userSwitchTo;
setUserSession(event, {
user: {
id: user?.id,
email: user?.email,
},
secure: {
authToken,
refreshToken,
},
});
}
}
// Return the original response data
return response._data!;
},
});

View File

@@ -0,0 +1,65 @@
import type { LoginRootMutation, UserSwitchToRootMutation } from "#graphql-operations";
import type { H3Event } from "h3";
import { pick } from "es-toolkit/compat";
export async function handleLogin(event: H3Event, loginData?: LoginRootMutation) {
if (!loginData?.login?.user) {
return;
}
const { authToken, refreshToken, user } = loginData.login;
await setUserSession(event, {
user: {
id: user.id,
email: user.email,
},
secure: {
authToken,
refreshToken,
},
loggedInAt: new Date().toISOString(),
isSwitchedTo: false,
});
}
export async function handleLogout(event: H3Event) {
await clearUserSession(event);
}
export async function handleSwitchTo(event: H3Event, data?: UserSwitchToRootMutation) {
if (!data?.userSwitchTo?.user) {
return;
}
const session = await getUserSession(event);
const { authToken, refreshToken, user } = data.userSwitchTo;
await setUserSession(event, {
user: {
id: user.id,
email: user.email,
},
secure: {
authToken,
refreshToken,
previous: {
user: session.user,
loggedInAt: session.loggedInAt,
secure: pick(session.secure, ["authToken", "refreshToken"]),
},
},
loggedInAt: new Date().toISOString(),
isSwitchedTo: true,
});
}
export async function handleSwitchBack(event: H3Event) {
const session = await getUserSession(event);
if (!session.secure?.previous) {
return;
}
const { user, loggedInAt, secure } = session.secure.previous;
await setUserSession(event, {
user,
secure,
loggedInAt,
isSwitchedTo: false,
});
}

View File

@@ -7,12 +7,17 @@ declare module "#auth-utils" {
interface UserSession {
loggedInAt: string;
switchedBy?: number;
isSwitchedTo: boolean;
}
interface SecureSessionData {
authToken: string;
refreshToken: string;
previous?: {
user: User;
loggedInAt: string;
secure: Pick<SecureSessionData, ["authToken", "refreshToken"]>;
};
}
}