# Accedi con Beeuni

Proteggi l'accesso alla tua app con l'identità Beeuni tramite un'unica route e agisci come l'utente autenticato tramite l'SDK.

Canonical page: https://beeuni.ai/docs/it/sdk/sign-in

"Accedi con Beeuni" rende Beeuni il provider di identità per un'app che gestisci:
una dashboard, uno strumento interno, un prodotto verticale basato su Beeuni. I tuoi utenti
accedono con il loro account Beeuni, il tuo server sa chi sono e ogni
chiamata Beeuni effettuata dalla tua app viene eseguita come quell'utente, con le sue
assegnazioni di ruolo. L'intero flusso risiede in `@beeuni/sdk`. La tua app non memorizza mai un
token Beeuni nel browser.

È OAuth 2.1 standard (codice di autorizzazione + PKCE), fornito dall'API Beeuni
su `api.beeuni.ai`.

> Stai creando un'App **ospitata da Beeuni** (`*.apps.beeuni.ai`)? Non ti serve nulla di
> tutto questo. Il controllo di accesso delle Apps ha già autenticato l'utente: leggine i dati con
> `beeuniAppViewerToken()` / `readAppViewer()` e ottieni i token di accesso per
> l'App o per un'App che utilizza con `beeuniToken()`. Vedi
> [Token di accesso per le Apps](#sign-in-tokens-for-apps) qui sotto.

<a id="1-register-your-app"></a>

## 1. Registra la tua app

Vai a **Account → Tokens → OAuth apps → Register app**, oppure chiama l'SDK:

```ts
const app = await beeuni.iam.oauthClients.create(accountId, {
  name: 'Dashboards',
  client_type: 'confidential',            // 'public' for a browser/native app (PKCE only, no secret)
  redirect_uris: ['https://dashboards.example.com/api/beeuni/auth/callback'],
  scopes: ['profile', 'email', 'beeuni'],
});
// app.client_id, app.client_secret (shown once)
```

La registrazione richiede `token.create` sull'account. Gli URI di reindirizzamento vengono confrontati
byte per byte; `https` è obbligatorio tranne su `localhost`.

| Ambito | Concede all'app |
|---|---|
| `profile` | L'id, l'email e le appartenenze agli account dell'utente (`GET /v1/accounts/me`). |
| `email` | L'indirizzo email (un alias per i client conformi a OIDC). |
| `beeuni` | La possibilità di agire come l'utente sull'intera API Beeuni: progetti, sessioni, file, verifiche IAM. Senza questo ambito, il token serve solo per l'identità. |

<a id="2-mount-the-handler"></a>

## 2. Monta l'handler

```ts
// lib/beeuni-auth.ts
import { createBeeuniAuth } from '@beeuni/sdk/server';

export const auth = createBeeuniAuth({
  backendUrl: 'https://api.beeuni.ai/v1',
  clientId: process.env.BEEUNI_OAUTH_CLIENT_ID!,
  clientSecret: process.env.BEEUNI_OAUTH_CLIENT_SECRET,   // omit for a public client
  redirectUri: 'https://dashboards.example.com/api/beeuni/auth/callback',
  cookieSecret: process.env.BEEUNI_AUTH_COOKIE_SECRET!,   // ≥ 32 chars; encrypts the session cookie
});
```

```ts
// app/api/beeuni/auth/[...beeuni]/route.ts  (Next.js App Router)
import { auth } from '@/lib/beeuni-auth';
const handle = (request: Request) => auth.handler(request);
export { handle as GET, handle as POST };
```

L'handler gestisce ogni route sotto `basePath` (derivato dall'URI di
reindirizzamento: `/api/beeuni/auth` qui sopra):

| Percorso | Funzione |
|---|---|
| `/signin?return_to=/path` | Avvia l'accesso (PKCE S256 + state in un cookie di 10 minuti) e reindirizza a Beeuni. |
| `/callback` | Scambia il codice, imposta il cookie di sessione crittografato `HttpOnly` e reindirizza a `return_to`. |
| `/refresh?return_to=` | Ruota la coppia di token e reindirizza. Usato da `requireViewer`. |
| `/signout?return_to=` | Revoca il token di aggiornamento su Beeuni ed elimina il cookie. |
| `/me` | L'utente corrente in formato JSON, oppure `401`. Esegue l'aggiornamento direttamente quando il token di accesso è scaduto. |
| `/proxy/*` | Inoltra all'API Beeuni come utente corrente. Il `backendUrl` dell'SDK per il browser. |

`return_to` è sempre limitato a un percorso della stessa origine.

<a id="3-gate-pages-and-act-as-the-user"></a>

## 3. Proteggi l'accesso alle pagine e agisci come l'utente

```ts
// middleware.ts — every page needs a viewer
import { auth } from '@/lib/beeuni-auth';

export async function middleware(request: Request) {
  const gate = await auth.requireViewer(request);
  if (gate.response) return gate.response;   // 302 → /refresh or /signin
}
export const config = { matcher: ['/((?!api/beeuni/auth|_next).*)'] };
```

```ts
// a server component / route handler
const viewer = await auth.viewer(request);       // { userId, email, accounts, scopes, token, expiresAt } | null
const beeuni = await auth.beeuni(request);       // request-scoped client acting as the viewer
const projects = await beeuni.projects.list();
const allowed = await beeuni.iam.can(accountId, viewer!.userId, { action: 'project.write', resourceType: 'project', resourceId });
```

