> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kiwify.com.br/llms.txt
> Use this file to discover all available pages before exploring further.

# Autenticação

> Autenticação EdDSA Proof-of-Possession (PoP) para a Banking API

# Autenticação

A Banking API usa autenticação **EdDSA Proof-of-Possession (PoP)**. Este método criptográfico garante que as requisições sejam assinadas pelo proprietário legítimo da chave privada da conta de serviço e previne ataques de replay.

## Visão Geral

Diferente da autenticação tradicional por API key ou OAuth, a autenticação PoP requer que você assine criptograficamente cada requisição. Isso fornece:

* **Não-repúdio** - Requisições podem ser comprovadas como originárias da sua conta de serviço
* **Proteção contra replay** - Timestamps previnem reutilização de requisições capturadas

## Pré-requisitos

Antes de fazer requisições à API, você precisa:

1. **Conta de Serviço** - Criada no seu painel Conta Digital
2. **Par de Chaves Ed25519** - Gere um par de chaves pública/privada
3. **Chave Pública Registrada** - Faça upload da sua chave pública na conta de serviço

## Headers Obrigatórios

Toda requisição autenticada deve incluir estes 4 headers:

| Header            | Descrição                             | Exemplo                                |
| ----------------- | ------------------------------------- | -------------------------------------- |
| `x-access-id`     | UUID da sua conta de serviço          | `550e8400-e29b-41d4-a716-446655440000` |
| `X-PoP-Signature` | Assinatura EdDSA (base64)             | `MEUCIQDx...`                          |
| `X-PoP-Challenge` | Timestamp Unix em milissegundos       | `1705423200000`                        |
| `X-PoP-Format`    | Identificador do tipo de autenticação | `service-account`                      |

## Processo de Assinatura

A assinatura é criada assinando um formato de mensagem específico com sua chave privada Ed25519.

### Passo 1: Construir a Mensagem

Concatene os seguintes valores separados por dois-pontos (`:`):

```
{uri}:{method}:{body}:{timestamp}
```

| Componente  | Descrição                                                                                 |
| ----------- | ----------------------------------------------------------------------------------------- |
| `uri`       | Caminho completo da requisição incluindo query string (ex: `/v1/account?include=balance`) |
| `method`    | Método HTTP em maiúsculas (ex: `GET`, `POST`)                                             |
| `body`      | Corpo da requisição como string, ou string vazia para requisições GET                     |
| `timestamp` | Mesmo valor do header `X-PoP-Challenge`                                                   |

### Passo 2: Assinar a Mensagem

Assine a mensagem usando sua chave privada Ed25519 e codifique a assinatura em base64.

### Passo 3: Definir os Headers

Inclua a assinatura e todos os headers obrigatórios na sua requisição.

## Exemplos de Código

### Node.js

```javascript theme={null}
import { sign } from '@noble/ed25519';
import { Buffer } from 'buffer';

async function signRequest({ uri, method, body, privateKey, accessId }) {
  const timestamp = Date.now().toString();
  const bodyStr = body ? JSON.stringify(body) : '';

  // Construir mensagem para assinar
  const message = `${uri}:${method}:${bodyStr}:${timestamp}`;
  const messageBytes = new TextEncoder().encode(message);

  // Assinar com Ed25519
  const signature = await sign(messageBytes, privateKey);
  const signatureBase64 = Buffer.from(signature).toString('base64');

  return {
    'x-access-id': accessId,
    'X-PoP-Signature': signatureBase64,
    'X-PoP-Challenge': timestamp,
    'X-PoP-Format': 'service-account',
    'Content-Type': 'application/json',
  };
}

// Exemplo de uso
const headers = await signRequest({
  uri: '/v1/account',
  method: 'GET',
  body: null,
  privateKey: process.env.ED25519_PRIVATE_KEY,
  accessId: process.env.SERVICE_ACCOUNT_ID,
});

const response = await fetch('https://conta-public-api.kiwify.com/v1/account', {
  method: 'GET',
  headers,
});
```

### Python

