# Emissão de token no backend

Troque a credencial da integração por acesso curto, mínimo e vinculado ao usuário do seu host.

[Abrir a versão HTML](https://rhizzalab.com/docs/integration/backend-token)

## A credencial nunca atravessa a fronteira

`createReportPlatformClient` é server-only. A troca usa autenticação Basic entre servidores e a rota de emissão não aceita CORS de navegador. Entregue ao cliente somente `accessToken`, `tokenType` e `expiresIn`.

```ts filename="app/api/rhizzadocs/token/route.ts"
import "server-only"

import { createReportPlatformClient } from "@rhizzalab/report-node"
import { NextResponse } from "next/server"

import { requireAuthenticatedUser } from "@/lib/auth"

export const runtime = "nodejs"

function requiredEnv(name: string): string {
  const value = process.env[name]
  if (!value) throw new Error("Variável ausente: " + name)
  return value
}

const reports = createReportPlatformClient({
  clientId: requiredEnv("RHIZZADOCS_CLIENT_ID"),
  clientSecret: requiredEnv("RHIZZADOCS_CLIENT_SECRET"),
  apiBaseUrl: process.env.RHIZZADOCS_API_URL,
})

export async function POST(request: Request) {
  // Esta função pertence ao seu host: valide a sessão antes da troca.
  const user = await requireAuthenticatedUser(request)

  const token = await reports.issueEditorToken({
    userId: user.id,
    workspaceId: user.companyId,
    reports: [
      {
        reportType: "acme.relatorio-mensal",
        scopes: ["editor:read", "templates:read", "export:pdf"],
      },
    ],
  })

  return NextResponse.json(token)
}
```

## Derive identidade e acesso no host

* `userId`: id estável do usuário autenticado no seu sistema, entre 1 e 255 caracteres.

* `workspaceId`: contexto opcional do host, também entre 1 e 255 caracteres; não é autorização.

* `reports`: lista não vazia de pares `reportType` + `scopes`.

* `scopes`: somente capacidades que a tela realmente precisa naquele momento.

> **Atenção: Não faça proxy de autorização**
>
> Não copie `userId`, `reportType` ou escopos de um body arbitrário. Mapeie-os a partir da sessão, da rota e das permissões já verificadas pelo host.

## Renove sem refresh token

O token dura 10 minutos por padrão e nunca pode exceder 15 minutos. Quando o editor sinalizar `AUTH_REQUIRED`, chame novamente a sua rota autenticada e substitua o JWT em memória.

Se a sessão do próprio host expirou, não tente renovar em loop. Redirecione o usuário para o login do host e preserve a explicação de que a autenticação principal terminou.

## Trate os erros do Node SDK

| `kind`       | Significado                          | Ação típica                                   |
| ------------ | ------------------------------------ | --------------------------------------------- |
| `validation` | Pedido inválido antes da rede        | Corrigir o mapeamento do host                 |
| `api`        | API respondeu fora de 2xx            | Usar `status`, `code`, `requestId` e `issues` |
| `network`    | Timeout, DNS, TLS ou fetch rejeitado | Aplicar retry limitado e observabilidade      |
| `contract`   | Resposta 2xx fora do contrato        | Interromper e investigar incompatibilidade    |

```ts
import { isReportNodeError } from "@rhizzalab/report-node"

try {
  return await reports.issueEditorToken(request)
} catch (error) {
  if (isReportNodeError(error)) {
    logger.warn({
      kind: error.kind,
      code: error.code,
      status: error.status,
      requestId: error.requestId,
    })
  }
  throw error
}
```
