Como Integrar APIs de CPF em um Sistema Ruby on Rails com Devise

Aprenda a integrar validação de CPF via API em um sistema Ruby on Rails com Devise, adicionando verificação de identidade ao fluxo de autenticação.

Redação CPFHub.io
Redação CPFHub.io
··7 min de leitura
Como Integrar APIs de CPF em um Sistema Ruby on Rails com Devise

Para integrar validação de CPF via API em um sistema Ruby on Rails com Devise, adicione o campo cpf ao model de usuário, processe a verificação em um ActiveJob assíncrono usando Faraday para chamar GET https://api.cpfhub.io/cpf/{CPF} com o header x-api-key, e condicione o acesso a funcionalidades sensíveis ao status cpf_verificado. O registro ocorre sem bloqueio enquanto a verificação acontece em background — garantindo boa experiência ao usuário e identidade validada antes de operações críticas.

Introdução

O Devise é a gem de autenticação mais utilizada em aplicações Rails, gerenciando registro, login e recuperação de senha. Integrar a validação de CPF via API ao fluxo do Devise adiciona uma camada de verificação de identidade que fortalece a segurança do cadastro, sem adicionar fricção perceptível ao usuário no momento do registro.

Adicionando CPF ao model de usuário

Primeiro, adicione o campo de CPF ao model de usuário e configure as validações.

# db/migrate/XXXXXX_add_cpf_to_users.rb
class AddCpfToUsers < ActiveRecord::Migration[7.1]
    def change
    add_column :users, :cpf, :string
    add_column :users, :cpf_verificado, :boolean, default: false
    add_column :users, :nome_cpf, :string
    add_column :users, :genero_cpf, :string
    add_column :users, :data_nascimento_cpf, :date

    add_index :users, :cpf, unique: true
    end
end

# app/models/user.rb
class User < ApplicationRecord
    devise :database_authenticatable, :registerable,
    :recoverable, :rememberable, :validatable

    validates :cpf, presence: true, uniqueness: true
    validate :cpf_formato_valido
    validate :cpf_algoritmo_valido

    before_save :limpar_cpf

    private

    def limpar_cpf
    self.cpf = cpf.gsub(/\D/, "") if cpf.present?
    end

    def cpf_formato_valido
    return if cpf.blank?

    cpf_limpo = cpf.gsub(/\D/, "")
    unless cpf_limpo.match?(/\A\d{11}\z/)
    errors.add(:cpf, "deve conter 11 digitos")
    end
    end

    def cpf_algoritmo_valido
    return if cpf.blank?

    cpf_limpo = cpf.gsub(/\D/, "")
    return if cpf_limpo.length != 11

    if cpf_limpo.chars.uniq.size == 1
    errors.add(:cpf, "nao pode ter todos os digitos iguais")
    return
    end

    unless CpfValidator.digitos_validos?(cpf_limpo)
    errors.add(:cpf, "possui digitos verificadores invalidos")
    end
    end
end
CampoTipoDescrição
cpfstringCPF do usuário (11 dígitos, único)
cpf_verificadobooleanSe o CPF foi verificado via API
nome_cpfstringNome retornado pela API
genero_cpfstringGênero retornado pela API
data_nascimento_cpfdateData de nascimento retornada pela API

Customizando o controller de registro do Devise

Para permitir o campo de CPF no registro, customize o controller do Devise.

# app/controllers/users/registrations_controller.rb
class Users::RegistrationsController < Devise::RegistrationsController
    before_action :configure_sign_up_params, only: [:create]
    before_action :configure_account_update_params, only: [:update]

    def create
    super do |user|
    if user.persisted?
    VerificarCpfJob.perform_later(user.id)
    end
    end
    end

    private

    def configure_sign_up_params
    devise_parameter_sanitizer.permit(
    :sign_up,
    keys: [:cpf, :nome]
    )
    end

    def configure_account_update_params
    devise_parameter_sanitizer.permit(
    :account_update,
    keys: [:cpf, :nome]
    )
    end
