# Autenticação: obter o userHash e o Servidor

Toda chamada da API do GransoftWeb é feita em nome de um usuário. A integração precisa de dois dados:

- **`userHash`**: a chave que identifica o usuário autenticado. Vai em todas as chamadas.
- **`Servidor`**: o endereço do servidor que atende a empresa desse usuário. É o início de todos os endereços da API.

Os exemplos usam valores fictícios.

## 1. Duas formas de obter o userHash

| Forma | Quando usar |
|---|---|
| **Chave de teste do catálogo de APIs** | Desenvolvimento e integrações internas de uma única empresa. Entre no GransoftWeb com o usuário da integração, abra `https://www.server1.gransoftweb.com/API/` e copie a chave exibida em "Sua chave de teste". A "URL base" da mesma página indica o `Servidor`. |
| **Método `ObterAutenticacao`** | Aplicações em que cada pessoa entra com o próprio e-mail e senha do GransoftWeb. |

Recomendação: crie no GransoftWeb um **usuário exclusivo para a integração**, com apenas as permissões de que ela precisa. Assim, o acesso pode ser revisto ou bloqueado sem afetar as pessoas da empresa.

## 2. ObterAutenticacao

### 2.1 Requisição

```
POST https://www.gransoftweb.com/API/ObterAutenticacao
Content-Type: application/json
```

```json
{
  "Email": "joao@empresa.com.br",
  "Senha": "senha-do-usuario"
}
```

| Campo | Obrigatório | Descrição |
|---|---|---|
| `Email` | Sim | E-mail do usuário no GransoftWeb. |
| `Senha` | Sim | Senha do usuário. |
| `Login` | Só quando o e-mail pertence a mais de um usuário | Nome de login do usuário (veja 4.3). |

O endereço da autenticação é sempre `https://www.gransoftweb.com`. As demais chamadas usam o `Servidor` devolvido.

### 2.2 Resposta quando dá certo

```json
{
  "Erro": "",
  "Hash": "aEJ6cG1oUjllOExOMXB2ay91TE5U...",
  "Servidor": "https://www.server1.gransoftweb.com",
  "Codigo": 1001,
  "CodigoUsuario": 7,
  "EmpresaID": 123456,
  "Nome": "João da Silva",
  "NomeEmpresa": "Marmoraria Exemplo",
  "Situacao": 1,
  "Bloqueado": false
}
```

| Campo | Descrição |
|---|---|
| `Erro` | Vazio quando deu certo. |
| `Hash` | O `userHash`. |
| `Servidor` | Endereço base do servidor da empresa. |
| `EmpresaID` | Código da empresa do usuário. |
| `Situacao` | `0` usuário em teste, `1` ativo, `2` bloqueado, `3` mais de um usuário com o mesmo e-mail. |
| `Bloqueado` | `true` quando o usuário está bloqueado. |

A resposta traz outros campos, que a integração não precisa usar. **Guarde apenas `Hash`, `Servidor` e os dados de exibição.**

### 2.3 Como conferir a resposta

A API responde HTTP 200 mesmo quando a autenticação falha. Confira nesta ordem:

1. **Status 200 e corpo JSON?** Se não, o serviço está indisponível (4.5).
2. **`Erro` preenchido?** A autenticação falhou (4.1 ou 4.5).
3. **`Situacao` igual a `3`?** Repita enviando o `Login` (4.3).
4. **`Hash` vazio?** A autenticação não aconteceu (4.2).
5. **`Bloqueado` é `true` ou `Situacao` é `2`?** Usuário bloqueado (4.4).

Passou pelos cinco pontos: use `Hash` e `Servidor`.

`Servidor` pode vir preenchido mesmo com erro. Só use-o se houver `Hash`.

## 3. Como enviar o userHash nas chamadas seguintes

```
POST {Servidor}/API/{Metodo}
Content-Type: application/json

{ "userHash": "aEJ6cG1oUjllOExOMXB2ay91TE5U...", ...demais campos do método }
```

- **Envie o `userHash` no corpo JSON.** Os métodos de vendas (`AcoesDocumentoVendaMarmoraria`) só leem o `userHash` do corpo e ignoram o header `Authorization`. Para não ter dois padrões, use o corpo em todos.
- **Exceção: `ObterLista`** lê o `userHash` da query string: `POST {Servidor}/API/ObterLista?userHash=...`.
- O `userHash` não tem prazo de validade documentado. Se uma chamada passar a recusar um `userHash` que funcionava (senha trocada, usuário bloqueado), autentique de novo.

## 4. Erros e como resolver

### 4.1 Dados recusados

```json
{ "Erro": "Email Não Cadastrado Na Base de Dados", "Hash": "", "Situacao": 0 }
```

E-mail, login ou senha não conferem. Mostre o texto de `Erro` ao usuário e **não repita automaticamente**: o resultado será o mesmo. O texto pode mudar; não o compare com textos fixos no código.

### 4.2 Sem erro e sem userHash

```json
{ "Erro": "", "Hash": "", "Situacao": 0 }
```

Trate como login ou senha inválidos (4.1).

### 4.3 Mais de um usuário com o mesmo e-mail

Resposta com `Situacao` igual a `3`. **Não use o `Hash` dessa resposta**, mesmo que venha preenchido. Peça ao usuário o nome de login e repita:

```json
{ "Email": "joao@empresa.com.br", "Login": "joao.silva", "Senha": "senha-do-usuario" }
```

### 4.4 Usuário bloqueado

`Bloqueado` igual a `true` ou `Situacao` igual a `2`. Não use o `Hash`. O desbloqueio é feito no cadastro do usuário no GransoftWeb.

### 4.5 Serviço indisponível

- Status diferente de 200 ou corpo que não é JSON (normalmente uma página HTML de erro);
- `Erro` com mensagem técnica em inglês, como `The remote server returned an error: (500) Internal Server Error.`;
- `Erro` começando com `Não foi possível obter os dados do Servidor` ou `Erro ao Deserializar Objeto`.

Repita depois de alguns segundos, aumentando o intervalo a cada tentativa. Mostre ao usuário uma mensagem genérica. Qualquer outra mensagem em `Erro` é recusa dos dados (4.1).

## 5. Cuidados

- Use sempre **POST com HTTPS e corpo JSON**. Não envie e-mail e senha na URL.
- **Chame a API a partir do seu servidor**, nunca de código que roda no navegador: o `userHash` ficaria exposto.
- Guarde o `userHash` em variável de ambiente ou cofre de segredos, **nunca no código-fonte nem no repositório**.
- **Não grave a resposta inteira da autenticação em log.** Ela contém dados do usuário.
- Mascare o `userHash` em qualquer log (ex.: `aEJ6…5U`).

## 6. Com o kit em Node.js

```js
import { GransoftClient } from "./gransoft-client.js";

// Opção 1: userHash já obtido (chave de teste)
const gs = new GransoftClient({
  userHash: process.env.GRANSOFT_USERHASH,
  servidor: process.env.GRANSOFT_SERVIDOR,
});

// Opção 2: autenticar com e-mail e senha
const gs2 = await GransoftClient.autenticar({
  email: process.env.GRANSOFT_EMAIL,
  senha: process.env.GRANSOFT_SENHA,
  login: process.env.GRANSOFT_LOGIN, // só se o e-mail tiver mais de um usuário
});
```

`GransoftClient.autenticar` já faz as conferências do item 2.3 e lança `GransoftErro` com `tipo` igual a `"autenticacao"`, `"login_necessario"`, `"bloqueado"` ou `"indisponivel"`.
