Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions apps/app/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ BETTER_AUTH_SECRET=dev-secret-change-in-prod-min32chars!!
# URL de base de l'app (utilisée pour générer les magic-links).
APP_URL=http://localhost:3000

# Claude (API Messages) — analyse d'offre, score de match et génération de CV
# (THI-124 / flux candidature). Sans cette clé, /api/candidature/* répond 502.
ANTHROPIC_API_KEY=sk-ant-changeme

# SMTP (optionnel en dev — si absent, le magic-link est loggé dans la console).
# SMTP_HOST=smtp.example.fr
# SMTP_PORT=587
Expand Down
1 change: 1 addition & 0 deletions apps/app/layouts/default.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ let unsubscribeSession: (() => void) | undefined
const userInitial = computed(() => user.value?.email?.charAt(0)?.toUpperCase() ?? '?')

const navLinks = [
{ label: 'Nouvelle candidature', to: '/candidature' },
{ label: 'Mon profil', to: '/profil' },
{ label: 'Mon CV', to: '/cv/demo' },
] as const
Expand Down
19 changes: 15 additions & 4 deletions apps/app/middleware/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,21 @@
* Middleware de navigation — protège les pages authentifiées.
* Usage : definePageMeta({ middleware: 'auth' }) dans la page.
* Redirige vers /connexion si la session est absente.
*
* La session est vérifiée auprès du serveur Better Auth (GET /api/auth/get-session),
* fiable en SSR (cookies transférés) comme en navigation client. L'atom nanostores
* de useAuth() n'est PAS utilisable ici : l'objet est toujours truthy et la session
* n'est hydratée qu'après le premier fetch côté client — l'ancien check laissait
* passer les visiteurs non connectés (écran d'erreur 401 sur /profil au lieu d'une
* redirection).
*/
export default defineNuxtRouteMiddleware(async () => {
const { session } = useAuth()
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const s = (session as any)?.value ?? session
if (!s) return navigateTo('/connexion')
// En SSR, $fetch interne ne transmet pas les cookies du navigateur tout seul.
const headers = import.meta.server ? useRequestHeaders(['cookie']) : undefined
try {
const session = await $fetch('/api/auth/get-session', { headers })
if (!session) return navigateTo('/connexion')
} catch {
return navigateTo('/connexion')
}
})
Loading
Loading