|
| 1 | +--- |
| 2 | +links: |
| 3 | + - label: Auth Service |
| 4 | + to: https://jamflow.cloud/auth-service |
| 5 | +title: "Client Guide" |
| 6 | +description: "Autenticazione e autorizzazione sul lato client" |
| 7 | +navigation: |
| 8 | + icon: i-lucide-chromium |
| 9 | +--- |
| 10 | + |
| 11 | +Questo modulo fornisce una serie di composables Vue e plugin Nuxt che facilitano l'integrazione con Jamflow Auth Service nelle applicazioni Nuxt. Qui trovi i principali strumenti lato client, come comunicano con il backend Auth e come integrarli nella tua app. |
| 12 | + |
| 13 | +::warning |
| 14 | +**Prerequisiti** |
| 15 | + |
| 16 | +- Il tuo contratto deve includere un'istanza di Auth Service. |
| 17 | +- Il modulo deve essere registrato in `nuxt.config.ts` e configurato con almeno `issuer` e `audience`. |
| 18 | +- I cookie per ID, access e refresh token sono gestiti automaticamente dal modulo; assicurati che il tuo ambiente di deploy non li blocchi. |
| 19 | +:: |
| 20 | + |
| 21 | +## Bootstrap della sessione |
| 22 | + |
| 23 | +Due plugin Nuxt si occupano di mantenere la sessione aggiornata durante navigazione e idratazione: |
| 24 | + |
| 25 | +- `session.server`: viene eseguito prima del render sul server. Popola il payload con una flag `isCached` e, quando la richiesta è renderizzata al volo, chiama `useUserSession().fetch()` per decodificare gli ID e access token più recenti. |
| 26 | +- `session.client`: viene eseguito sul client durante l'idratazione. Se la pagina è stata consegnata da cache del payload o da prerendering statico, recupera la sessione dopo il mount dell'app per evitare dati obsoleti. |
| 27 | + |
| 28 | +Non è necessario importare manualmente questi plugin: vengono registrati automaticamente all'installazione del modulo. |
| 29 | + |
| 30 | +## `useUserSession()` |
| 31 | + |
| 32 | +`useUserSession` è il composable principale esposto dal modulo. Si occupa di rinfrescare i cookie in modo trasparente, comunicare con le route proxy del server e fornire uno stato reattivo per l'utente autenticato. |
| 33 | + |
| 34 | +```ts |
| 35 | +const { |
| 36 | + user, // Computed<IDTokenClaims | null> |
| 37 | + access, // Computed<AccessTokenClaims | null> |
| 38 | + loggedIn, // Computed<boolean> |
| 39 | + login, |
| 40 | + requestAccess, |
| 41 | + fetch, |
| 42 | + refresh, |
| 43 | + clear, |
| 44 | +} = useUserSession() |
| 45 | +``` |
| 46 | + |
| 47 | +### Accesso allo stato |
| 48 | + |
| 49 | +- `user`: claim dell'ID token (sub, email, team, ecc.). `null` quando il visitatore è anonimo o il token non è verificabile. |
| 50 | +- `access`: claim dell'access token, inclusi i codici di permesso serializzati usati da `usePermissions`. |
| 51 | +- `loggedIn`: booleano di comodo derivato da `user`. |
| 52 | + |
| 53 | +### Azioni |
| 54 | + |
| 55 | +- `login(email, password)`: Chiama `/_auth-api/auth/login`, imposta i cookie, recupera i permessi di accesso e risolve quando la sessione è pronta. |
| 56 | +- `requestAccess(teamId?)`: Richiede manualmente un access token aggiornato per l'utente corrente. Utile quando si cambia contesto team. |
| 57 | +- `fetch()`: Rilegge i cookie, valida i token contro il JWKS e aggiorna lo stato locale. Di solito non serve chiamarla direttamente perché i plugin la gestiscono. |
| 58 | +- `refresh()`: Usa l'endpoint di refresh per ottenere nuovi ID e access token. |
| 59 | +- `clear()`: Disconnette l'utente cancellando i cookie tramite `/_auth-api/auth/session` e resettando lo stato in memoria. |
| 60 | + |
| 61 | +### Uso nei diversi contesti di fetch |
| 62 | + |
| 63 | +Il composable seleziona automaticamente tra `$fetch` client e `$fetch` request-scoped sul server. Questo è importante quando si scrivono plugin o middleware personalizzati: lo stesso codice funziona in componenti, route server e handler Nitro senza configurazioni aggiuntive. |
| 64 | + |
| 65 | +## Gestire i permessi con `usePermissions()` |
| 66 | + |
| 67 | +I permessi sono codificati nell'access token come codici brevi (es. `@blog:cru` per create/read/update globali sul topic `blog`). `usePermissions` traduce queste stringhe in una struttura dati descrittiva e fornisce helper per proteggere UI e pagine. |
| 68 | + |
| 69 | +```ts |
| 70 | +const { permissions, hasPermission, pagePermission } = usePermissions() |
| 71 | +``` |
| 72 | + |
| 73 | +- `permissions`: oggetto computed di tipo `DecryptedPermissions` che separa gli ambiti `team` e `global`. |
| 74 | +- `hasPermission(check)`: Restituisce `true` se l'access token corrente concede tutte le azioni richieste per uno specifico topic. Imposta `check.team = true` per valutare i permessi a livello di team; altrimenti si controlla l'ambito globale. |
| 75 | +- `pagePermission(check, { redirect? })`: Restituisce l'oggetto `ResourcePermissions` completo per il topic. Se l'utente non ha accesso puoi abilitare un redirect (di default `'/'`). Senza redirect restituisce un oggetto con tutte le azioni a `false`, utile per renderizzare uno stato di avviso. |
| 76 | + |
| 77 | +### Esempio: proteggere una pagina |
| 78 | + |
| 79 | +```vue |
| 80 | +const { pagePermission } = usePermissions() |
| 81 | +
|
| 82 | +<script setup lang="ts"> |
| 83 | +const blogPerms = await pagePermission({ |
| 84 | + topic: 'blog-posts', |
| 85 | + actions: ['read'], |
| 86 | +}) |
| 87 | +</script> |
| 88 | +
|
| 89 | +<template> |
| 90 | + <section v-if="blogPerms.read"> |
| 91 | + <!-- Contenuto protetto --> |
| 92 | + </section> |
| 93 | + <NuxtErrorBoundary v-else> |
| 94 | + <p>Non hai ancora accesso ai post del blog.</p> |
| 95 | + </NuxtErrorBoundary> |
| 96 | +</template> |
| 97 | +``` |
| 98 | + |
| 99 | +### Esempio: abilitare/disabilitare controlli UI |
| 100 | + |
| 101 | +```vue |
| 102 | +<script setup lang="ts"> |
| 103 | +const { hasPermission } = usePermissions() |
| 104 | +
|
| 105 | +const canPublish = computed(() => hasPermission({ |
| 106 | + topic: 'blog-posts', |
| 107 | + actions: ['execute'], |
| 108 | +})) |
| 109 | +</script> |
| 110 | +
|
| 111 | +<template> |
| 112 | + <UButton :disabled="!canPublish">Publish</UButton> |
| 113 | +</template> |
| 114 | +``` |
| 115 | + |
| 116 | +## Ciclo di vita dei token |
| 117 | + |
| 118 | +- I cookie vengono aggiornati automaticamente ad ogni chiamata a `fetch()` e `refresh()` tramite l'helper `refreshCookie` di Nuxt. |
| 119 | +- Quando un access token è scaduto, `useUserSession` richiede trasparentemente uno nuovo e propaga gli header Set-Cookie dall'API al browser. |
| 120 | +- Le chiavi JWKS vengono memorizzate in memoria per fino a un'ora per ridurre traffico di rete inutile. |
| 121 | + |
| 122 | +## Risoluzione dei problemi |
| 123 | + |
| 124 | +| Sintomo | Probabile causa | Soluzione | |
| 125 | +| --- | --- | --- | |
| 126 | +| `useUserSession().user` è sempre `null` | `issuer` / `audience` runtime mancanti o non validi | Verifica `nuxt.config` e le variabili d'ambiente. | |
| 127 | +| Il login riesce ma i permessi sono vuoti | Access token non richiesto o codici permesso non configurati server-side | Assicurati che `requestAccess()` venga chiamato dopo il login e che l'Auth Service emetta i permessi. | |
| 128 | +| Le navigazioni client perdono la sessione | Cookie bloccati dal dominio o mismatch degli attributi secure | Controlla l'URL base del deploy e la configurazione dei cookie nel servizio. | |
| 129 | + |
| 130 | +## Passi successivi |
| 131 | + |
| 132 | +- Consulta la [Guida server](/it/auth-module/server-guide.md) per le utility Nitro da usare nelle route API. |
| 133 | +- Fai attenzione alla scadenza dei token in tab mantenute a lungo; valuta di chiamare periodicamente `useUserSession().refresh()` se la tua UX lo richiede. |
0 commit comments