end

# config/routes.rb
Rails.application.routes.draw do
    devise_for :users, controllers: {
    registrations: "users/registrations"
    }
end

Job de verificação de CPF via API

Após o registro, um job verifica o CPF via API e atualiza o perfil do usuário.

# app/jobs/verificar_cpf_job.rb
class VerificarCpfJob < ApplicationJob
    queue_as :default
    retry_on Faraday::TimeoutError, wait: :exponentially_longer, attempts: 3

    def perform(user_id)
    user = User.find(user_id)
    return if user.cpf_verificado?

    cliente = Faraday.new(url: "https://api.cpfhub.io") do |conn|
    conn.headers["x-api-key"] = ENV["CPFHUB_API_KEY"]
    conn.options.timeout = 10
    conn.adapter Faraday.default_adapter
    end

    resposta = cliente.get("/cpf/#{user.cpf}")
    resultado = JSON.parse(resposta.body)

    if resultado["success"]
    dados = resultado["data"]
    user.update!(
    cpf_verificado: true,
    nome_cpf: dados["name"],
    genero_cpf: dados["gender"],
    data_nascimento_cpf: dados["birthDate"]
    )

    UserMailer.cpf_verificado(user).deliver_later
    Rails.logger.info("[VerificarCpfJob] CPF #{user.cpf} verificado")
    else
    Rails.logger.warn(
    "[VerificarCpfJob] CPF #{user.cpf} nao encontrado na base"
    )
    end
    end
end

# app/services/cpf_validator.rb
class CpfValidator
    def self.digitos_validos?(cpf)
    numeros = cpf.chars.map(&:to_i)

    # Primeiro dígito verificador
    soma = (0..8).sum { |i| numeros[i] * (10 - i) }
    resto = (soma * 10) % 11
    resto = 0 if resto == 10
    return false unless resto == numeros[9]

    # Segundo dígito verificador
    soma = (0..9).sum { |i| numeros[i] * (11 - i) }
    resto = (soma * 10) % 11
    resto = 0 if resto == 10
    resto == numeros[10]
    end
end

Middleware de verificação de CPF

Crie um middleware que exige CPF verificado para acessar determinadas funcionalidades.

# app/controllers/concerns/cpf_verificado_concern.rb
module CpfVerificadoConcern
    extend ActiveSupport::Concern

    included do
    before_action :exigir_cpf_verificado, if: :usuario_logado?
    end

    private

    def exigir_cpf_verificado
    return unless acao_requer_cpf_verificado?

    unless current_user.cpf_verificado?
    if request.format.json?
    render json: {
    erro: "CPF nao verificado",
    mensagem: "Aguarde a verificacao do seu CPF para acessar esta funcionalidade"
    }, status: :forbidden
    else
    redirect_to verificacao_pendente_path,
    alert: "Seu CPF ainda esta sendo verificado."
    end
    end
    end

    def acao_requer_cpf_verificado?
    self.class.const_defined?(:ACOES_REQUEREM_CPF) &&
    self.class::ACOES_REQUEREM_CPF.include?(action_name.to_sym)
    end

    def usuario_logado?
    user_signed_in?
    end
end

# app/controllers/pedidos_controller.rb
class PedidosController < ApplicationController
    include CpfVerificadoConcern
    ACOES_REQUEREM_CPF = %i[create update].freeze

    def create
    # Apenas usuários com CPF verificado chegam aqui
    end
end
AçãoRequer CPF VerificadoMotivo
Navegar no siteNãoAcesso público
Criar contaNãoCPF será verificado após registro
Realizar compraSimSegurança da transação
Alterar dadosSimProteção contra fraude
Ver históricoNãoDados do próprio usuário

Formulário de registro com CPF

Customize a view de registro do Devise para incluir o campo de CPF com máscara.

