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

# Autenticação - FlexExtractor

> Obtenha seu token de acesso para usar a API de Extração de Dados

## Visão Geral

A API FlexExtractor utiliza autenticação baseada em **username e password** para gerar tokens de acesso. Este token deve ser usado em todas as requisições subsequentes para extração de dados.

<CardGroup cols={2}>
  <Card title="Autenticação Simples" icon="key">
    Username + Password via POST
  </Card>

  <Card title="Token JWT" icon="shield">
    Retorna access\_token e refresh\_token
  </Card>

  <Card title="Validade Configurável" icon="clock">
    Tokens com tempo de expiração definido
  </Card>

  <Card title="Refresh Automático" icon="arrows-rotate">
    Renovação via refresh\_token
  </Card>
</CardGroup>

***

## Fluxo de Autenticação

<Steps>
  <Step title="Enviar Credenciais">
    Faça um POST com username e password
  </Step>

  <Step title="Receber Token">
    API retorna access\_token e refresh\_token
  </Step>

  <Step title="Usar Token">
    Adicione o token no header: `Authorization: Bearer {access_token}`
  </Step>

  <Step title="Renovar se Necessário">
    Use refresh\_token quando o access\_token expirar
  </Step>
</Steps>

***

## Request Parameters

<Note>
  **Teste Agora!** Use o playground interativo **"Try It"** na lateral direita desta página →

  Preencha suas credenciais e clique em "Send" para gerar seu token.
</Note>

### Body Parameters (application/x-www-form-urlencoded)

<ParamField body="username" type="string" required>
  Identificação do cliente fornecida pela Flexdoc

  **Formato:** String alfanumérica

  **Exemplo:** `cliente_teste`
</ParamField>

<ParamField body="password" type="string" required>
  Senha do cliente fornecida pela Flexdoc

  **Formato:** String

  **Exemplo:** `SuaSenhaSegura123`

  <Warning>
    **Nunca** compartilhe ou exponha sua senha em repositórios públicos ou código frontend
  </Warning>
</ParamField>

***

## Response

<ResponseField name="access_token" type="string" required>
  Token JWT para autenticação nas APIs. Use no header `Authorization: Bearer {token}`

  **Formato:** JWT (JSON Web Token)

  **Exemplo:** `eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...`
</ResponseField>

<ResponseField name="expires_in" type="integer">
  Tempo de validade do access\_token em segundos

  **Exemplo:** `3600` (1 hora)
</ResponseField>

<ResponseField name="refresh_expires_in" type="integer">
  Tempo de validade do refresh\_token em segundos

  **Exemplo:** `86400` (24 horas)
</ResponseField>

<ResponseField name="refresh_token" type="string">
  Token para renovar o access\_token quando expirar

  **Uso:** Envie em requisição de refresh para obter novo access\_token
</ResponseField>

<ResponseField name="token_type" type="string">
  Tipo do token. Sempre retorna `Bearer`
</ResponseField>

<ResponseField name="id_token" type="string">
  Token de identificação (OpenID Connect)
</ResponseField>

<ResponseField name="session_state" type="string">
  Estado da sessão de autenticação
</ResponseField>

<ResponseField name="scope" type="string">
  Escopos de acesso concedidos ao token

  **Exemplo:** `profile email`
</ResponseField>

<ResponseField name="not-before-policy" type="integer">
  Política de tempo mínimo antes do token ser válido
</ResponseField>

<ResponseExample>
  ```json Sucesso (200 OK) theme={"theme":"catppuccin-latte"}
  {
    "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJxNzJMVEMyVXQ4VjhfYTBYMjRMU2g3MThsUndVdWFQRDVWNXVhX0pIaW5VIn0.eyJleHAiOjE3NDU0MjE2MzMsImlhdCI6MTc0NTQxODAzMywianRpIjoiZjc4YzA5ZjAtMTBkZS00NzQwLWI4ODEtOGY0YWQwZjBmZmZkIiwiaXNzIjoiaHR0cHM6Ly9hdXRoLmZsZXhkb2MuY29tLmJyL3JlYWxtcy9mbGV4aW1hZ2UiLCJhdWQiOiJhY2NvdW50Iiwic3ViIjoiNGU3YzY4YWItNzQxZi00ZDhjLWJiNGUtMWY3MzI5ZDkwNzAzIiwidHlwIjoiQmVhcmVyIn0...",
    "expires_in": 3600,
    "refresh_expires_in": 86400,
    "refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICIyMzQ1Njc4OS1hYmNkLWVmZ2gtaWprbC1tbm9wcXJzdHV2dyJ9...",
    "token_type": "Bearer",
    "id_token": "eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJxNzJMVEMyVXQ4VjhfYTBYMjRMU2g3MThsUndVdWFQRDVWNXVhX0pIaW5VIn0...",
    "not-before-policy": 0,
    "session_state": "f78c09f0-10de-4740-b881-8f4ad0f0fffd",
    "scope": "profile email"
  }
  ```

  ```json Erro 401 - Credenciais Inválidas theme={"theme":"catppuccin-latte"}
  {
    "error": "invalid_grant",
    "error_description": "Invalid user credentials"
  }
  ```

  ```json Erro 400 - Parâmetros Ausentes theme={"theme":"catppuccin-latte"}
  {
    "error": "invalid_request",
    "error_description": "Missing form parameter: username"
  }
  ```
