# App Studio

## Guia Completo de Integração OAuth Zydon

Este guia detalha como implementar a integração OAuth com a plataforma Zydon, permitindo que seus clientes autorizem o acesso aos dados da conta Zydon deles através do seu plugin/aplicação.

#### Pré-requisitos

Antes de começar, garanta que seu plugin já está registrado na plataforma Zydon. Com o registro, você receberá três informações essenciais:

1. `client_id`: (Plugin ID).

   <figure><img src="https://4238366962-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FPSLb7DtcuAqWIRHDBT7b%2Fuploads%2F3XqepmHoPpMAUxJAPQhE%2Fimage.png?alt=media&#x26;token=cef4774f-8582-4838-b54f-745fade3596d" alt=""><figcaption></figcaption></figure>

2. `access_key`: Sua chave secreta.

   <figure><img src="https://4238366962-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FPSLb7DtcuAqWIRHDBT7b%2Fuploads%2Fn4zkfhWB5Ly46BdQiHfy%2Fimage.png?alt=media&#x26;token=9cc3aa6b-48a4-4ab7-88a3-7e42b5ee5b60" alt=""><figcaption></figcaption></figure>

3. URLs de Callback: Os endereços para onde o cliente será enviado após a autorização.<br>

### 🚀 **Fluxo OAuth Completo**

#### **Etapa 1: Redirecionamento para Autorização**

Redirecione seu cliente para a URL de autorização do Zydon:

```
https://admin.zydon.com.br/oauth/authorize?client_id={PLUGIN_ID}&redirect_uri={CALLBACK_URL}&state={STATE}
```

**Parâmetros Obrigatórios:**

* **`client_id`**: ID do seu plugin (UUID)
* **`redirect_uri`**: URL de callback autorizada do seu sistema
* **`state`**: Valor aleatório para proteção CSRF (recomendado)

**Exemplo:**

```
https://admin.zydon.com.br/oauth/authorize?client_id=123e4567-e89b-12d3-a456-426614174000&redirect_uri=https://meuapp.com/callback&state=xyz123
```

#### **Etapa 2: Autorização do Cliente**

O cliente será direcionado para a tela de autorização do Zydon onde:

1. **Visualizará** as permissões solicitadas
2. **Decidirá** se autoriza ou não o acesso
3. **Seu plugin será instalado automaticamente** (se ainda não estiver)

#### **Etapa 3: Callback com Código de Autorização**

Após a autorização, o cliente será redirecionado para sua URL de callback:

**Sucesso:**

```
https://meuapp.com/callback?code={AUTHORIZATION_CODE}&state={STATE}
```

**Erro:**

```
https://meuapp.com/callback?error={ERROR_CODE}&state={STATE}
```

**Códigos de Erro Possíveis:**

* **`invalid_client`**: Plugin não encontrado ou URL de callback não autorizada
* **`server_error`**: Erro interno durante a instalação/autorização

#### **Etapa 4: Troca do Código por Token de Acesso**

Com o código de autorização recebido, faça uma requisição para obter o token de acesso:

**Endpoint:**

```
POST https://api.zydon.com.br/appcenter/oauth/token
```

**Headers:**

```
Content-Type: application/x-www-form-urlencoded
Authorization: Basic {BASE64_ENCODED_CREDENTIALS}
```

**Credenciais Basic Auth:**

```
Base64({PLUGIN_ID}:{ACCESS_KEY})
```

**Body (form-urlencoded):**

```
grant_type=authorization_code
code={AUTHORIZATION_CODE}
redirect_uri={CALLBACK_URL}
```

**Exemplo de Requisição:**

```bash
curl -X POST https://api.zydon.com.br/appcenter/oauth/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -H "Authorization: Basic MTIzZTQ1NjctZTg5Yi0xMmQzLWE0NTYtNDI2NjE0MTc0MDAwOmFiY2RlZmdoLWlqa2wtbW5vcC1xcnN0LXV2d3h5ejEyMzQ1Ng==" \
  -d "grant_type=authorization_code&code=987fcdeb-51a2-43d7-b890-123456789abc&redirect_uri=https://meuapp.com/callback"
```

**Resposta de Sucesso (200):**

```json
{
  "access_key_code": "987fcdeb-51a2-43d7-b890-123456789abc",
  "access_key_token": "fedcba98-7654-3210-fedc-ba9876543210"
}
```

### 🔑 **Usando as Credenciais de Acesso**

Após obter as credenciais, você pode usar o **`access_key_code`** e **`access_key_token`** para fazer chamadas autenticadas às APIs do Zydon em nome do cliente.

#### **Autenticação nas APIs:**

```
Authorization: Bearer {ACCESS_KEY_TOKEN}
X-Access-Key-Code: {ACCESS_KEY_CODE}
```

