# Como integrar validação de CPF em aplicações Tauri (Rust + web)

> Aprenda a integrar validação de CPF em aplicações Tauri usando Rust no backend e JavaScript no frontend com a API da CPFHub.io.

**Publicado:** 06/07/2026
**Autor:** Redação CPFHub.io
**URL:** https://cpfhub.io/blog/como-integrar-validacao-de-cpf-em-aplicacoes-tauri-rust-web

---


O **Tauri** é um framework para construção de aplicações desktop que combina um backend em **Rust** com um frontend web (HTML, CSS, JavaScript). Para integrar validação de CPF, a chamada à API da CPFHub.io é feita pelo backend Rust — mantendo a chave de API fora do alcance do webview — e o resultado é devolvido ao frontend via comando Tauri. A API responde em ~900ms com nome, data de nascimento e demais dados do titular ao receber `GET https://api.cpfhub.io/cpf/{CPF}` com o header `x-api-key`.

---

## 1. Pré-requisitos

* **Rust** (rustup) e **Node.js 18+** instalados.

* Tauri CLI: `cargo install tauri-cli`.

* Um projeto Tauri criado: `cargo tauri init`.

* Uma conta gratuita na [**CPFHub.io**](https://www.cpfhub.io/)

---

## 2. Adicione as dependências Rust

No `Cargo.toml` do projeto (dentro de `src-tauri/`), adicione as dependências necessárias:

```toml
[dependencies]
tauri = { version = "2", features = [] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
reqwest = { version = "0.12", features = ["json"] }
tokio = { version = "1", features = ["full"] }
dotenv = "0.15"
```

---

## 3. Configure as variáveis de ambiente

Crie um arquivo `.env` na pasta `src-tauri/`:

```env
CPFHUB_API_KEY=SUA_CHAVE_DE_API
CPFHUB_BASE_URL=https://api.cpfhub.io
CPFHUB_TIMEOUT=5
```

---

## 4. Crie as structs de resposta

Defina as structs Rust para deserializar a resposta da API:

```rust
// src-tauri/src/cpfhub.rs
use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize)]
pub struct CpfResponse {
 pub success: bool,
 pub data: Option<CpfData>,
}

#[derive(Debug, Serialize, Deserialize, Clone)]
pub struct CpfData {
 pub cpf: String,
 pub name: String,
 #[serde(rename = "nameUpper")]
 pub name_upper: String,
 pub gender: String,
 #[serde(rename = "birthDate")]
 pub birth_date: String,
 pub day: u32,
 pub month: u32,
 pub year: u32,
}

#[derive(Debug, Serialize)]
pub struct CpfError {
 pub message: String,
 pub status_code: u16,
}
```

---

## 5. Implemente o comando Tauri

Crie o comando que será invocado pelo frontend. Consulte a [documentação do Tauri](https://tauri.app/develop/calling-rust/) para referência completa sobre comandos:

```rust
// src-tauri/src/cpfhub.rs (continuação)
use reqwest::Client;
use std::time::Duration;
use std::env;

pub async fn consultar_cpf(cpf: &str) -> Result<CpfData, CpfError> {
 let cpf_limpo: String = cpf.chars().filter(|c| c.is_ascii_digit()).collect();

 if cpf_limpo.len() != 11 {
 return Err(CpfError {
 message: "CPF deve conter exatamente 11 dígitos".to_string(),
 status_code: 400,
 });
 }

 let api_key = env::var("CPFHUB_API_KEY").map_err(|_| CpfError {
 message: "Chave de API não configurada".to_string(),
 status_code: 500,
 })?;

 let base_url = env::var("CPFHUB_BASE_URL")
 .unwrap_or_else(|_| "https://api.cpfhub.io".to_string());

 let timeout: u64 = env::var("CPFHUB_TIMEOUT")
 .unwrap_or_else(|_| "5".to_string())
 .parse()
 .unwrap_or(5);

 let url = format!("{}/cpf/{}", base_url, cpf_limpo);

 let client = Client::builder()
 .timeout(Duration::from_secs(timeout))
 .build()
 .map_err(|e| CpfError {
 message: format!("Erro ao criar cliente HTTP: {}", e),
 status_code: 500,
 })?;

 let response = client
 .get(&url)
 .header("x-api-key", &api_key)
 .header("Accept", "application/json")
 .send()
 .await
 .map_err(|e| {
 if e.is_timeout() {
 CpfError {
 message: "Timeout ao consultar a API".to_string(),
 status_code: 504,
 }
 } else {
 CpfError {
 message: format!("Erro de conexão: {}", e),
 status_code: 502,
 }
 }
 })?;

 let status = response.status().as_u16();

 match status {
 200 => {
 let body: CpfResponse = response.json().await.map_err(|e| CpfError {
 message: format!("Erro ao parsear resposta: {}", e),
 status_code: 500,
 })?;

 if body.success {
 body.data.ok_or(CpfError {
 message: "Resposta sem dados".to_string(),
 status_code: 500,
 })
 } else {
 Err(CpfError {
 message: "Consulta retornou sucesso falso".to_string(),
 status_code: 500,
 })
 }
 }
 400 => Err(CpfError { message: "CPF com formato inválido".to_string(), status_code: 400 }),
 401 => Err(CpfError { message: "Chave de API inválida".to_string(), status_code: 401 }),
 404 => Err(CpfError { message: "CPF não encontrado".to_string(), status_code: 404 }),
 _ => Err(CpfError { message: format!("Erro HTTP {}", status), status_code: status }),
 }
}
```

---

## 6. Registre o comando no main.rs

Registre o comando Tauri para que o frontend possa invocá-lo:

```rust
// src-tauri/src/main.rs
mod cpfhub;

use cpfhub::{CpfData, CpfError};

#[tauri::command]
async fn consultar_cpf_command(cpf: String) -> Result<CpfData, String> {
 dotenv::dotenv().ok();

 match cpfhub::consultar_cpf(&cpf).await {
 Ok(data) => Ok(data),
 Err(e) => Err(format!("{}: {}", e.status_code, e.message)),
 }
}

fn main() {
 tauri::Builder::default()
 .invoke_handler(tauri::generate_handler![consultar_cpf_command])
 .run(tauri::generate_context!())
 .expect("Erro ao iniciar aplicação Tauri");
}
```

---

## 7. Crie o frontend

No frontend, invoque o comando Rust via `@tauri-apps/api`:

```html
<!-- src/index.html -->
<!DOCTYPE html>
<html lang="pt-BR">
<head>
 <meta charset="UTF-8">
 <title>Consulta de CPF - Tauri</title>
 <style>
 body { font-family: sans-serif; max-width: 600px; margin: 40px auto; padding: 0 20px; }
 input { padding: 10px; width: 200px; font-size: 16px; }
 button { padding: 10px 20px; font-size: 16px; cursor: pointer; }
 .resultado { margin-top: 20px; padding: 15px; border: 1px solid #ddd; border-radius: 4px; }
 .erro { color: #c0392b; }
 .sucesso { color: #27ae60; }
 </style>
</head>
<body>
 <h1>Consulta de CPF</h1>
 <div>
 <input type="text" id="cpf-input" placeholder="000.000.000-00" maxlength="14" />
 <button id="btn-consultar">Consultar</button>
 </div>
 <div id="resultado" class="resultado" style="display: none;"></div>
 <script type="module" src="/main.js"></script>
</body>
</html>
```

```javascript
// src/main.js
const { invoke } = window.__TAURI__.core;

const btnConsultar = document.getElementById("btn-consultar");
const cpfInput = document.getElementById("cpf-input");
const resultadoDiv = document.getElementById("resultado");

btnConsultar.addEventListener("click", async () => {
 const cpf = cpfInput.value.trim();
 if (!cpf) {
 mostrarErro("Digite um CPF.");
 return;
 }

 resultadoDiv.style.display = "block";
 resultadoDiv.innerHTML = "Consultando...";
 resultadoDiv.className = "resultado";

 try {
 const dados = await invoke("consultar_cpf_command", { cpf });
 mostrarSucesso(dados);
 } catch (erro) {
 mostrarErro(erro);
 }
});

function mostrarSucesso(dados) {
 resultadoDiv.className = "resultado sucesso";
 resultadoDiv.innerHTML = `
 <h3>CPF Encontrado</h3>
 <p><strong>Nome:</strong> ${dados.name}</p>
 <p><strong>CPF:</strong> ${dados.cpf}</p>
 <p><strong>Genero:</strong> ${dados.gender}</p>
 <p><strong>Nascimento:</strong> ${dados.birth_date}</p>
 `;
}

function mostrarErro(mensagem) {
 resultadoDiv.className = "resultado erro";
 resultadoDiv.innerHTML = `<p>${mensagem}</p>`;
 resultadoDiv.style.display = "block";
}
```

---

## 8. Boas práticas

* **Segurança** -- A chave de API fica exclusivamente no backend Rust, inacessível ao frontend. Nunca exponha credenciais no webview.

* **Timeout** -- Configure timeout no `reqwest::Client` para evitar que a aplicação trave aguardando respostas da rede.

* **Variáveis de ambiente** -- Use `.env` para desenvolvimento e variáveis de ambiente do sistema para distribuição.

* **Tratamento de erros** -- Mapeie cada código HTTP para uma mensagem clara que será exibida ao usuário.

* **Performance** -- O Tauri com Rust no backend oferece performance nativa. A API da CPFHub responde em ~900ms, proporcionando uma experiência fluida ao usuário.

* **LGPD** -- A API da CPFHub.io é 100% compatível com a LGPD. Em aplicações desktop, garanta que dados pessoais não sejam armazenados localmente sem o consentimento do usuário.

---

## Perguntas frequentes

### Por que fazer a chamada à API de CPF pelo backend Rust no Tauri?

O backend Rust em uma aplicação Tauri roda em processo separado do webview, sem acesso via DevTools do navegador. Isso significa que a chave de API nunca fica exposta ao ambiente web — qualquer inspeção de tráfego ou acesso ao webview não revela a credencial. A prática segue as recomendações de segurança da [OWASP](https://owasp.org/www-project-mobile-application-security/) para proteção de secrets em aplicações cliente.

### A API da CPFHub.io bloqueia quando o limite do plano é atingido?

Não. Ao atingir o limite mensal, a API continua respondendo normalmente e cobra R$0,15 por consulta adicional — sem retornar erro nem bloquear requisições. O plano gratuito inclui 50 consultas/mês e o plano Pro inclui 1.000 consultas/mês por R$149. O controle de uso fica disponível no painel em `app.cpfhub.io/settings/billing`.

### Como tratar o tempo de resposta de ~900ms em uma aplicação desktop Tauri?

Mostre um estado de carregamento no frontend assim que o usuário acionar a consulta, antes de aguardar a resposta do comando Rust. No frontend JavaScript, defina `resultadoDiv.innerHTML = "Consultando..."` antes do `invoke`, e use `try/catch` para exibir mensagem de erro em caso de timeout. Configure o `reqwest::Client` com timeout adequado para evitar que a UI trave indefinidamente.

### Como distribuir uma aplicação Tauri com a chave de API protegida?

Para distribuição, use variáveis de ambiente do sistema operacional em vez de arquivo `.env`. O instalador pode solicitar a chave durante a configuração inicial e armazená-la nas variáveis de ambiente do usuário. Outra abordagem é usar um backend intermediário (seu próprio servidor) que armazena a chave e serve como proxy para a API da CPFHub.io, removendo completamente a credencial do pacote distribuído.

---

### Leia também

- [Como validar CPF no frontend com React e API REST](https://cpfhub.io/blog/como-validar-cpf-no-frontend-com-react-e-api-rest)
- [Como consumir API de CPF em Rust com reqwest e serde](https://cpfhub.io/blog/como-consumir-api-de-cpf-em-rust-com-reqwest-e-serde)
- [Autenticação em APIs REST: como garantir segurança na consulta de CPF](https://cpfhub.io/blog/autenticacao-apis-rest-seguranca-consulta-cpf)
- [Boas práticas para consumir APIs de CPF de forma segura](https://cpfhub.io/blog/boas-praticas-consumir-apis-cpf-segura)

---

## Conclusão

Integrar a API da [**CPFHub.io**](https://www.cpfhub.io/)

Cadastre-se em [cpfhub.io](https://www.cpfhub.io/)