</ResponseExample>

***

## Exemplos de Código

<CodeGroup>
  ```bash cURL theme={"theme":"catppuccin-latte"}
  curl -X POST "https://hml.flexextractor.com.br/api/v2/Security/GetToken" \
    -H "Content-Type: application/x-www-form-urlencoded" \
    -d "username=seu_username" \
    -d "password=sua_senha"
  ```

  ```javascript JavaScript (Axios) theme={"theme":"catppuccin-latte"}
  const axios = require('axios');
  const qs = require('qs');

  async function getFlexExtractorToken(username, password) {
    try {
      const response = await axios.post(
        'https://hml.flexextractor.com.br/api/v2/Security/GetToken',
        qs.stringify({
          username: username,
          password: password
        }),
        {
          headers: {
            'Content-Type': 'application/x-www-form-urlencoded'
          }
        }
      );

      const { access_token, expires_in, refresh_token } = response.data;

      console.log('✓ Token obtido com sucesso!');
      console.log('Expira em:', expires_in, 'segundos');

      return {
        accessToken: access_token,
        refreshToken: refresh_token,
        expiresIn: expires_in
      };
    } catch (error) {
      console.error('Erro ao obter token:', error.response?.data || error.message);
      throw error;
    }
  }

  // Uso
  getFlexExtractorToken('seu_username', 'sua_senha')
    .then(tokens => {
      console.log('Access Token:', tokens.accessToken.substring(0, 50) + '...');
    });
  ```

  ```python Python (Requests) theme={"theme":"catppuccin-latte"}
  import requests
  from datetime import datetime, timedelta

  def get_flexextractor_token(username: str, password: str):
      """
      Obtém token de acesso FlexExtractor

      Args:
          username: Nome de usuário
          password: Senha

      Returns:
          dict: Contendo access_token, refresh_token e expiration_time
      """
      url = "https://hml.flexextractor.com.br/api/v2/Security/GetToken"

      data = {
          'username': username,
          'password': password
      }

      headers = {
          'Content-Type': 'application/x-www-form-urlencoded'
      }

      try:
          response = requests.post(url, data=data, headers=headers)
          response.raise_for_status()

          token_data = response.json()
          access_token = token_data['access_token']
          refresh_token = token_data.get('refresh_token')
          expires_in = token_data['expires_in']

          # Calcula horário de expiração
          expiration_time = datetime.now() + timedelta(seconds=expires_in)

          print(f"✓ Token obtido com sucesso!")
          print(f"Expira em: {expiration_time.strftime('%Y-%m-%d %H:%M:%S')}")

          return {
              'access_token': access_token,
              'refresh_token': refresh_token,
              'expiration_time': expiration_time
          }

      except requests.exceptions.RequestException as e:
          print(f"✗ Erro ao obter token: {e}")
          raise

  # Uso
  if __name__ == "__main__":
      tokens = get_flexextractor_token('seu_username', 'sua_senha')
      print(f"\nToken: {tokens['access_token'][:50]}...")
  ```

  ```java Java theme={"theme":"catppuccin-latte"}
  import java.net.http.*;
  import java.net.*;
  import java.time.*;
  import com.google.gson.*;

  public class FlexExtractorAuthClient {

      private static final String TOKEN_URL =
          "https://hml.flexextractor.com.br/api/v2/Security/GetToken";

      public static class TokenResponse {
          public String access_token;
          public String refresh_token;
          public String token_type;
          public int expires_in;
          public int refresh_expires_in;
          public String id_token;
          public String session_state;
          public String scope;
      }

      public static TokenResponse getAccessToken(String username, String password)
              throws Exception {
          HttpClient client = HttpClient.newHttpClient();

          String body = "username=" + URLEncoder.encode(username, "UTF-8") +
                        "&password=" + URLEncoder.encode(password, "UTF-8");

          HttpRequest request = HttpRequest.newBuilder()
              .uri(URI.create(TOKEN_URL))
              .header("Content-Type", "application/x-www-form-urlencoded")
              .POST(HttpRequest.BodyPublishers.ofString(body))
              .build();

          HttpResponse<String> response = client.send(request,
              HttpResponse.BodyHandlers.ofString());

          if (response.statusCode() == 200) {
              Gson gson = new Gson();
              TokenResponse tokenResponse = gson.fromJson(
                  response.body(),
                  TokenResponse.class
              );

              Instant expiresAt = Instant.now()
                  .plusSeconds(tokenResponse.expires_in);
              System.out.println("✓ Token obtido com sucesso!");
              System.out.println("Expira em: " + expiresAt);

              return tokenResponse;
          } else {
              throw new RuntimeException("Erro ao obter token: " + response.body());
          }
      }

      public static void main(String[] args) {
          try {
              TokenResponse token = getAccessToken("seu_username", "sua_senha");
              System.out.println("\nToken: " +
                  token.access_token.substring(0, 50) + "...");
          } catch (Exception e) {
              System.err.println("Erro: " + e.getMessage());
          }
      }
  }
  ```

  ```php PHP theme={"theme":"catppuccin-latte"}
  <?php

  function getFlexExtractorToken($username, $password) {
      $url = 'https://hml.flexextractor.com.br/api/v2/Security/GetToken';

      $data = [
          'username' => $username,
          'password' => $password
      ];

      $ch = curl_init($url);
      curl_setopt($ch, CURLOPT_POST, true);
      curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($data));
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
      curl_setopt($ch, CURLOPT_HTTPHEADER, [
          'Content-Type: application/x-www-form-urlencoded'
      ]);

      $response = curl_exec($ch);
      $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
      curl_close($ch);

      if ($httpCode === 200) {
          $tokenData = json_decode($response, true);
          $expiresAt = date('Y-m-d H:i:s', time() + $tokenData['expires_in']);

          echo "✓ Token obtido com sucesso!\n";
          echo "Expira em: {$expiresAt}\n";

          return [
              'access_token' => $tokenData['access_token'],
              'refresh_token' => $tokenData['refresh_token'] ?? null,
              'expires_at' => $expiresAt
          ];
      } else {
          throw new Exception("Erro ao obter token: {$response}");
      }
  }

  // Uso
  try {
      $tokens = getFlexExtractorToken('seu_username', 'sua_senha');
      echo "\nToken: " . substr($tokens['access_token'], 0, 50) . "...\n";
  } catch (Exception $e) {
      echo "Erro: " . $e->getMessage() . "\n";
  }
  ?>
  ```

  ```go Go theme={"theme":"catppuccin-latte"}
  package main

  import (
      "encoding/json"
      "fmt"
      "io"
      "net/http"
      "net/url"
      "strings"
      "time"
  )

  type TokenResponse struct {
      AccessToken      string `json:"access_token"`
      RefreshToken     string `json:"refresh_token"`
      TokenType        string `json:"token_type"`
      ExpiresIn        int    `json:"expires_in"`
      RefreshExpiresIn int    `json:"refresh_expires_in"`
      IDToken          string `json:"id_token"`
      SessionState     string `json:"session_state"`
      Scope            string `json:"scope"`
  }

  func getFlexExtractorToken(username, password string) (*TokenResponse, error) {
      tokenURL := "https://hml.flexextractor.com.br/api/v2/Security/GetToken"

      data := url.Values{}
      data.Set("username", username)
      data.Set("password", password)

      req, err := http.NewRequest("POST", tokenURL, strings.NewReader(data.Encode()))
      if err != nil {
          return nil, err
      }

      req.Header.Set("Content-Type", "application/x-www-form-urlencoded")

      client := &http.Client{Timeout: 10 * time.Second}
      resp, err := client.Do(req)
      if err != nil {
          return nil, err
      }
      defer resp.Body.Close()

      body, err := io.ReadAll(resp.Body)
      if err != nil {
          return nil, err
      }

      if resp.StatusCode != http.StatusOK {
          return nil, fmt.Errorf("erro ao obter token: %s", string(body))
      }

      var tokenResp TokenResponse
      if err := json.Unmarshal(body, &tokenResp); err != nil {
          return nil, err
      }

      expiresAt := time.Now().Add(time.Duration(tokenResp.ExpiresIn) * time.Second)
      fmt.Printf("✓ Token obtido com sucesso!\n")
      fmt.Printf("Expira em: %s\n", expiresAt.Format("2006-01-02 15:04:05"))

      return &tokenResp, nil
  }

  func main() {
      tokenResp, err := getFlexExtractorToken("seu_username", "sua_senha")
      if err != nil {
          fmt.Printf("Erro: %v\n", err)
          return
      }

      fmt.Printf("\nToken: %s...\n", tokenResp.AccessToken[:50])
  }
  ```
