# 01 — Configuração e Autenticação

> Como as credenciais do Exent Space são resolvidas, como as rotas inbound autenticam o Space e como
> o Nexos autentica suas chamadas outbound.

---

## 1. Credenciais do Exent Space

As credenciais são **centralizadas** (banco landlord) e resolvidas por tenant através do
[IntegrationCredentialService](../../app/Services/IntegrationCredentialService.php):

```php
$token = (new IntegrationCredentialService())->getToken('exent_space');
// $token['exent_space_url_api']  → URL base da API do Space (ex.: https://space.exent.com.br/api)
// $token['exent_space_token']    → Bearer token usado nos dois sentidos
```

### Cadeia de resolução

```
IntegrationProvider (slug = 'exent_space')         ← banco central
        │  provider_id
        ▼
IntegrationToken.payload (JSON criptografado)      ← exent_space_url_api, exent_space_token
        │  integration_token_id
        ▼
CompanyToken (tenant_id ↔ integration_token_id)    ← vincula o token ao tenant atual
```

- O provider é identificado pelo **slug `exent_space`** (não pelo nome).
- O `payload` do `IntegrationToken` é **criptografado** (cast automático no model) e contém as duas chaves.
- O `CompanyToken` amarra o token ao tenant. `getToken()` usa `tenancy()->tenant` para filtrar.
- Cadastro/edição das credenciais é feito pelo painel **Master** (`MasterController`).

> **Multi-tenant:** `IntegrationProvider`, `IntegrationToken` e `CompanyToken` ficam no **banco central**.
> As queries usam `::on(config('tenancy.database.central_connection'))`.

---

## 2. Autenticação Inbound (Space → Nexos)

Os middlewares são registrados em [bootstrap/app.php](../../bootstrap/app.php):

```php
$middleware->alias([
    'tenancy.header'    => \App\Http\Middleware\InitializeTenancyByHeader::class,
    'google.domain'     => \App\Http\Middleware\EnsureGoogleWorkspaceDomain::class,
    'integration.token' => \App\Http\Middleware\IntegrationApiTokenMiddleware::class,
    // ...
]);
```

### 2.1 `integration.token` — grupo `integration/`

[IntegrationApiTokenMiddleware](../../app/Http/Middleware/IntegrationApiTokenMiddleware.php):

1. Exige `Authorization: Bearer <token>` → senão `401 {"error":"Unauthorized"}`.
2. Exige header `X-Tenant-ID` → senão `400 {"error":"X-Tenant-ID header is required"}`.
3. Busca o provider `exent_space` no banco central.
4. Percorre os `CompanyToken` daquele tenant e compara o token recebido com `payload['exent_space_token']`
   usando **`hash_equals()`** (comparação segura contra timing attack).
5. Se nenhum bater → `401 {"error":"Unauthorized"}`.

### 2.2 `google.domain` — grupo `finance/`

[EnsureGoogleWorkspaceDomain](../../app/Http/Middleware/EnsureGoogleWorkspaceDomain.php):

- Espera `Authorization: Bearer <email>` (o e-mail do usuário Google, não um token).
- Valida se o e-mail pertence a um dos domínios de `GOOGLE_HOSTED_DOMAIN`
  (default `exent.com.br,vendrix.com.br`).
- Disponibiliza o e-mail validado em `$request->attributes->get('google_email')`.

### 2.3 `tenancy.header` — ambos os grupos

[InitializeTenancyByHeader](../../app/Http/Middleware/InitializeTenancyByHeader.php):

- Lê `X-Tenant-ID`, valida o tenant e **troca a conexão de banco** para o tenant correspondente.
- Sem esse middleware as queries rodariam no banco errado.

---

## 3. Headers obrigatórios por grupo de rotas

| Grupo | Header | Valor |
|-------|--------|-------|
| `integration/` | `Authorization` | `Bearer <exent_space_token>` |
| `integration/` | `X-Tenant-ID` | ID do tenant (empresa) |
| `finance/` | `Authorization` | `Bearer <email @exent.com.br ou @vendrix.com.br>` |
| `finance/` | `X-Tenant-ID` | ID do tenant (empresa) |

Para envio de arquivos (documentos, comprovantes, NFs) usar `Content-Type: multipart/form-data`.

---

## 4. Cliente HTTP Outbound (Nexos → Space)

Todas as chamadas do Nexos para o Space passam pelo [GuzzleService](../../app/Services/GuzzleService.php):

```php
$guzzle = new GuzzleService();
$response = $guzzle->request('POST', $url, $headers, json_encode($payload));
```

**Assinatura:** `request($method, $url, $headers = [], $body = [])`

**Retorno (sempre array, nunca lança exceção em 4xx/5xx):**

```php
[
    'success' => bool,   // true para HTTP 2xx
    'status'  => int,    // código HTTP
    'data'    => mixed,  // JSON decodificado (array) ou string bruta
]
```

- Timeouts: ~10s de conexão, ~30s total.
- O `body` é enviado como **string JSON** (`json_encode(...)`), não como array.
- Headers padrão das chamadas ao Space:

```php
[
    'Accept'        => 'application/json',
    'Content-Type'  => 'application/json',
    'Authorization' => 'Bearer ' . $token['exent_space_token'],
]
```

> O mesmo `exent_space_token` é usado tanto para o Space autenticar-se no Nexos (inbound) quanto para o
> Nexos autenticar-se no Space (outbound).
