# Entrar com Beeuni

Proteja o acesso ao seu próprio app com a identidade Beeuni usando uma única rota e atue como o usuário autenticado por meio do SDK.

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

"Entrar com Beeuni" torna o Beeuni o provedor de identidade de um app que você executa:
um painel, uma ferramenta interna, um produto vertical criado sobre o Beeuni. Seus usuários
entram com a conta Beeuni, seu servidor sabe quem eles são, e cada
chamada ao Beeuni feita pelo seu app é executada como esse usuário, com as atribuições de função
dele. Todo o fluxo fica em `@beeuni/sdk`. Seu app nunca armazena um
token Beeuni no navegador.

É o OAuth 2.1 padrão (código de autorização + PKCE), servido pela API Beeuni
em `api.beeuni.ai`.

> Está criando um App **hospedado pelo Beeuni** (`*.apps.beeuni.ai`)? Você não precisa de nada
> disso. O controle de acesso dos Apps já autenticou o visitante — leia seus dados com
> `beeuniAppViewerToken()` / `readAppViewer()` e obtenha tokens de login para o
> App ou um App que ele usa com `beeuniToken()`. Veja
> [Tokens de login para Apps](#sign-in-tokens-for-apps) abaixo.

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

## 1. Registre seu app

Acesse **Account → Tokens → OAuth apps → Register app** ou chame o 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)
```

O registro exige `token.create` na conta. Os URIs de redirecionamento são comparados
byte a byte; `https` é obrigatório, exceto em `localhost`.

| Escopo | Concede ao app |
|---|---|
| `profile` | O id, o e-mail e as associações a contas do usuário (`GET /v1/accounts/me`). |
| `email` | O endereço de e-mail (um alias para clientes com formato OIDC). |
| `beeuni` | Atuar como o usuário em toda a API Beeuni — projetos, sessões, arquivos, verificações de IAM. Sem ele, o token serve apenas para identidade. |

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

## 2. Monte o 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 };
```

O handler atende todas as rotas em `basePath` (derivado do URI de
redirecionamento — `/api/beeuni/auth` acima):

| Caminho | Ação |
|---|---|
| `/signin?return_to=/path` | Inicia o login (PKCE S256 + state em um cookie de 10 minutos) e redireciona para o Beeuni. |
| `/callback` | Troca o código, define o cookie de sessão criptografado `HttpOnly` e redireciona para `return_to`. |
| `/refresh?return_to=` | Rotaciona o par de tokens e redireciona. Usado por `requireViewer`. |
| `/signout?return_to=` | Revoga o token de atualização no Beeuni e remove o cookie. |
| `/me` | O visitante em JSON, ou `401`. Atualiza durante a própria chamada quando o token de acesso expirou. |
| `/proxy/*` | Encaminha para a API Beeuni como o visitante. O `backendUrl` do SDK do navegador. |

`return_to` é sempre restrito a um caminho da mesma origem.

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

## 3. Restrinja o acesso às páginas e atue como o usuário

```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()` é somente leitura e nunca consome o token de atualização de uso único; use
`requireViewer()` no middleware para que uma página nunca seja renderizada como desconectada para um usuário
cujo token de atualização ainda é válido.

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

## 4. O navegador

```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" />;
}
```

O cliente do navegador envia um bearer sentinela; `/proxy` o substitui pelo
token real do visitante no servidor. `useSession`, `beeuni.project(id).sessions.*` e
todas as outras chamadas do SDK funcionam sem alterações por meio dele.

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

## O que o usuário vê

Na primeira vez, o Beeuni mostra uma tela de consentimento com o nome do seu app e os escopos.
O Beeuni lembra a decisão por usuário e app, então os logins seguintes redirecionam
diretamente de volta. Revogar um app exclui todos os tokens que ele emitiu.

<a id="discovery"></a>

## Descoberta

`GET https://api.beeuni.ai/.well-known/oauth-authorization-server` (também
em `/v1/oauth/.well-known/…`) publica os endpoints para um cliente OAuth
genérico. O SDK não precisa disso — ele deriva todos os endpoints de `backendUrl`.

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

## Tokens de login para Apps

O código em um App hospedado pelo Beeuni, e nos Apps que ele usa, aceita um segundo tipo
de token: um JWT ES256 curto que o Beeuni emite para um App. Sem fluxo OAuth, sem
redirecionamento, sem segredo do cliente.

| | Valor |
|---|---|
| Emissor | `<API origin>/v1/projects/<projectId>`, um por projeto |
| Descoberta | `<issuer>/.well-known/openid-configuration` e `<issuer>/jwks.json`, públicos |
| Público-alvo | O id do App ao qual o token se destina |
| Validade | 15 minutos |
| Claims | `sub`, `email`, `name`, `picture`, `groups`, `group_ids`, `role`, `account_id`, `project_id`; o token de um agente adiciona `kind: "agent"` e não tem grupos nem função |

Cada App contém os valores que verificam seus tokens: `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'] });
```

Em um App de servidor, o Beeuni injeta `BEEUNI_AUTH_ISSUER` (o emissor do projeto),
`BEEUNI_AUTH_AUDIENCE` (o id do próprio App) e `BEEUNI_AUTH_JWKS` (o conjunto de
chaves do projeto, como um URI `data:`), então `verifyBeeuniToken(bearer)` não precisa de opções.
Não defina `BEEUNI_AUTH_*` por conta própria: o prefixo `BEEUNI_` é reservado e
`beeuni validate` o rejeita.

`verifyBeeuniToken` recusa um token quando nenhum público-alvo está definido (a opção ou
`BEEUNI_AUTH_AUDIENCE`): uma chave do projeto assina os tokens de todos os Apps do
projeto, então `aud` é o que impede a entrada do token de outro App. Passe
`audience: false` apenas para aceitar um token de qualquer App do projeto.

`beeuniToken` lê `GET /_beeuni/token?audience=<slug or id>` na origem do
próprio App. O público-alvo é o próprio App (o padrão) ou um App que ele usa
(`beeuni apps link <app> --uses <other>`); qualquer outro retorna
`403 app_not_linked`. Um membro, um script ou um agente emite um token pela API
em vez disso: `beeuni.project(projectId).apps.token(appId)`, ou
`beeuni apps token <app>`. O contrato completo, a montagem dos bindings e a
configuração do backend Convex: [SDK → Apps](/docs/pt/sdk/apps) e
[Apps → Apps que um App usa](/docs/pt/feature-flags/apps#apps-an-app-uses-sign-in-tokens-and-bindings).