```python theme={null}
import time
import base64
import json
import requests
from nacl.signing import SigningKey

def sign_request(uri: str, method: str, body: dict | None, private_key_hex: str, access_id: str) -> dict:
    timestamp = str(int(time.time() * 1000))
    body_str = json.dumps(body) if body else ''

    # Construir mensagem para assinar
    message = f"{uri}:{method}:{body_str}:{timestamp}"
    message_bytes = message.encode('utf-8')

    # Assinar com Ed25519
    signing_key = SigningKey(bytes.fromhex(private_key_hex))
    signed = signing_key.sign(message_bytes)
    signature_base64 = base64.b64encode(signed.signature).decode('utf-8')

    return {
        'x-access-id': access_id,
        'X-PoP-Signature': signature_base64,
        'X-PoP-Challenge': timestamp,
        'X-PoP-Format': 'service-account',
        'Content-Type': 'application/json',
    }

# Exemplo de uso
import os

headers = sign_request(
    uri='/v1/account',
    method='GET',
    body=None,
    private_key_hex=os.environ['ED25519_PRIVATE_KEY'],
    access_id=os.environ['SERVICE_ACCOUNT_ID'],
)

response = requests.get(
    'https://conta-public-api.kiwify.com/v1/account',
    headers=headers,
)
```

### cURL (com assinatura pré-computada)

```bash theme={null}
# Nota: Você precisará computar a assinatura externamente
# Este exemplo mostra o formato dos headers

TIMESTAMP=$(date +%s000)
ACCESS_ID="seu-uuid-da-conta-de-servico"
SIGNATURE="sua-assinatura-base64-computada"

curl -X GET "https://conta-public-api.kiwify.com/v1/account" \
  -H "x-access-id: ${ACCESS_ID}" \
  -H "X-PoP-Signature: ${SIGNATURE}" \
  -H "X-PoP-Challenge: ${TIMESTAMP}" \
  -H "X-PoP-Format: service-account"
```

## Validação de Timestamp

O timestamp `X-PoP-Challenge` deve estar dentro de **5 minutos** do horário atual do servidor. Isso previne ataques de replay enquanto permite uma margem razoável para diferença de relógios.

<Warning>
  Certifique-se de que o relógio do seu sistema está sincronizado usando NTP. Requisições com timestamps fora da janela de 5 minutos serão rejeitadas com erro `401 Unauthorized`.
</Warning>

## Solução de Problemas

### Erros Comuns

<AccordionGroup>
  <Accordion title="401 - Assinatura inválida">
    **Causa:** A assinatura não corresponde ao valor esperado.

    **Soluções:**

    * Verifique se está assinando o formato exato da mensagem: `{uri}:{method}:{body}:{timestamp}`
    * Certifique-se de que a URI inclui o caminho completo e a query string
    * Verifique se a string do body corresponde exatamente ao que está enviando
    * Confirme que sua chave privada corresponde à chave pública registrada na conta de serviço
  </Accordion>

  <Accordion title="401 - Timestamp expirado">
    **Causa:** O timestamp `X-PoP-Challenge` está mais de 5 minutos diferente do horário do servidor.

    **Soluções:**

    * Sincronize o relógio do seu sistema usando NTP
    * Gere o timestamp imediatamente antes de fazer a requisição
    * Certifique-se de usar milissegundos, não segundos
  </Accordion>

  <Accordion title="401 - Access ID inválido">
    **Causa:** O `x-access-id` não corresponde a nenhuma conta de serviço ativa.

    **Soluções:**

    * Verifique se o UUID da conta de serviço está correto
    * Certifique-se de que a conta de serviço está ativa e não desabilitada
    * Verifique se há erros de digitação ou espaços extras
  </Accordion>
</AccordionGroup>

### Dicas de Depuração

1. **Registre a mensagem antes de assinar** - Imprima a string exata sendo assinada para verificar o formato
2. **Teste com uma assinatura conhecida** - Use vetores de teste para verificar sua implementação de assinatura
3. **Verifique os headers de resposta** - Respostas de erro podem incluir informações adicionais de depuração
4. **Verifique o formato da chave** - Chaves privadas Ed25519 devem ter 32 bytes (64 caracteres hexadecimais)

## Melhores Práticas de Segurança

<CardGroup cols={2}>
  <Card title="Proteja Sua Chave Privada" icon="shield">
    Nunca exponha sua chave privada em código client-side, logs ou controle de versão. Use variáveis de ambiente ou gerenciamento seguro de secrets.
  </Card>

  <Card title="Rotacione Chaves Regularmente" icon="arrows-rotate">
    Gere novos pares de chaves periodicamente e atualize sua conta de serviço. Revogue chaves antigas após a rotação.
  </Card>

  <Card title="Monitore o Uso da API" icon="chart-line">
    Revise regularmente seus logs de acesso à API para padrões inesperados ou tentativas não autorizadas.
  </Card>
</CardGroup>