</CodeGroup>

***

## Gerenciamento de Token

<AccordionGroup>
  <Accordion title="Tempo de Validade" icon="clock">
    O access\_token possui tempo de expiração configurável (geralmente 1 hora).

    **Recomendações:**

    * Armazene o horário de expiração ao obter o token
    * Renove o token **5 minutos antes** de expirar
    * Use o refresh\_token para renovação automática
    * Implemente tratamento de erro 401 (token expirado)

    **Exemplo de gerenciamento:**

    ```javascript theme={"theme":"catppuccin-latte"}
    class FlexExtractorTokenManager {
      constructor() {
        this.accessToken = null;
        this.refreshToken = null;
        this.expiresAt = null;
      }

      async getToken(username, password) {
        // Se token ainda é válido (com margem de 5min)
        if (this.accessToken && this.expiresAt > Date.now() + 300000) {
          return this.accessToken;
        }

        // Tenta renovar com refresh_token
        if (this.refreshToken) {
          try {
            await this.refreshAccessToken();
            return this.accessToken;
          } catch (error) {
            // Falhou, pega novo token
          }
        }

        // Obtém novo token
        const response = await this.fetchNewToken(username, password);
        this.accessToken = response.access_token;
        this.refreshToken = response.refresh_token;
        this.expiresAt = Date.now() + (response.expires_in * 1000);

        return this.accessToken;
      }
    }
    ```
  </Accordion>

  <Accordion title="Cache e Armazenamento" icon="database">
    **Boas Práticas:**

    * Cache tokens em memória durante validade
    * Use variáveis de ambiente para credenciais
    * Implemente singleton para gerenciamento centralizado
    * Criptografe tokens se armazenar em disco

    **Evite:**

    * Armazenar tokens em localStorage (frontend)
    * Logar tokens completos
    * Compartilhar tokens entre usuários
    * Hard-code de credenciais no código

    **Exemplo de cache seguro:**

    ```python theme={"theme":"catppuccin-latte"}
    import os
    from datetime import datetime, timedelta

    class TokenCache:
        def __init__(self):
            self._token = None
            self._expires_at = None

        def get_valid_token(self):
            if self._token and self._expires_at > datetime.now():
                return self._token
            return None

        def set_token(self, token, expires_in):
            self._token = token
            self._expires_at = datetime.now() + timedelta(seconds=expires_in)
    ```
  </Accordion>

  <Accordion title="Tratamento de Erros" icon="triangle-exclamation">
    **Erro 401 - Invalid Credentials**

    ```json theme={"theme":"catppuccin-latte"}
    {
      "error": "invalid_grant",
      "error_description": "Invalid user credentials"
    }
    ```

    **Causa:** Username ou password incorretos

    **Solução:** Verifique as credenciais fornecidas

    ***

    **Erro 400 - Missing Parameters**

    ```json theme={"theme":"catppuccin-latte"}
    {
      "error": "invalid_request",
      "error_description": "Missing form parameter: username"
    }
    ```

    **Causa:** Parâmetros obrigatórios ausentes

    **Solução:** Certifique-se de enviar username e password

    ***

    **Erro 401 - Token Expired**

    Quando usar um token expirado em outras APIs:

    **Solução:** Renove o token usando refresh\_token ou obtenha um novo
  </Accordion>

  <Accordion title="Segurança" icon="shield">
    **Práticas de Segurança:**

    1. **Proteja Credenciais:**
       * Nunca commite username/password em Git
       * Use variáveis de ambiente (.env)
       * Rotacione senhas periodicamente
    2. **Proteja Tokens:**
       * Use apenas HTTPS em produção
       * Nunca envie tokens em URLs
       * Não armazene em cookies sem flags de segurança
    3. **Monitoramento:**
       * Registre tentativas de autenticação falhas
       * Configure alertas para uso anômalo
       * Implemente rate limiting
    4. **Exemplo .env:**

    ```bash theme={"theme":"catppuccin-latte"}
    FLEXEXTRACTOR_USERNAME=seu_username
    FLEXEXTRACTOR_PASSWORD=sua_senha_segura
    FLEXEXTRACTOR_ENDPOINT=https://api.flexextractor.com.br
    ```
  </Accordion>
</AccordionGroup>

***

## Próximos Passos

Após obter seu token de acesso, você está pronto para usar a API de Extração!

<CardGroup cols={2}>
  <Card title="Extração de Dados (JSON)" icon="file-code" href="/flexextractor-extract">
    Extraia informações de documentos via imagem Base64
  </Card>

  <Card title="Tipos de Documento" icon="id-card" href="/flexextractor-tipos">
    Veja os tipos de documento suportados (RG, CNH, etc)
  </Card>
</CardGroup>
