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.
Disponível em Nodaro Cloud · Business edition
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.
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
- O usuário clica em Conectar ao Nodaro no seu site.
- O seu site envia o navegador para a página
/oauth/authorizedo Nodaro com o seuclient_id,redirect_uri,scopeestate. - 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.
- O usuário clica em Permitir, e o Nodaro cria um código de autorização de uso único.
- O navegador volta para o seu
redirect_uricom?code=...&state=.... - O seu servidor troca o código por um token de acesso em
POST /v1/oauth/token, com o seuclient_ide o seuclient_secret. - 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.developerAppsdo SDK cria, atualiza e exclui apps e rotaciona os segredos deles. Veja o 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, 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 emmissingScope. Veja Erros. - 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:executepara iniciar a execução ejobs:readpara 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:
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:
import { randomBytes } from "node:crypto"
// 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_uricomerror=access_denied, umerror_descriptione o seustate. 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:
https://yourapp.com/oauth/callback?code=ndr_code_...&state=<your state>- Verifique o
stateprimeiro. 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. - 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.
import { createClient, StaticTokenAuth } from "@nodaro/sdk"
// 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 -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:
{
"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-urlencodedfuncionam sem mudanças, com o métodoclient_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:
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=S256Enviar o verificador na troca do token
Envie o code_verifier em vez do client_secret:
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:
import { createClient, StaticTokenAuth } from "@nodaro/sdk"
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.
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/authorizede 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
scopemais 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, emsessionStorageou 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.
await client.oauth.revoke(tokens.access_token)
// { success: true }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:
import { ForbiddenError } from "@nodaro/sdk"
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
stateem todo callback. Crie um por autorização e guarde-o na sessão do usuário. - Mantenha o
client_secretno 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
import express from "express"
import { createClient, StaticTokenAuth } from "@nodaro/sdk"
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 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
codee a concessãoauthorization_code; - PKCE só com
S256; - o método de autenticação
client_secret_postno 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 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:
- 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. - Coloque o ID do cliente do app em
FIGMA_PLUGIN_OAUTH_CLIENT_IDno 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.
Perguntas frequentes
Páginas relacionadas
Autenticação
SDK para TypeScript
Conectar um cliente
Skills para agentes
Incorporar um miniapp
Última atualização
Exemplos
Receitas prontas da CLI do Nodaro: execute um workflow toda noite com cron, condicione etapas de CI, gere imagens, legende um vídeo e melhore um prompt.
Login externo (SSO)
Use um provedor de identidade confiável no login de uma instalação do Nodaro, com asserção JWT assinada, OIDC ou SAML, e controle a vinculação de contas.