# Apps OAuth

> Registre um app OAuth, envie os usuários à tela de consentimento do Nodaro, troque o código por um token de acesso de 90 dias e chame a API em nome deles.

Source: https://nodaro.ai/pt-BR/docs/developers/oauth

Um **app OAuth** permite que o seu produto chame a API do Nodaro em nome de outros usuários do Nodaro. Cada usuário aprova o seu app em uma tela de consentimento, o seu servidor troca o código resultante por um token de acesso, e toda chamada com esse token age como esse usuário, limitada aos escopos que ele concedeu. O Nodaro implementa o fluxo padrão de código de autorização do OAuth 2.0, com PKCE para clientes que não conseguem guardar um segredo.

Os apps de desenvolvedor estão disponíveis no Nodaro Cloud e nas instalações da Business edition.

## OAuth ou token de API pessoal
| Você está criando | Use | Formato do token |
| --- | --- | --- |
| Um script, um cron job, um job de CI ou um backend que usa a sua própria conta | Um token de API pessoal | `ndr_` seguido de 64 caracteres hexadecimais |
| Um produto hospedado cujos usuários têm as próprias contas do Nodaro | Um app OAuth | `ndr_app_` seguido de 64 caracteres hexadecimais |

Use um **token de API pessoal** quando só a sua própria conta se autentica e você não precisa de tela de consentimento nem de revogação por usuário. Veja [Autenticação](https://nodaro.ai/docs/developers/api/authentication).

Use **OAuth** nestes casos:

- Você cria um produto hospedado, como um app web, um SaaS ou um marketplace, e os seus usuários têm as próprias contas do Nodaro.
- Cada usuário concede ao seu app só uma parte do que a conta dele pode fazer.
- Cada usuário pode cortar o acesso do seu app a qualquer momento, sem afetar outros apps.

## Como o fluxo funciona
1. O usuário clica em **Conectar ao Nodaro** no seu site.
2. O seu site envia o navegador para a página `/oauth/authorize` do Nodaro com o seu `client_id`, `redirect_uri`, `scope` e `state`.
3. O Nodaro mostra a tela de consentimento, depois de um login, se necessário. A tela mostra o nome, o logotipo e os escopos solicitados do seu app, e a conta que vai conceder o acesso. **Usar outra conta** encerra a sessão do usuário e volta para a mesma tela.
4. O usuário clica em **Permitir**, e o Nodaro cria um código de autorização de uso único.
5. O navegador volta para o seu `redirect_uri` com `?code=...&state=...`.
6. O seu servidor troca o código por um token de acesso em `POST /v1/oauth/token`, com o seu `client_id` e o seu `client_secret`.
7. O seu servidor chama a API do Nodaro com `Authorization: Bearer ndr_app_...` em nome do usuário.

## Registrar o seu app
### Abrir Apps de desenvolvedor
Na instância do Nodaro que você quer usar, abra **Configurações › Apps de desenvolvedor** (`/settings/developer-apps`) e clique em **Criar app**.

### Preencher o formulário
Informe o nome, as URIs de redirecionamento e os escopos. Os campos estão descritos na tabela abaixo.

### Guardar o segredo do cliente
A caixa de diálogo **App criado** mostra o **ID do cliente**, que começa com `app_`, e o **Segredo do cliente**, que começa com `sec_`. O segredo aparece uma única vez. Copie-o para o seu gerenciador de segredos antes de fechar a caixa de diálogo: o Nodaro guarda só um hash dele e não consegue mostrá-lo de novo.

| Campo | Obrigatório | Regras |
| --- | --- | --- |
| **Nome** | Sim | De 1 a 100 caracteres. Aparece na tela de consentimento. |
| **Descrição** | Não | Até 500 caracteres. Aparece abaixo do nome na tela de consentimento. |
| **URIs de redirecionamento** | Sim | De 1 a 10, uma por linha. Cada uma é um endereço `https://`, ou um endereço `http://localhost` para desenvolvimento. O Nodaro as compara byte a byte, e curingas não são aceitos. |
| **Origens permitidas** | Não | Até 5 origens simples, sem caminho, query ou fragmento. Necessárias só se o seu frontend chamar o Nodaro a partir de um navegador (CORS). |
| **Escopos solicitados** | Sim | Pelo menos um. É o máximo que o seu app poderá pedir: os usuários podem conceder menos, e o seu app nunca pode pedir mais. |
| **URL da página inicial**, **URL do logotipo** | Não | Defina-as na página do app depois de criá-lo. Cada uma é um endereço `https://` ou `http://localhost`. Um logotipo quadrado fica melhor. |

### Gerenciar o app
- **Rotacione o segredo** na página do app quando você o perder, ou como prática de segurança de rotina. O segredo antigo para de funcionar na hora, então atualize imediatamente a configuração de todos os serviços em execução.
- **Exclua o app** para revogar todos os tokens de acesso que ele recebeu. Os usuários que o autorizaram precisam se conectar de novo.
- **Cinco apps por usuário.** Os clientes MCP que se registraram sozinhos aparecem na mesma lista, mas não entram no limite.
- **Por código**, o `client.developerApps` do SDK cria, atualiza e exclui apps e rotaciona os segredos deles. Veja o [SDK](https://nodaro.ai/docs/developers/sdk).

## Escopos
Um escopo é uma permissão que o seu app pede. Solicite só os escopos que você usa: os usuários veem todos os escopos solicitados na tela de consentimento, e uma lista curta conquista a confiança deles.

| Escopo | A tela de consentimento diz | O que permite |
| --- | --- | --- |
| `workflows:read` | Ler seus workflows | Listar, ler e exportar workflows. |
| `workflows:write` | Criar e modificar workflows | Criar, atualizar, excluir, importar e mover workflows, e criar sub-workflows. |
| `workflows:execute` | Executar workflows em seu nome | Executar workflows e apps publicados, executar nós de geração individuais pelo MCP e usar o assistente de prompt. |
| `jobs:read` | Ler o status e os resultados das tarefas | Ler os jobs, o status e os resultados deles. |
| `assets:read` | Ler as mídias que você enviou | Ler a galeria, os envios, os favoritos, as execuções de apps, os personagens, os locais, os objetos e as criaturas. |
| `assets:write` | Enviar mídias para sua conta | Enviar mídia, marcar mídias como favoritas e criar e atualizar personagens, locais e objetos. |
| `credits:read` | Ver seu saldo de créditos | Ler o saldo de créditos e as transações de créditos. |
| `apps:read` | Ler apps publicados | Listar os apps publicados e ler as entradas deles. |
| `pipelines:read` | Ler seus pipelines | Ler os pipelines **História → vídeo** (Story → Video), o status deles e as aprovações pendentes. |
| `pipelines:execute` | Executar pipelines em seu nome (isso pode gastar seus créditos) | Iniciar pipelines, executar as etapas deles e criar derivações a partir de uma etapa. |
| `pipelines:approve` | Aprovar etapas de pipelines em seu nome | Aprovar a saída das etapas e usar o chat das etapas e os auxiliares de cena. |
| `presets:read` | Ler suas predefinições salvas | Ler as predefinições de nó e as predefinições favoritas do usuário. |
| `workspaces:read` | Ver os espaços de trabalho de que você faz parte | Listar os espaços de trabalho do usuário. |
| `workspaces:write` | Escolher em qual espaço de trabalho ele atua | Escolher o espaço de trabalho em que o app trabalha. |

- Alguns escopos controlam rotas REST, outros controlam [ferramentas MCP](https://nodaro.ai/docs/mcp/tools), e alguns controlam as duas coisas. O servidor MCP oculta toda ferramenta cujo escopo falta ao token.
- Um token sem o escopo de que uma rota precisa recebe `403 insufficient_scope`, com o escopo que falta em `missingScope`. Veja [Erros](#errors).
- Os escopos de espaço de trabalho nunca são adicionados a um token emitido antes de as organizações existirem. O usuário precisa autorizar o seu app de novo para concedê-los.
- Executar um app publicado exige `workflows:execute` para iniciar a execução e `jobs:read` para ler o progresso dela.

## Levar o usuário à tela de consentimento
Quando o usuário clicar em **Conectar ao Nodaro**, envie o navegador para esta URL:

```text
https://nodaro.example.com/oauth/authorize?
client_id=app_...&
redirect_uri=https://yourapp.com/oauth/callback&
response_type=code&
scope=workflows:read+workflows:execute&
state=<random CSRF token>
```

| Parâmetro | Regra |
| --- | --- |
| `client_id` | O ID do cliente do seu app. |
| `redirect_uri` | Exatamente uma das URIs de redirecionamento registradas, byte a byte. Uma divergência é recusada com `400 invalid_redirect_uri`. |
| `response_type` | Sempre `code`. A tela de consentimento recusa qualquer outro valor. |
| `scope` | Os escopos que você solicita, separados por espaços ou por `+`. Precisam ser um subconjunto dos escopos solicitados do app. |
| `state` | Um token aleatório que você cria para cada autorização e guarda na sessão do usuário. O Nodaro o devolve sem mudanças, e você precisa verificá-lo. |

Crie o `state` no seu servidor:

```ts

// In your /connect handler:
const state = randomBytes(32).toString("hex")
req.session.oauthState = state

const url = new URL("https://nodaro.example.com/oauth/authorize")
url.searchParams.set("client_id", process.env.NODARO_CLIENT_ID!)
url.searchParams.set("redirect_uri", "https://yourapp.com/oauth/callback")
url.searchParams.set("response_type", "code")
url.searchParams.set("scope", "workflows:read workflows:execute")
url.searchParams.set("state", state)
res.redirect(url.toString())
```

- **Se o usuário clicar em Cancelar,** o Nodaro redireciona para o seu `redirect_uri` com `error=access_denied`, um `error_description` e o seu `state`. Trate isso como um resultado normal, não como uma falha.
- **Se a URI de redirecionamento não estiver registrada,** a tela de consentimento mostra uma página de erro e não redireciona para lugar nenhum, tanto em Cancelar quanto em Permitir.

## Trocar o código por um token
Depois que o usuário clica em **Permitir**, o Nodaro envia o navegador para o seu callback:

```text
https://yourapp.com/oauth/callback?code=ndr_code_...&state=<your state>
```

1. **Verifique o `state` primeiro.** Se ele não corresponder ao valor na sessão do usuário, pare: essa é a proteção contra falsificação de requisição entre sites.
2. **Troque o código no seu servidor.** Nunca faça essa chamada em um navegador, onde qualquer pessoa com as ferramentas de desenvolvedor poderia ler o seu `client_secret`.

**TypeScript SDK**

```ts

// The token endpoint is public: your client ID and secret authenticate
// the request, so the client needs no token of its own.
const client = createClient({
baseUrl: "https://nodaro.example.com",
auth: new StaticTokenAuth(""),
})

const tokens = await client.oauth.exchangeCode({
client_id: process.env.NODARO_CLIENT_ID!,
client_secret: process.env.NODARO_CLIENT_SECRET!,
code: req.query.code as string,
redirect_uri: "https://yourapp.com/oauth/callback",
})
// tokens.access_token: "ndr_app_..."
// tokens.scope:        the scopes the user granted, separated by spaces
// tokens.expires_in:   7776000 (seconds, that is 90 days)
// tokens.token_type:   "Bearer"
```

**curl**

```bash
curl -X POST https://nodaro.example.com/v1/oauth/token \
  -H "Content-Type: application/json" \
  -d '{
"grant_type": "authorization_code",
"client_id": "app_...",
"client_secret": "sec_...",
"code": "ndr_code_...",
"redirect_uri": "https://yourapp.com/oauth/callback"
}'
```

A resposta usa os nomes de campo padrão do OAuth:

```json
{
"access_token": "ndr_app_...",
"token_type": "Bearer",
"scope": "workflows:read workflows:execute",
"expires_in": 7776000
}
```

- **Um código funciona uma única vez.** Uma segunda troca do mesmo código retorna `400 invalid_grant`.
- **Um código expira 10 minutos depois de ser emitido.** Troque-o assim que o seu callback o receber.
- **O endpoint de token aceita corpos JSON e codificados como formulário.** Clientes OAuth padrão que enviam `application/x-www-form-urlencoded` funcionam sem mudanças, com o método `client_secret_post`.

## Clientes públicos: PKCE
Apps mobile, apps de página única e ferramentas de CLI não conseguem guardar um `client_secret`. Eles usam PKCE no lugar. O Nodaro aceita só o método `S256`; `plain` é recusado com `400 invalid_request`.

### Criar um verificador e um desafio
Antes do redirecionamento, crie um `code_verifier` aleatório e de alta entropia. Derive o `code_challenge` como a codificação base64url do hash SHA-256 do verificador.

### Enviar o desafio na requisição de autorização
Adicione `code_challenge` e `code_challenge_method=S256` à URL de autorização:

```text
https://nodaro.example.com/oauth/authorize?
client_id=app_...&
redirect_uri=https://yourapp.com/oauth/callback&
response_type=code&
scope=workflows:read+workflows:execute&
state=<random CSRF token>&
code_challenge=<base64url SHA-256 of the verifier>&
code_challenge_method=S256
```

### Enviar o verificador na troca do token
Envie o `code_verifier` em vez do `client_secret`:

```bash
curl -X POST https://nodaro.example.com/v1/oauth/token \
  -H "Content-Type: application/json" \
  -d '{
"grant_type": "authorization_code",
"client_id": "app_...",
"code": "ndr_code_...",
"redirect_uri": "https://yourapp.com/oauth/callback",
"code_verifier": "<the original verifier>"
}'
```

Um cliente confidencial pode enviar tanto um segredo quanto um verificador PKCE. O Nodaro verifica cada um que estiver presente.

## Chamar a API com o token
Crie um cliente por usuário, com o token de acesso desse usuário:

```ts

const userClient = createClient({
baseUrl: "https://nodaro.example.com",
auth: new StaticTokenAuth(tokens.access_token),
})

// Every call acts as the user who authorized your app, within the granted scopes.
const projects = await userClient.projects.list()
const workflows = await userClient.workflows.list(projects.data[0].id)
const run = await userClient.workflows.run(workflows.data[0].id)
```

Sem o SDK, envie o token no cabeçalho `Authorization: Bearer` de cada chamada REST. Os endpoints estão na referência da [API REST](https://nodaro.ai/docs/developers/api).

## Quando um token expira
Um token de acesso dura **90 dias**. O Nodaro **não emite refresh tokens**: há um único tipo de token, um único lugar para guardá-lo e uma única regra de expiração, ao custo de uma tela de consentimento a cada 90 dias.

- Depois que o token expira ou é revogado, as chamadas à API retornam `401`. Envie o usuário para `/oauth/authorize` de novo.
- Quando o usuário autoriza o seu app de novo, o Nodaro atualiza a autorização dele e emite um token novo. Os tokens anteriores continuam válidos até expirarem ou serem revogados, então acompanhe quais tokens estão em uso.
- Para adicionar um escopo, leve o usuário pela URL de autorização com o `scope` mais amplo. A autorização existente é ampliada.

## Guardar tokens com segurança
- **Mantenha os tokens no seu servidor.** Nunca coloque um token de acesso em `localStorage`, em `sessionStorage` ou em um cookie que o JavaScript consiga ler.
- **Criptografe os tokens em repouso** se a sua plataforma permitir. O Nodaro guarda só um hash SHA-256 de cada token, então um vazamento do seu próprio banco de dados é a única forma de um token escapar.
- **Nunca compartilhe um token entre usuários.** Cada token pertence a um usuário do Nodaro; usá-lo no contexto de outro usuário é um bug de autorização.

## Revogar um token
Revogue um token quando o usuário sair do seu app, excluir a conta dele na sua plataforma ou clicar em **Desconectar o Nodaro** nas configurações do seu app.

**TypeScript SDK**

```ts
await client.oauth.revoke(tokens.access_token)
// { success: true }
```

**curl**

```bash
curl -X POST https://nodaro.example.com/v1/oauth/revoke \
  -H "Content-Type: application/json" \
  -d '{ "token": "ndr_app_..." }'
```

O endpoint de revogação sempre responde `200`, mesmo para um token que não existe, então ninguém consegue usá-lo para testar se um token adivinhado é válido. Depois de uma revogação, as chamadas com o token retornam `401`.

### Quando o usuário revoga o acesso
Os usuários também podem encerrar o acesso do seu app por conta própria. **Configurações › Apps conectados** (`/settings/connected-apps`) lista todos os apps e assistentes de IA com acesso à conta do usuário. Cada item mostra o nome e o tipo, quando foi conectado, quando foi usado pela última vez e os escopos que tem. **Revogar acesso** pede confirmação e depois encerra na hora a autorização e todos os tokens emitidos com ela.

Depois disso, as chamadas com o seu token retornam `401`. Trate isso como um token expirado: leve o usuário de novo pela tela de consentimento.

Só uma sessão de navegador com login pode listar ou revogar essas autorizações. Um token de acesso OAuth ou um token de API pessoal recebe `401` de `GET /v1/me/connected-apps` e de `POST /v1/me/connected-apps/:id/revoke`, então um app não consegue ler a lista nem alterá-la. Para encerrar o seu próprio acesso por código, use o endpoint de revogação acima.

## Erros
O endpoint de token responde com erros OAuth padrão:

| Status | Erro | Quando | O que fazer |
| --- | --- | --- | --- |
| `400` | `invalid_request` | O corpo está malformado ou falta um campo. | Corrija a requisição. |
| `401` | `invalid_client` (Unknown client) | O `client_id` não corresponde a nenhum app registrado. | Confira o ID do cliente na sua configuração. |
| `401` | `invalid_client` (Bad client_secret) | O segredo está errado, muitas vezes um antigo depois de uma rotação. | Carregue o segredo atual e reinicie o seu serviço. |
| `400` | `invalid_grant` | O código tem mais de 10 minutos, já foi usado ou o `redirect_uri` é diferente do usado na requisição de autorização. | Leve o usuário de novo pelo consentimento, com URIs idênticas. |

A etapa de autorização mostra estes erros na própria tela de consentimento e nunca redireciona com eles:

| Status | Código | Quando | O que fazer |
| --- | --- | --- | --- |
| `400` | `invalid_redirect_uri` | O `redirect_uri` não está registrado para o app. | Adicione a URI na página do app. |
| `400` | `invalid_scope` | Um escopo solicitado não está entre os escopos solicitados do app. | Adicione o escopo ao app primeiro. |
| `404` | `invalid_client` | O `client_id` é desconhecido, ou o app está suspenso. | Confira o ID do cliente e o status do app. |

As chamadas à API com o token de acesso podem falhar com:

| Status | Código | Quando | O que fazer |
| --- | --- | --- | --- |
| `401` | `unauthorized` | O token expirou, foi revogado ou está malformado. | Leve o usuário de novo pelo consentimento. |
| `403` | `insufficient_scope` | Falta ao token o escopo de que a rota precisa. O corpo informa esse escopo em `missingScope`. | Leve o usuário pelo consentimento com o escopo mais amplo. |

O SDK lança o caso `403` como um `ForbiddenError` com um `missingScope` tipado, para que você possa oferecer um novo consentimento com um clique:

```ts

try {
await userClient.workflows.run(workflowId)
} catch (err) {
if (err instanceof ForbiddenError && err.missingScope) {
// Send the user back to /oauth/authorize with the broader scope list.
redirectToConsent({ scopes: [...currentScopes, err.missingScope] })
return
}
throw err
}
```

## Checklist de segurança
- **HTTPS em tudo.** A instância do Nodaro, o seu app e todas as URIs de redirecionamento usam `https://`. `http://localhost` é só para desenvolvimento local.
- **Verifique o `state` em todo callback.** Crie um por autorização e guarde-o na sessão do usuário.
- **Mantenha o `client_secret` no seu servidor.** Nunca o inclua em um app de navegador, nunca o registre em logs nem o repita em uma mensagem de erro.
- **Rotacione o segredo** pelo menos uma vez por ano, e imediatamente se suspeitar de um vazamento.
- **Registre só as suas próprias URIs de redirecionamento.** Registre só os endereços que você realmente usa.
- **Solicite o menor conjunto de escopos.** Adicione um escopo quando criar o recurso que precisa dele.
- **Revogue no logout.** Chame o endpoint de revogação quando um usuário sair do seu app, para que o token dele não possa ser reutilizado.
- **Trate o `missingScope`.** Ofereça ao usuário um novo consentimento, não uma página genérica de “permissão negada”.

## Testar o fluxo localmente
O ciclo de teste mais rápido precisa de uma instância do Nodaro com **Apps de desenvolvedor**, como o Nodaro Cloud ou uma instalação da Business edition, e de um pequeno servidor de callback na sua máquina.

### Registrar um app de teste
Crie um app com a URI de redirecionamento `http://localhost:8080/cb` e os escopos `workflows:read`, `workflows:execute` e `jobs:read`.

### Executar um servidor de callback na porta 8080
```ts

const NODARO_URL = "https://app.nodaro.ai" // or your Business edition install

const app = express()

app.get("/cb", async (req, res) => {
const client = createClient({ baseUrl: NODARO_URL, auth: new StaticTokenAuth("") })
const tokens = await client.oauth.exchangeCode({
client_id: process.env.NODARO_CLIENT_ID!,
client_secret: process.env.NODARO_CLIENT_SECRET!,
code: req.query.code as string,
redirect_uri: "http://localhost:8080/cb",
})
res.json(tokens)
})

app.listen(8080)
```

### Abrir a URL de autorização e clicar em Permitir
Abra `/oauth/authorize?client_id=app_...&redirect_uri=http://localhost:8080/cb&response_type=code&scope=workflows:read+workflows:execute&state=test123` na instância. Depois que você clicar em **Permitir**, o servidor de callback mostra o JSON do token.

### Chamar uma rota real
Use o token em uma rota como `GET /v1/projects/<id>/workflows` e verifique se ela responde `200` com dados.

## Descoberta e registro dinâmico para clientes MCP
Os clientes MCP, como Claude, ChatGPT e Cursor, encontram sozinhos os endpoints OAuth e podem se registrar em tempo de execução, sem que uma pessoa visite Apps de desenvolvedor. Veja [Conectar um cliente](https://nodaro.ai/docs/mcp/connect) para o lado do usuário.

### Documentos de descoberta
| Endpoint | Padrão | Finalidade |
| --- | --- | --- |
| `GET /.well-known/oauth-authorization-server` | RFC 8414 | Onde autorizar, obter tokens, registrar e revogar. |
| `GET /.well-known/oauth-protected-resource` | RFC 9728 | Associa o recurso MCP, `https://mcp.nodaro.ai/mcp`, ao servidor de autorização dele. |

Cada documento também é servido com o sufixo `/mcp`, porque alguns clientes mais rigorosos tentam essa forma primeiro. Os quatro endereços funcionam tanto no host do Nodaro quanto no host do MCP. O emissor é o `PUBLIC_URL` da instância, `https://app.nodaro.ai` no Nodaro Cloud.

Os metadados do servidor de autorização anunciam:

- os endpoints de autorização, token, registro e revogação;
- o tipo de resposta `code` e a concessão `authorization_code`;
- PKCE só com `S256`;
- o método de autenticação `client_secret_post` no endpoint de token;
- cada escopo em `scopes_supported`.

### Registro dinâmico de clientes
Um cliente se registra com `POST /v1/oauth/register` (RFC 7591) e recebe um `client_id` que começa com `ndr_dcr_`, além de um `client_secret`. O endpoint aceita 10 requisições por minuto por endereço IP. O operador da instância define `MCP_DYNAMIC_REGISTRATION`:

| Modo | Comportamento |
| --- | --- |
| `allowlist` (padrão) | Só os nomes de cliente em `MCP_DCR_ALLOWLIST` podem se registrar. Os outros recebem `403 client_not_allowed`. |
| `open` | Qualquer cliente pode se registrar, até 5 registros não usados por nome de cliente e URIs de redirecionamento em 24 horas (`429 too_many_open_registrations`). |
| `off` | O registro fica desativado (`403 dcr_disabled`). Em vez disso, o operador distribui um ID de cliente e um segredo fixos. |

Um cliente que se registrou sozinho escolheu o próprio nome, então a tela de consentimento avisa o usuário de que o Nodaro não o verificou. Os escopos que ele declara são informativos: o consentimento do usuário é o verdadeiro controle, e o cliente pode solicitar qualquer escopo válido. Veja [MCP em uma instalação self-hosted](https://nodaro.ai/docs/self-hosting/mcp) para as configurações do operador.

## O plugin para Figma em uma instalação self-hosted
O plugin do Nodaro para Figma funciona dentro do Figma e não consegue receber um redirecionamento. Em vez disso, ele se conecta com um handshake no estilo de dispositivo: mostra um código curto ao usuário, que aprova o plugin na tela de consentimento comum e digita esse código, e então recebe o token. O token é um token comum de app de desenvolvedor, com os escopos `jobs:read`, `assets:read`, `assets:write` e `credits:read`, e pode ser revogado como qualquer outro.

Para permitir que o plugin se conecte à sua própria instalação:

1. Registre um app de desenvolvedor, em **Apps de desenvolvedor** ou com `POST /v1/developer-apps`. Adicione `<PUBLIC_URL>/v1/oauth/plugin/callback` às URIs de redirecionamento dele e solicite os quatro escopos acima.
2. Coloque o ID do cliente do app em `FIGMA_PLUGIN_OAUTH_CLIENT_ID` no servidor.

Sem essa configuração, todas as rotas de conexão do plugin respondem `503 plugin_connect_not_configured`. Se faltar ao app a URI de callback ou um escopo, as rotas respondem `503 plugin_connect_misconfigured`, e o log do servidor informa o que está faltando.

## Frequently asked questions

### Quando preciso de OAuth em vez de um token de API pessoal?

Use OAuth quando o seu produto agir nas contas do Nodaro de outras pessoas e cada usuário precisar aprovar o seu app e poder cortar o acesso dele. Para scripts e servidores que só usam a sua própria conta, um token de API pessoal é mais simples.

### Quanto tempo dura um token de acesso OAuth do Nodaro?

90 dias. O Nodaro não emite refresh tokens, então, quando um token expira ou é revogado, as chamadas à API retornam 401, e você leva o usuário de novo pela tela de consentimento.

### O Nodaro aceita PKCE?

Sim, só com o método S256. Apps mobile, apps de página única e ferramentas de CLI enviam um code_challenge na requisição de autorização e o code_verifier correspondente na troca do token, em vez de um segredo do cliente.

### O que acontece se eu perder o segredo do cliente?

O Nodaro guarda só um hash do segredo e não consegue mostrá-lo de novo. Rotacione o segredo na página do app para obter um novo. O segredo antigo para de funcionar na hora.

### Quantos apps de desenvolvedor posso registrar?

Cinco por usuário. Os clientes MCP que se registram sozinhos aparecem na mesma lista, mas não entram no limite.

### Um usuário pode retirar o acesso que deu ao meu app?

Sim. Em Configurações › Apps conectados, o usuário pode revogar qualquer app com acesso à conta dele. A autorização e todos os tokens emitidos com ela param de funcionar na hora, e as suas chamadas retornam 401. Leve o usuário de novo pela tela de consentimento.