### ⚠️ **Tratamento de Erros**

#### **Erros na Autorização:**

* **404**: Plugin não encontrado
* **400**: Parâmetros inválidos
* **401**: Não autorizado

#### **Erros na Troca de Token:**

* **400**: `grant_type` inválido (deve ser `authorization_code`)
* **401**: Credenciais Basic Auth inválidas
* **404**: Código de autorização não encontrado ou expirado

### 🛡️ **Segurança**

#### **Boas Práticas:**

1. **Sempre use HTTPS** em suas URLs de callback
2. **Valide o parâmetro `state`** para prevenir ataques CSRF
3. **Mantenha o `access_key` seguro** - nunca exponha no frontend
4. **Configure apenas URLs de callback confiáveis** no seu plugin
5. **Implemente timeout** para códigos de autorização

#### **Validações Implementadas:**

* URLs de callback devem estar pré-autorizadas
* Códigos de autorização têm tempo de vida limitado
* Access key é validada em cada requisição

### 📊 **Fluxo Técnico Resumido**

<figure><img src="https://4238366962-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FPSLb7DtcuAqWIRHDBT7b%2Fuploads%2FdO1xBdYxLuj7Rvalpvkm%2Fimage.png?alt=media&#x26;token=48675e43-b408-4083-9be3-c57f0c6b1d35" alt=""><figcaption></figcaption></figure>

### 💡 **Exemplo Prático de Implementação**

#### **1. Iniciando o Fluxo (Backend da sua aplicação):**

```javascript
// Gerar state aleatório para CSRF protection
const state = crypto.randomUUID();
// Salvar state na sessão/cache para validação posterior

const authUrl = `https://admin.zydon.com.br/oauth/authorize?` +
  `client_id=${PLUGIN_ID}&` +
  `redirect_uri=${encodeURIComponent(CALLBACK_URL)}&` +
  `state=${state}`;

// Redirecionar cliente para authUrl
res.redirect(authUrl);
```

#### **2. Tratando o Callback:**

```javascript
app.get('/callback', async (req, res) => {
  const { code, state, error } = req.query;
  
  // Validar state para CSRF protection
  if (state !== getStoredState()) {
    return res.status(400).send('Invalid state');
  }
  
  if (error) {
    return res.status(400).send(`Authorization error: ${error}`);
  }
  
  try {
    // Trocar código por token
    const credentials = await exchangeCodeForToken(code);
    
    // Salvar credenciais do cliente
    await saveClientCredentials(clientId, credentials);
    
    res.send('Autorização realizada com sucesso!');
  } catch (err) {
    res.status(500).send('Erro ao obter token de acesso');
  }
});
```

#### **3. Trocando Código por Token:**

```javascript
async function exchangeCodeForToken(code) {
  const credentials = Buffer.from(`${PLUGIN_ID}:${ACCESS_KEY}`).toString('base64');
  
  const response = await fetch('https://api.zydon.com.br/appcenter/oauth/token', {
    method: 'POST',
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded',
      'Authorization': `Basic ${credentials}`
    },
    body: new URLSearchParams({
      grant_type: 'authorization_code',
      code: code,
      redirect_uri: CALLBACK_URL
    })
  });
  
  if (!response.ok) {
    throw new Error(`HTTP ${response.status}: ${await response.text()}`);
  }
  
  return await response.json();
}
```

#### **4. Usando as Credenciais para Acessar APIs:**

```javascript
async function callZydonAPI(endpoint, accessKeyCode, accessKeyToken) {
  const response = await fetch(`https://api.zydon.com.br${endpoint}`, {
    headers: {
      'Authorization': `Bearer ${accessKeyToken}`,
      'X-Access-Key-Code': accessKeyCode,
      'Content-Type': 'application/json'
    }
  });
  
  if (!response.ok) {
    throw new Error(`API Error: ${response.status}`);
  }
  
  return await response.json();
}
```

### 🎯 **URLs de Referência**

* **Frontend (Autorização)**: `https://admin.zydon.com.br/oauth/authorize`
* **Backend API (Token)**: `https://api.zydon.com.br/appcenter/oauth/token`
* **Backend APIs (Dados)**: `https://api.zydon.com.br/*`

### 📋 **Checklist de Implementação**

* [ ] Plugin registrado na plataforma Zydon
* [ ] URLs de callback configuradas e autorizadas
* [ ] Implementação do redirecionamento para autorização
* [ ] Tratamento do callback com validação de state
* [ ] Implementação da troca código por token
* [ ] Armazenamento seguro das credenciais
* [ ] Implementação de chamadas autenticadas às APIs
* [ ] Tratamento de erros e renovação de tokens (se necessário)

***