<%# app/views/devise/registrations/new.html.erb %>
<%= form_for(resource, as: resource_name,
    url: registration_path(resource_name)) do |f| %>

    <div class="campo">
    <%= f.label :nome, "Nome completo" %>
    <%= f.text_field :nome, required: true, autofocus: true %>
    </div>

    <div class="campo">
    <%= f.label :email %>
    <%= f.email_field :email, required: true %>
    </div>

    <div class="campo">
    <%= f.label :cpf, "CPF" %>
    <%= f.text_field :cpf,
    required: true,
    inputmode: "numeric",
    maxlength: 14,
    placeholder: "000.000.000-00",
    data: { controller: "mascara-cpf" } %>
    <span class="info">
    Seu CPF sera verificado para seguranca da sua conta.
    </span>
    </div>

    <div class="campo">
    <%= f.label :password, "Senha" %>
    <%= f.password_field :password, required: true,
    minlength: Devise.password_length.min %>
    </div>

    <div class="acoes">
    <%= f.submit "Criar conta" %>
    </div>
<% end %>

Perguntas frequentes

Por que usar um ActiveJob assíncrono para verificar o CPF em vez de fazer a chamada na hora do registro?

A chamada à API tem latência de aproximadamente 900ms e pode ocasionalmente exceder esse tempo. Fazer a verificação em background evita que o usuário espere durante o registro e protege o fluxo de cadastro contra falhas de rede ou timeout da API. O acesso a funcionalidades sensíveis fica condicionado ao campo cpf_verificado, garantindo segurança sem prejudicar a experiência.

Como armazenar a chave de API com segurança em uma aplicação Rails?

Armazene a chave em uma variável de ambiente (ENV["CPFHUB_API_KEY"]) e nunca a coloque diretamente no código-fonte. Em produção, utilize ferramentas como Rails credentials (rails credentials:edit), secrets managers do provedor de nuvem (AWS Secrets Manager, Google Secret Manager) ou serviços como Doppler. Consulte as diretrizes da OWASP sobre gestão de segredos para boas práticas adicionais.

O que acontece se o CPF não for encontrado na API após o registro?

O job registra um aviso no log e o campo cpf_verificado permanece false. O usuário consegue fazer login normalmente, mas é bloqueado nas ações que requerem CPF verificado (como realizar compras ou alterar dados sensíveis). Você pode configurar um retry com backoff exponencial ou acionar um fluxo de revisão manual para esses casos.

Como garantir conformidade com a LGPD ao armazenar dados retornados pela API?

Armazene apenas os campos necessários para as finalidades declaradas (nome para exibição, data de nascimento para verificação de idade). Implemente controle de acesso aos registros contendo dados do CPF, defina período de retenção e documente a base legal para o tratamento. A ANPD recomenda o princípio da minimização: armazene apenas o que é estritamente necessário para cada finalidade.


Conclusão

Integrar a validação de CPF via API ao fluxo de autenticação do Devise fortalece a segurança do cadastro sem adicionar fricção excessiva ao usuário. O registro ocorre normalmente enquanto a verificação acontece em background. Funcionalidades sensíveis ficam condicionadas à verificação, criando uma camada adicional de proteção contra fraudes e cadastros fraudulentos.

Cadastre-se em cpfhub.io — 50 consultas mensais gratuitas, sem cartão de crédito — e adicione verificação de identidade ao seu sistema Rails com Devise ainda hoje.

CPFHub.io

Pronto para integrar a API?

50 consultas gratuitas para testar agora. Sem cartão de crédito. Acesso imediato à documentação.

Redação CPFHub.io

Sobre a redação

Redação CPFHub.io

Time editorial especializado em APIs de CPF, identidade digital e compliance no mercado brasileiro. Produzimos guias técnicos, análises regulatórias e tutoriais sobre LGPD e KYC para desenvolvedores e líderes de produto.

WhatsAppFale conosco via WhatsApp