# Autenticação

> Escolha como o SDK do Nodaro se autentica, com StaticTokenAuth, CallbackAuth ou supabaseAuth, e compartilhe um login do navegador entre seus subdomínios.

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

Um **provedor de autenticação** diz ao SDK do Nodaro qual token enviar. Antes de cada requisição, o cliente chama o `getToken()` do provedor e envia o resultado como `Authorization: Bearer <token>`. Quando o provedor retorna `null`, a requisição é enviada sem o cabeçalho, como uma requisição anônima.

## Escolher um provedor
| Provedor | Use para | De onde vem o token |
| --- | --- | --- |
| [`StaticTokenAuth`](#statictokenauth) | Código de servidor, scripts, tarefas agendadas | Um token de API fixo ou um token de acesso OAuth |
| [`CallbackAuth`](#callbackauth) | Tokens que expiram e precisam ser renovados, armazenamentos de sessão personalizados | A sua função, chamada antes de cada requisição |
| [`supabaseAuth`](#supabaseauthsupabase) | Um app de navegador cujos usuários entram na mesma instância do Nodaro | A sessão ativa do usuário, renovada automaticamente |
| Seu próprio objeto | Qualquer outro caso | Qualquer objeto com um método `getToken()` |

## Tokens que você pode usar
| Token | Formato | Em nome de quem age | Onde obter |
| --- | --- | --- | --- |
| Token de API | `ndr_` seguido de 64 caracteres hexadecimais | Você | **Configurações › Tokens de API** no Nodaro |
| Token de acesso OAuth | `ndr_app_` seguido de 64 caracteres hexadecimais | Um usuário que aprovou o seu app | A troca de código OAuth, [`client.oauth.exchangeCode()`](https://nodaro.ai/docs/developers/sdk/developer-apps) |
| Token de sessão | Uma sessão com login ativo | O usuário conectado | O login do Nodaro, por meio de `supabaseAuth` |

- **Um token de API** é uma credencial permanente, sem limite de gastos. Ele funciona até você desativá-lo ou excluí-lo, então mantenha-o em um servidor. Veja [Autenticação da API](https://nodaro.ai/docs/developers/api/authentication) para conhecer os limites e as configurações de limite de taxa.
- **Um token de acesso OAuth** carrega apenas os escopos que o usuário aprovou. Use-o quando o seu app agir em nome de outras pessoas. Veja [OAuth](https://nodaro.ai/docs/developers/oauth).
- **Em uma instalação self-hosted da Community Edition**, o app não oferece tokens de API. Entre e use o seu token de sessão, com `supabaseAuth` ou `CallbackAuth`.

## A interface Auth
```ts
interface Auth {
getToken(): Promise<string | null>
}
```

Qualquer objeto com esse formato pode ser a opção `auth` de `createClient`. Os três provedores abaixo a implementam.

## StaticTokenAuth
```ts
new StaticTokenAuth(token: string)
```

Encapsula um único token fixo. Use-o quando o token não muda enquanto o seu processo está em execução: um token de API, ou um token de acesso OAuth que o seu servidor obteve pelo fluxo de código de autorização.

<TypeTable
type={{
token: {
type: 'string',
required: true,
description: "O token a enviar em cada requisição: um token de API (ndr_...) ou um token de acesso OAuth (ndr_app_...).",
},
}}
/>

```ts

const client = createClient({
baseUrl: "https://app.nodaro.ai",
auth: new StaticTokenAuth(process.env.NODARO_TOKEN!),
})
```

## CallbackAuth
```ts
new CallbackAuth(fn: () => string | null | Promise<string | null>)
```

Chama a sua função antes de cada requisição e envia o token que ela retorna. A função pode ser síncrona ou assíncrona. Retorne `null` para enviar a requisição sem token.

<TypeTable
type={{
fn: {
type: '() => string | null | Promise<string | null>',
required: true,
description: "Retorna o token da próxima requisição, ou null para uma requisição anônima.",
},
}}
/>

Use-o para renovar tokens, ler um armazenamento de sessão personalizado ou rotacionar credenciais:

```ts

const client = createClient({
baseUrl: "https://app.nodaro.ai",
auth: new CallbackAuth(async () => {
const session = await sessionStore.read()
if (!session) return null
if (Date.now() > session.expiresAt - 60_000) {
await refresh(session)
}
return session.accessToken
}),
})
```

## supabaseAuth(supabase)
```ts
supabaseAuth(supabase: SupabaseLikeClient): Auth
```

Lê o token do usuário conectado de um cliente Supabase v2 antes de cada requisição. Use-o em um app de navegador cujos usuários entram na mesma instância do Nodaro, por exemplo o seu próprio frontend para uma instalação self-hosted. O editor do Nodaro usa o mesmo provedor. Como o token é lido na hora, uma sessão renovada é usada automaticamente.

<TypeTable
type={{
supabase: {
type: 'SupabaseLikeClient',
required: true,
description: "Um cliente Supabase v2, ou qualquer objeto cujo método auth.getSession() retorne a sessão atual. Nada mais é chamado.",
},
}}
/>

```ts

const supabase = createSupabase(
import.meta.env.VITE_SUPABASE_URL,
import.meta.env.VITE_SUPABASE_ANON_KEY,
)

const client = createClient({
baseUrl: import.meta.env.VITE_API_URL ?? "",
auth: supabaseAuth(supabase),
})
```

Quando ninguém está conectado, a requisição é enviada sem token.

## createSharedSupabaseClient(options)
```ts

createSharedSupabaseClient<Db = any>(options: {
url: string
anonKey: string
cookieDomain?: string
}): SupabaseClient<Db>
```

Cria um cliente Supabase de navegador que guarda a sessão em **cookies**, e não no local storage. Com `cookieDomain`, vários apps em subdomínios irmãos compartilham um único login: um usuário que entra em um deles fica conectado em todos, e sair em qualquer um encerra a sessão em todos.

<TypeTable
type={{
url: {
type: 'string',
required: true,
description: "A URL do projeto Supabase da instância do Nodaro.",
},
anonKey: {
type: 'string',
required: true,
description: "A chave anônima pública desse projeto.",
},
cookieDomain: {
type: 'string',
description: "Um domínio pai, como .example.com, para compartilhar a sessão entre os subdomínios dele. Omita-o para cookies que ficam no host atual.",
},
}}
/>

```ts

const supabase = createSharedSupabaseClient({
url: SUPABASE_URL,
anonKey: SUPABASE_ANON_KEY,
cookieDomain: ".example.com",
})

const client = createClient({ baseUrl: "", auth: supabaseAuth(supabase) })
```

- `cookieDomain` só se aplica quando o host da página é esse domínio ou um dos subdomínios dele. Em qualquer outro host, como `localhost` ou uma URL de prévia, os cookies ficam no host atual, então o desenvolvimento local mantém uma sessão separada por origem.
- No primeiro carregamento, uma sessão existente no local storage passa para o cookie, e a entrada antiga é removida. Um usuário que já estava conectado continua conectado. Sessões expiradas são descartadas.
- Esta exportação fica no caminho separado `@nodaro/sdk/supabase`, para que o pacote principal não dependa do Supabase. Instale `@supabase/supabase-js` e `@supabase/ssr` para usá-la.

## Escopos e permissões ausentes
Um token de acesso OAuth carrega os escopos que o usuário aprovou, como `workflows:read` ou `workflows:execute`. A página de referência de cada recurso indica o escopo de que os métodos dele precisam. Quando falta um escopo ao token, o método lança um `ForbiddenError` cujo `missingScope` indica qual é:

```ts

try {
await client.workflows.run(workflowId)
} catch (err) {
if (err instanceof ForbiddenError && err.missingScope) {
requestConsentFor([err.missingScope]) // send the user through OAuth again
} else {
throw err
}
}
```

Tokens de API e tokens de sessão não são limitados por escopos. Veja [Erros](https://nodaro.ai/docs/developers/sdk/errors) para conhecer todas as classes de erro.

## Regras para o navegador
- **Nunca envie um token de API para um navegador.** Qualquer pessoa pode lê-lo na página, e ele age como você.
- **Tokens OAuth no navegador** só funcionam a partir das origens listadas em `allowedOrigins` do seu app de desenvolvedor. Veja [OAuth e apps de desenvolvedor](https://nodaro.ai/docs/developers/sdk/developer-apps).
- **Tokens de sessão de `supabaseAuth`** não são verificados com essa lista.
- **Mantenha os segredos no servidor.** A troca de código OAuth precisa do segredo do cliente, então execute [`client.oauth.exchangeCode()`](https://nodaro.ai/docs/developers/sdk/developer-apps) apenas em código de servidor.

## Frequently asked questions

### Qual provedor de autenticação um servidor deve usar?

StaticTokenAuth. Passe a ele um token de API que começa com ndr_, ou um token de acesso OAuth que começa com ndr_app_, lido de uma variável de ambiente.

### Como renovar com o SDK um token que expira?

Use CallbackAuth. O SDK chama a sua função antes de cada requisição, então a função pode verificar a expiração, renovar o token e retornar o novo.

### Posso colocar um token de API em um app de navegador?

Não. Um token de API age como você, sem limite de gastos, e qualquer pessoa pode lê-lo no código do navegador. No navegador, faça os usuários entrarem e use a sessão deles, ou use OAuth.

### O que significa ForbiddenError.missingScope?

O token OAuth é válido, mas não recebeu o escopo de que o endpoint precisa, por exemplo workflows:execute. Peça ao usuário que conceda esse escopo e tente de novo com o novo token.