`viewer()` è di sola lettura e non consuma mai il token di aggiornamento monouso; usa
`requireViewer()` nel middleware affinché una pagina non venga mai renderizzata come se l'utente non fosse autenticato
quando il suo token di aggiornamento è ancora valido.

<a id="4-the-browser"></a>

## 4. Il browser

```tsx
import { createBeeuni } from '@beeuni/sdk';
import { SignInWithBeeuni, useBeeuniViewer } from '@beeuni/sdk/react';

const beeuni = createBeeuni(auth.clientConfig());   // backendUrl = '/api/beeuni/auth/proxy'

function Header() {
  const { status, viewer } = useBeeuniViewer();
  if (status === 'signed-in') return <span>{viewer.email}</span>;
  return <SignInWithBeeuni className="button" />;
}
```

Il client del browser invia un bearer sentinella; `/proxy` lo sostituisce con il
token reale dell'utente corrente sul server. `useSession`, `beeuni.project(id).sessions.*` e
ogni altra chiamata SDK funzionano senza modifiche tramite questo meccanismo.

<a id="what-the-user-sees"></a>

## Cosa vede l'utente

La prima volta, Beeuni mostra una schermata di consenso che indica il nome della tua app e gli ambiti.
Beeuni ricorda la decisione per ogni utente e app, quindi gli accessi successivi reindirizzano
direttamente all'app. La revoca di un'app elimina tutti i token che ha emesso.

## Discovery

`GET https://api.beeuni.ai/.well-known/oauth-authorization-server` (anche
sotto `/v1/oauth/.well-known/…`) pubblica gli endpoint per un client OAuth
generico. L'SDK non ne ha bisogno: ricava ogni endpoint da `backendUrl`.

<a id="sign-in-tokens-for-apps"></a>

## Token di accesso per le Apps

Il codice in un'App ospitata da Beeuni e nelle Apps che utilizza accetta un secondo tipo
di token: un JWT ES256 breve che Beeuni emette per una singola App. Nessun flusso OAuth, nessun
reindirizzamento, nessun segreto client.

| | Valore |
|---|---|
| Emittente | `<API origin>/v1/projects/<projectId>`, uno per progetto |
| Discovery | `<issuer>/.well-known/openid-configuration` e `<issuer>/jwks.json`, pubblici |
| Destinatario | L'id dell'App a cui è destinato il token |
| Durata | 15 minuti |
| Claim | `sub`, `email`, `name`, `picture`, `groups`, `group_ids`, `role`, `account_id`, `project_id`; il token di un agente aggiunge `kind: "agent"` e non ha gruppi né ruolo |

Ogni App contiene i valori per verificare i propri token: `app.auth.issuer`,
`app.auth.audience`, `app.auth.jwks_uri`.

```ts
import { beeuniToken, beeuniBinding, verifyBeeuniToken, requireBeeuniMember } from '@beeuni/sdk';

// In the App's browser code: a token fetcher for this App, or an App it uses.
const forThisApp = beeuniToken();
const forDb = beeuniToken({ audience: 'db' });
const db = beeuniBinding('db');   // { url: '<origin>/_beeuni/apps/db', token: forDb }

// On a server that receives the token:
const member = await verifyBeeuniToken(bearer, {
  issuer: app.auth.issuer,
  audience: app.auth.audience,
  jwks: app.auth.jwks_uri,
});
requireBeeuniMember(member, { roles: ['owner', 'admin'] });
```

In un'App server, Beeuni inietta `BEEUNI_AUTH_ISSUER` (l'emittente del progetto),
`BEEUNI_AUTH_AUDIENCE` (l'id dell'App stessa) e `BEEUNI_AUTH_JWKS` (il set di chiavi del progetto,
come URI `data:`), quindi `verifyBeeuniToken(bearer)` non richiede opzioni.
Non impostare `BEEUNI_AUTH_*` autonomamente: il prefisso `BEEUNI_` è riservato e
`beeuni validate` lo rifiuta.

`verifyBeeuniToken` rifiuta un token quando non è impostato alcun destinatario (tramite l'opzione o
`BEEUNI_AUTH_AUDIENCE`): una sola chiave del progetto firma i token di tutte le Apps del
progetto, quindi è `aud` a impedire l'accesso con il token di un'altra App. Passa
`audience: false` solo per accettare un token destinato a qualsiasi App del progetto.

`beeuniToken` legge `GET /_beeuni/token?audience=<slug or id>` sull'origine
dell'App stessa. Il destinatario è l'App stessa (per impostazione predefinita) o un'App che utilizza
(`beeuni apps link <app> --uses <other>`); per qualsiasi altro destinatario, la risposta è
`403 app_not_linked`. Un membro, uno script o un agente ne emette invece uno tramite l'API:
`beeuni.project(projectId).apps.token(appId)`, oppure
`beeuni apps token <app>`. Il contratto completo, il montaggio dei binding e la
configurazione del backend Convex: [SDK → Apps](/docs/it/sdk/apps) e
[Apps → Apps utilizzate da un'App](/docs/it/feature-flags/apps#apps-an-app-uses-sign-in-tokens-and-bindings).
