---
url: 'https://www.corbado.com/pt/blog/como-construir-verifier-credenciais-digitais'
title: 'Como construir um Verifier de Credenciais Digitais (Guia para Desenvolvedores)'
description: 'Aprenda a construir um Verifier de credenciais digitais do zero usando Next.js, OpenID4VP e ISO mDoc. Este guia de desenvolvedor passo a passo mostra como criar um Verifier que pode solicitar, receber e validar carteiras de motorista móveis e outras crede'
lang: 'pt'
author: 'Amine'
date: '2025-08-20T15:39:36.826Z'
lastModified: '2026-03-25T10:03:57.899Z'
keywords: 'verifier de credenciais digitais, tutorial verifier, construir verifier'
category: 'Digital Credentials'
---

# Como construir um Verifier de Credenciais Digitais (Guia para Desenvolvedores)

## 1. Introdução

Provar identidades online é um desafio constante, que nos leva a depender de senhas e a
compartilhar documentos confidenciais por canais inseguros. Para as empresas, isso tornou
a verificação de identidade um processo lento, caro e suscetível a fraudes. As Credenciais
Digitais oferecem uma nova abordagem, colocando os usuários de volta no controle de seus
dados. Elas são o equivalente digital de uma
[carteira](https://www.corbado.com/pt/blog/garantia-carteiras-digitais) física, contendo desde uma
[carteira](https://www.corbado.com/pt/blog/garantia-carteiras-digitais) de motorista até um diploma
universitário, mas com os benefícios adicionais de serem criptograficamente seguras,
preservarem a privacidade e serem instantaneamente verificáveis.

Este guia oferece aos desenvolvedores um
[tutorial](https://www.corbado.com/pt/blog/aplicacao-crud-react-express-mysql) prático e passo a passo para
construir um Verifier para [Credenciais Digitais](https://www.corbado.com/pt/blog/credenciais-digitais-passkeys).
Embora os padrões existam, há pouca orientação sobre como implementá-los. Este
[tutorial](https://www.corbado.com/pt/blog/aplicacao-crud-react-express-mysql) preenche essa lacuna, mostrando
como construir um Verifier usando a
[API de Credenciais Digitais](https://www.corbado.com/pt/blog/digital-credentials-api) nativa do navegador, o
[OpenID4VP](https://www.corbado.com/glossary/open-id-4-vp) para o protocolo de apresentação e o ISO
[mDoc](https://www.corbado.com/glossary/mdoc) (por exemplo, [carteira](https://www.corbado.com/pt/blog/garantia-carteiras-digitais) de
motorista móvel) como formato da credencial.

O resultado final será uma aplicação [Next.js](https://www.corbado.com/blog/nextjs-passkeys) simples, mas
funcional, que pode solicitar, receber e verificar uma Credencial Digital de uma carteira
móvel compatível.

Veja um rápido vislumbre da aplicação final em ação. O processo envolve quatro etapas
principais:

**Etapa 1: Página Inicial** O usuário chega à página inicial e clica em "Verificar com
[Identidade Digital](https://www.corbado.com/pt/blog/credenciais-digitais-passkeys)" para iniciar o processo.
![Página inicial para solicitação de verificação](https://s3.eu-central-1.amazonaws.com/corbado-cloud-staging-website-assets/Screenshot_2025_07_25_at_11_00_33_5217b35c96.png)

**Etapa 2: Prompt de Confiança** O navegador solicita a confiança do usuário. O usuário
clica em "Continuar" para prosseguir.
![Prompt de confiança do navegador](https://s3.eu-central-1.amazonaws.com/corbado-cloud-staging-website-assets/Screenshot_2025_07_25_at_11_00_39_ba390a8097.png)

**Etapa 3: Escaneamento do QR Code** Um [QR code](https://www.corbado.com/blog/qr-code-login-authentication) é
exibido, que o usuário escaneia com sua aplicação de carteira compatível.
![QR code para escaneamento](https://s3.eu-central-1.amazonaws.com/corbado-cloud-staging-website-assets/Screenshot_2025_07_25_at_11_00_45_3b30669a10.png)

**Etapa 4: Credencial Decodificada** Após a verificação bem-sucedida, a aplicação exibe os
dados da credencial decodificada.
![Resultado da credencial decodificada](https://s3.eu-central-1.amazonaws.com/corbado-cloud-staging-website-assets/Screenshot_2025_07_25_at_11_01_36_684f7489cd.png)

### 1.1 Como Funciona

A magia por trás das [credenciais digitais](https://www.corbado.com/pt/blog/credenciais-digitais-passkeys) está
em um modelo de "**triângulo de confiança**" simples, mas poderoso, envolvendo três
participantes principais:

- **Issuer (Emissor):** Uma autoridade confiável (por exemplo, uma agência
  [governamental](https://www.corbado.com/passkeys-for-public-sector), universidade ou banco) que assina
  criptograficamente e emite uma credencial para um usuário.
- **Holder (Titular):** O usuário, que recebe a credencial e a armazena de forma segura em
  uma [carteira digital](https://www.corbado.com/pt/blog/garantia-carteiras-digitais) pessoal em seu dispositivo.
- **Verifier (Verificador):** Uma aplicação ou serviço que precisa verificar a credencial
  do usuário.

![Ecossistema de Credenciais Verificáveis do W3C](https://www.w3.org/TR/vc-data-model/diagrams/ecosystem.svg)

Quando um usuário quer acessar um serviço, ele apresenta a credencial de sua carteira. O
Verifier pode então verificar instantaneamente sua autenticidade sem precisar contatar o
[Issuer](https://www.corbado.com/glossary/issuer) original diretamente.

### 1.2 Por Que os Verifiers São Essenciais (e Por Que Você Está Aqui)

Para que este **ecossistema de identidade descentralizada** prospere, o papel do
**Verifier** é absolutamente crítico. Eles são os guardiões desta nova
[infraestrutura](https://www.corbado.com/passkeys-for-critical-infrastructure) de confiança, aqueles que consomem
as credenciais e as tornam úteis no mundo real. Como o diagrama abaixo ilustra, um
Verifier completa o triângulo de confiança ao solicitar, receber e validar uma credencial
do Holder.

Se você é um desenvolvedor, construir um serviço para realizar essa verificação é uma
habilidade fundamental para a próxima geração de aplicações seguras e centradas no
usuário. Este guia foi projetado para orientá-lo exatamente nesse processo. Cobriremos
tudo o que você precisa saber para **construir seu próprio Verifier de credenciais
verificáveis**, desde os conceitos e padrões fundamentais até os detalhes da implementação
passo a passo da validação de assinaturas e verificação do status da credencial.

> **Quer pular direto para o final?** Você pode encontrar o projeto completo deste
> [tutorial](https://www.corbado.com/pt/blog/aplicacao-crud-react-express-mysql) no GitHub. Sinta-se à vontade
> para cloná-lo e testá-lo você mesmo:
> [https://github.com/corbado/digital-credentials-example](https://github.com/corbado/digital-credentials-example)

Vamos começar.

## 2. Pré-requisitos para Construir um Verifier

Antes de começar, certifique-se de que você tem:

1. **Compreensão Básica de Credenciais Digitais e mDoc**
    - Este tutorial foca no formato **ISO mDoc** (por exemplo, para carteiras de motorista
      móveis) e não cobre outros formatos como W3C
      [Verifiable Credentials](https://www.corbado.com/glossary/microcredentials) (VCs). Familiaridade com os
      conceitos básicos do [mdoc](https://www.corbado.com/glossary/mdoc) será útil.
2. **Docker e Docker Compose**
    - Nosso projeto usa um banco de dados [MySQL](https://www.corbado.com/blog/passkey-webauthn-database-guide)
      em um contêiner Docker para gerenciar o estado da sessão OIDC. Certifique-se de ter
      ambos instalados e em execução.
3. **Protocolo Escolhido: OpenID4VP**
    - Usaremos o protocolo **OpenID4VP** (OpenID for Verifiable Presentations) para o
      fluxo de troca de credenciais.
4. **Tech Stack Preparado**
    - Usaremos **TypeScript** (Node.js) para a lógica de backend.
    - Usaremos **Next.js** tanto para o backend (API routes) quanto para o frontend (UI).
    - Bibliotecas chave: bibliotecas de decodificação [CBOR](https://www.corbado.com/glossary/cbor) para análise
      de [mdoc](https://www.corbado.com/glossary/mdoc) e um cliente
      [MySQL](https://www.corbado.com/blog/passkey-webauthn-database-guide).
5. **Credenciais de Teste e Wallet**
    - Usaremos a
      **[CMWallet](https://github.com/digitalcredentialsdev/CMWallet/actions/runs/16407676816/artifacts/3574255220)**
      para [Android](https://www.corbado.com/blog/how-to-enable-passkeys-android), que entende solicitações
      [OpenID4VP](https://www.corbado.com/glossary/open-id-4-vp) e pode apresentar credenciais mdoc.
6. **Conhecimento Básico de Criptografia**
    - Entender assinaturas digitais e conceitos de
      [chave pública](https://www.corbado.com/pt/glossary/jwks)/privada, pois se relacionam com mdoc e fluxos
      OIDC.

---

Agora vamos detalhar cada um desses pré-requisitos, começando pelos padrões e protocolos
que sustentam este Verifier baseado em mdoc.

### 2.1 Escolhas de Protocolo

Nosso Verifier foi construído para o seguinte:

| Padrão / Protocolo                                                                        | Descrição                                                                                                                                                                                            |
| :---------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **[W3C VC](https://www.w3.org/TR/vc-data-model/)**                                        | O Modelo de Dados de Credenciais Verificáveis do W3C. Ele define a estrutura padrão para credenciais digitais, incluindo claims, metadados e provas.                                                 |
| **[SD-JWT](https://datatracker.ietf.org/doc/draft-ietf-oauth-selective-disclosure-jwt/)** | Divulgação Seletiva para JWTs. Um formato para VCs baseado em JSON Web Tokens que permite aos Holders divulgar seletivamente apenas claims específicas de uma credencial, aumentando a privacidade.  |
| **[ISO mDoc](https://www.iso.org/standard/69084.html)**                                   | ISO/IEC 18013-5. O padrão internacional para Carteiras de Motorista móveis (mDLs) e outros IDs móveis, definindo estruturas de dados e protocolos de comunicação para uso online e offline.          |
| **OpenID4VP**                                                                             | OpenID for Verifiable Presentations. Um protocolo de apresentação interoperável construído sobre OAuth 2.0. Ele define como um Verifier solicita credenciais e como a wallet do Holder as apresenta. |

Para este tutorial, usamos especificamente:

- **OpenID4VP** como o protocolo para solicitar e receber credenciais.
- **ISO mDoc** como o formato da credencial (por exemplo, para carteiras de motorista
  móveis).

> **Nota sobre o Escopo:** Embora introduzamos brevemente W3C VC e SD-JWT para fornecer um
> contexto mais amplo, este tutorial implementa exclusivamente credenciais ISO mDoc via
> [OpenID4VP](https://www.corbado.com/glossary/open-id-4-vp). VCs baseadas em W3C estão fora do escopo deste
> exemplo.

#### 2.1.1 ISO mDoc (Mobile Document)

O padrão ISO/IEC 18013-5 mDoc define a estrutura e a codificação para documentos móveis,
como carteiras de motorista móveis (mDLs). As credenciais mDoc são codificadas em
[CBOR](https://www.corbado.com/glossary/cbor), assinadas criptograficamente e podem ser apresentadas digitalmente
para verificação. Nosso Verifier se concentrará em decodificar e validar essas credenciais
mdoc.

#### 2.1.2 OpenID4VP (OpenID for Verifiable Presentations)

O OpenID4VP é um protocolo interoperável para solicitar e apresentar
[credenciais digitais](https://www.corbado.com/pt/blog/credenciais-digitais-passkeys), construído sobre
[OAuth 2.0](https://www.corbado.com/glossary/oauth2) e OpenID Connect. Nesta implementação, o OpenID4VP é usado
para:

- Iniciar o fluxo de apresentação de credenciais (via
  [QR code](https://www.corbado.com/blog/qr-code-login-authentication) ou API do navegador)
- Receber a credencial mdoc da [wallet](https://www.corbado.com/blog/digital-wallet-assurance) do usuário
- Garantir uma troca de credenciais segura, com estado e que preserva a privacidade

### 2.2 Escolhas de Tech Stack

Agora que temos um entendimento claro dos padrões e protocolos, precisamos escolher o tech
stack certo para construir nosso Verifier. Nossas escolhas são projetadas para robustez,
experiência do desenvolvedor e compatibilidade com o ecossistema web moderno.

#### 2.2.1 Linguagem: TypeScript

Usaremos **TypeScript** tanto para nosso código de frontend quanto de backend. Como um
superset do JavaScript, ele adiciona tipagem estática, o que ajuda a capturar erros mais
cedo, melhora a qualidade do código e torna aplicações complexas mais fáceis de gerenciar.
Em um contexto sensível à segurança como a verificação de credenciais, a segurança de
tipos é uma grande vantagem.

#### 2.2.2 Framework: Next.js

**Next.js** é nosso framework de escolha porque oferece uma experiência integrada e fluida
para construir aplicações [full-stack](https://www.corbado.com/pt/blog/aplicacao-crud-react-express-mysql).

- **Para o Frontend:** Usaremos [Next.js](https://www.corbado.com/blog/nextjs-passkeys) com
  [React](https://www.corbado.com/blog/react-passkeys) para construir a interface do usuário onde o processo de
  verificação é iniciado (por exemplo, exibindo um
  [QR code](https://www.corbado.com/blog/qr-code-login-authentication)).
- **Para o Backend:** Aproveitaremos as **API Routes do Next.js** para criar os endpoints
  do lado do servidor. Esses endpoints são responsáveis por criar solicitações OpenID4VP
  válidas и por atuar como `redirect_uri` para receber e verificar com segurança a
  resposta final da CMWallet.

#### 2.2.3 Bibliotecas Chave

Nossa implementação depende de um conjunto específico de bibliotecas para o frontend e o
backend:

- **next**: O framework [Next.js](https://www.corbado.com/blog/nextjs-passkeys), usado tanto para as rotas da API
  de backend quanto para a UI do frontend.
- **react** e **react-dom**: Potencializam a interface do usuário do frontend.
- **cbor-web**: Usado para decodificar credenciais mdoc codificadas em
  [CBOR](https://www.corbado.com/glossary/cbor) em objetos JavaScript utilizáveis.
- **mysql2**: Fornece conectividade com o banco de dados
  [MySQL](https://www.corbado.com/blog/passkey-webauthn-database-guide) para armazenar desafios e sessões de
  verificação.
- **uuid**: Uma biblioteca para gerar strings de desafio únicas (nonces).
- **@types/uuid**: Tipos TypeScript para a geração de UUID.

> **Nota sobre `openid-client`:** Verifiers mais avançados e prontos para produção podem
> usar a biblioteca `openid-client` para lidar diretamente com o protocolo OpenID4VP no
> backend, habilitando recursos como um `redirect_uri` dinâmico. Em um fluxo OpenID4VP
> orientado pelo servidor com um `redirect_uri`, o `openid-client` seria usado para
> analisar e validar respostas `vp_token` diretamente. Para este tutorial, estamos usando
> um fluxo mais simples, mediado pelo navegador, que não o exige, tornando o processo mais
> fácil de entender.

Este tech stack garante uma implementação de Verifier robusta, com segurança de tipos e
escalável, focada na [API de Credenciais Digitais](https://www.corbado.com/pt/blog/digital-credentials-api) do
navegador e no formato de credencial ISO mDoc.

### 2.3 Obtenha uma Wallet e Credenciais de Teste

Para testar seu Verifier, você precisa de uma carteira móvel que possa interagir com a API
de Credenciais Digitais do navegador.

Usaremos a
**[CMWallet](https://github.com/digitalcredentialsdev/CMWallet/actions/runs/16407676816/artifacts/3574255220)**,
uma robusta [wallet](https://www.corbado.com/blog/digital-wallet-assurance) de teste compatível com OpenID4VP
para [Android](https://www.corbado.com/blog/how-to-enable-passkeys-android).

**Como Instalar a CMWallet (Android):**

1. **Baixe o arquivo APK** usando o link acima diretamente no seu dispositivo
   [Android](https://www.corbado.com/blog/how-to-enable-passkeys-android).
2. Abra as **Configurações > Segurança** do seu dispositivo.
3. Habilite **"Instalar aplicativos desconhecidos"** para o navegador que você usou para
   baixar o arquivo.
4. Localize o APK baixado na sua pasta "Downloads" e toque nele para iniciar a instalação.
5. Siga as instruções na tela para concluir a instalação.
6. Abra a CMWallet e você a encontrará pré-carregada com credenciais de teste, pronta para
   o fluxo de verificação.

> **Nota:** Instale arquivos APK apenas de fontes confiáveis. O link fornecido é do
> repositório oficial do projeto.

### 2.4 Conhecimento em Criptografia

Antes de mergulharmos na implementação, é essencial entender os conceitos criptográficos
que sustentam as credenciais verificáveis. É isso que as torna "verificáveis" e
confiáveis.

#### 2.4.1 Assinaturas Digitais: A Base da Confiança

No seu cerne, uma Credencial Verificável é um conjunto de declarações (como nome, data de
nascimento, etc.) que foi assinado digitalmente por um [Issuer](https://www.corbado.com/glossary/issuer). Uma
assinatura digital oferece duas garantias críticas:

- **Autenticidade:** Prova que a credencial foi de fato criada pelo
  [Issuer](https://www.corbado.com/glossary/issuer) e não por um impostor.
- **Integridade:** Prova que a credencial não foi alterada ou adulterada desde que foi
  assinada.

#### 2.4.2 Criptografia de Chave Pública/Privada

As assinaturas digitais são criadas usando
[criptografia de chave pública](https://www.corbado.com/pt/blog/webauthn-pubkeycredparams-credentialpublickey)/privada
(também chamada de criptografia assimétrica). Veja como funciona em nosso contexto:

1. **O Issuer tem um par de chaves:** uma chave privada, que é mantida em segredo, e uma
   [chave pública](https://www.corbado.com/pt/glossary/jwks), que é disponibilizada a todos (geralmente através
   de seu DID Document).
2. **Assinatura:** Quando um Issuer cria uma credencial, ele usa sua **chave privada**
   para gerar uma assinatura digital única para os dados específicos daquela credencial.
3. **Verificação:** Quando nosso Verifier recebe a credencial, ele usa a **chave pública**
   do Issuer para verificar a assinatura. Se a verificação for aprovada, o Verifier sabe
   que a credencial é autêntica e não foi adulterada. Qualquer alteração nos dados da
   credencial invalidaria a assinatura.

> **Nota sobre DIDs:** Neste tutorial, não resolvemos as chaves do Issuer via DIDs. Em
> produção, os Issuers normalmente exporiam chaves públicas via DIDs ou outros endpoints
> autoritativos, que o Verifier usaria para validação criptográfica.

#### 2.4.3 Credenciais Verificáveis como JWTs

Credenciais Verificáveis são frequentemente formatadas como **JSON Web Tokens (JWTs)**. Um
JWT é uma forma compacta e segura para URLs de representar declarações a serem
transferidas entre duas partes. Um JWT assinado (também conhecido como JWS) tem três
partes separadas por pontos (`.`):

- **Header:** Contém metadados sobre o token, como o algoritmo de assinatura usado
  (`alg`).
- **Payload:** Contém as declarações reais da Credencial Verificável (claim `vc`),
  incluindo o `issuer`, `credentialSubject`, etc.
- **Signature:** A assinatura digital gerada pelo Issuer, que cobre o header e o payload.

```
// Exemplo de uma estrutura JWT
[Header].[Payload].[Signature]
```

> **Nota:** Credenciais Verificáveis baseadas em JWT estão fora do escopo deste post de
> blog. Esta implementação foca em credenciais ISO mDoc e OpenID4VP, não em Credenciais
> Verificáveis W3C ou credenciais baseadas em JWT.

#### 2.4.4 A Apresentação Verificável: Provando a Posse

Não é suficiente para um Verifier saber que uma credencial é válida; ele também precisa
saber que a pessoa que _apresenta_ a credencial é o titular legítimo. Isso impede que
alguém use uma credencial roubada.

Isso é resolvido usando uma **Apresentação Verificável (VP)**. Uma VP é um invólucro em
torno de uma ou mais VCs que é **assinado pelo próprio Holder**.

O fluxo é o seguinte:

1. O Verifier pede ao usuário para apresentar uma credencial.
2. A [wallet](https://www.corbado.com/blog/digital-wallet-assurance) do usuário cria uma Apresentação
   Verificável, agrupa a(s) credencial(is) necessária(s) dentro dela e assina a
   apresentação inteira usando a **chave privada do Holder**.
3. A wallet envia esta VP assinada para o Verifier.

Nosso Verifier deve então realizar **duas** verificações de assinatura separadas:

1. **Verificar a(s) Credencial(is):** Verificar a assinatura em cada VC dentro da
   apresentação usando a **chave pública do Issuer**. (Prova que a credencial é real).
2. **Verificar a Apresentação:** Verificar a assinatura na própria VP usando a **chave
   pública do Holder**. (Prova que a pessoa que a apresenta é o proprietário).

Esta verificação em dois níveis garante tanto a autenticidade da credencial quanto a
identidade da pessoa que a apresenta, criando um modelo de confiança robusto e seguro.

> **Nota:** O conceito de Apresentações Verificáveis, conforme definido no ecossistema W3C
> VC, está fora do escopo deste post. O termo Apresentação Verificável aqui se refere à
> resposta `vp_token` do OpenID4VP, que se comporta de maneira semelhante a uma VP do W3C,
> mas é baseada na semântica do ISO mDoc em vez do modelo de assinatura
> [JSON-LD](https://www.corbado.com/glossary/json-ld) do W3C. Este guia foca em credenciais ISO mDoc e OpenID4VP,
> não em Apresentações Verificáveis W3C ou sua validação de assinatura.

## 3. Visão Geral da Arquitetura

Nossa arquitetura de Verifier usa a **API de Credenciais Digitais** nativa do navegador
como um intermediário seguro para conectar nossa aplicação web com a **CMWallet** móvel do
usuário. Essa abordagem simplifica o fluxo, permitindo que o navegador lide com a exibição
do QR code nativo e a comunicação com a wallet.

- **Frontend (Next.js & React):** Um site leve voltado para o usuário. Seu trabalho é
  buscar um objeto de solicitação do nosso backend, passá-lo para a API
  `navigator.credentials.get()` do navegador, receber o resultado e encaminhá-lo ao nosso
  backend para verificação.
- **Backend (Next.js API Routes):** O motor do Verifier. Ele gera um objeto de solicitação
  válido para a API do navegador e expõe um endpoint para receber a apresentação da
  credencial do frontend para validação final.
- **Navegador (Credential API):** O facilitador. Ele recebe o objeto de solicitação do
  nosso frontend, entende o protocolo `openid4vp` e gera nativamente um QR code. Em
  seguida, aguarda a wallet retornar uma resposta.
- **CMWallet (App Móvel):** A carteira do usuário. Ela escaneia o QR code, processa a
  solicitação, obtém o consentimento do usuário e envia a resposta assinada de volta para
  o navegador.

Aqui está um diagrama de sequência ilustrando o fluxo completo e preciso:

![Fluxo de Verificação usando a API de Credenciais Digitais do Navegador](https://s3.eu-central-1.amazonaws.com/corbado-cloud-staging-website-assets/Mermaid_Chart_Create_complex_visual_diagrams_with_text_A_smarter_way_of_creating_diagrams_2025_07_24_233623_1b6ed9b957.svg)

**O Fluxo Explicado:**

1. **Iniciação:** O usuário clica no botão "Verificar" em nosso **Frontend**.
2. **Objeto de Solicitação:** O frontend chama nosso **Backend** (`/api/verify/start`),
   que gera um objeto de solicitação contendo a query e um nonce, e então o retorna.
3. **Chamada da API do Navegador:** O frontend chama `navigator.credentials.get()` com o
   objeto de solicitação.
4. **QR Code Nativo:** O **Navegador** vê a solicitação do protocolo `openid4vp` e exibe
   nativamente um QR code. A promise `.get()` agora está pendente.

> **Nota:** Este fluxo de QR code ocorre em navegadores de desktop. Em navegadores móveis
> (Android Chrome com a flag experimental ativada), o navegador pode se comunicar
> diretamente com wallets compatíveis no mesmo dispositivo, eliminando a necessidade de
> escanear o QR code. Para habilitar esse recurso no Android Chrome, navegue para
> `chrome://flags#web-identity-digital-credentials` e defina a flag como "Enabled".

5. **Escanear e Apresentar:** O usuário escaneia o QR code com a **CMWallet**. A wallet
   obtém a aprovação do usuário e envia a Apresentação Verificável de volta para o
   navegador.
6. **Resolução da Promise:** O navegador recebe a resposta, e a promise `.get()` original
   no frontend finalmente é resolvida, entregando o payload da apresentação.
7. **Verificação no Backend:** O frontend envia o payload da apresentação via **POST**
   para o endpoint `/api/verify/finish` do nosso backend. O backend valida o nonce e a
   credencial.
8. **Resultado:** O backend retorna uma mensagem final de sucesso ou falha para o
   frontend, que atualiza a UI.

## 4. Construindo o Verifier

Agora que temos uma compreensão sólida dos padrões, protocolos e do fluxo arquitetural,
podemos começar a construir nosso Verifier.

> **Acompanhe ou Use o Código Final**
>
> Agora vamos passar pela configuração e implementação do código passo a passo. Se
> preferir pular direto para o produto final, você pode clonar o projeto completo do nosso
> repositório no GitHub e executá-lo localmente.
>
> ```bash
> git clone https://github.com/corbado/digital-credentials-example.git
> ```

### 4.1 Configurando o Projeto

Primeiro, vamos inicializar um novo projeto Next.js, instalar as dependências necessárias
e iniciar nosso banco de dados.

#### 4.1.1 Inicializando a Aplicação Next.js

Abra seu terminal, navegue até o diretório onde deseja criar seu projeto e execute o
seguinte comando. Estamos usando o App Router, TypeScript e Tailwind CSS para este
projeto.

```bash
npx create-next-app@latest . --ts --eslint --tailwind --app --src-dir --import-alias "@/*" --use-npm
```

Este comando cria o esqueleto de uma nova aplicação Next.js em seu diretório atual.

#### 4.1.2 Instalando Dependências

Em seguida, precisamos instalar as bibliotecas que lidarão com a decodificação CBOR,
conexões com o banco de dados e geração de UUID.

```bash
npm install cbor-web mysql2 uuid @types/uuid
```

Este comando instala:

- `cbor-web`: Para decodificar o payload da credencial mdoc.
- `mysql2`: O cliente MySQL para nosso banco de dados.
- `uuid`: Para gerar strings de desafio únicas.
- `@types/uuid`: Tipos TypeScript para a biblioteca `uuid`.

#### 4.1.3 Iniciando o Banco de Dados

Nosso backend requer um banco de dados MySQL para armazenar dados de sessão OIDC,
garantindo que cada fluxo de verificação seja seguro e com estado. Incluímos um arquivo
`docker-compose.yml` para facilitar isso.

Se você clonou o repositório, pode simplesmente executar `docker-compose up -d`. Se
estiver construindo do zero, crie um arquivo chamado `docker-compose.yml` com o seguinte
conteúdo:

```yaml
services:
    mysql:
        image: mysql:8.0
        restart: always
        environment:
            MYSQL_ROOT_PASSWORD: rootpassword
            MYSQL_DATABASE: digital_credentials
            MYSQL_USER: app_user
            MYSQL_PASSWORD: app_password
        ports:
            - "3306:3306"
        volumes:
            - mysql_data:/var/lib/mysql
            - ./sql/init.sql:/docker-entrypoint-initdb.d/init.sql
        healthcheck:
            test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
            timeout: 20s
            retries: 10

volumes:
    mysql_data:
```

Esta configuração do Docker Compose também requer um script de inicialização SQL. Crie um
diretório chamado `sql` e, dentro dele, um arquivo chamado `init.sql` com o seguinte
conteúdo para configurar as tabelas necessárias:

```sql
-- Create database if not exists
CREATE DATABASE IF NOT EXISTS digital_credentials;
USE digital_credentials;

-- Table for storing challenges
CREATE TABLE IF NOT EXISTS challenges (
    id VARCHAR(36) PRIMARY KEY,
    challenge VARCHAR(255) NOT NULL UNIQUE,
    expires_at TIMESTAMP NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    used BOOLEAN DEFAULT FALSE,
    INDEX idx_challenge (challenge),
    INDEX idx_expires_at (expires_at)
);

-- Table for storing verification sessions
CREATE TABLE IF NOT EXISTS verification_sessions (
    id VARCHAR(36) PRIMARY KEY,
    challenge_id VARCHAR(36),
    status ENUM('pending', 'verified', 'failed', 'expired') DEFAULT 'pending',
    presentation_data JSON,
    verified_at TIMESTAMP NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    FOREIGN KEY (challenge_id) REFERENCES challenges(id) ON DELETE CASCADE,
    INDEX idx_challenge_id (challenge_id),
    INDEX idx_status (status)
);

-- Table for storing verified credentials data (optional)
CREATE TABLE IF NOT EXISTS verified_credentials (
    id VARCHAR(36) PRIMARY KEY,
    session_id VARCHAR(36),
    credential_type VARCHAR(255),
    issuer VARCHAR(255),
    subject VARCHAR(255),
    claims JSON,
    verified_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    FOREIGN KEY (session_id) REFERENCES verification_sessions(id) ON DELETE CASCADE,
    INDEX idx_session_id (session_id),
    INDEX idx_credential_type (credential_type)
);
```

Com ambos os arquivos no lugar, abra seu terminal na raiz do projeto e execute:

```bash
docker-compose up -d
```

Este comando iniciará um contêiner MySQL em segundo plano.

### 4.2 Visão Geral da Arquitetura da Aplicação Next.js

Nossa aplicação Next.js está estruturada para separar as responsabilidades entre o
frontend e o backend, embora façam parte do mesmo projeto.

- **Frontend (`src/app/page.tsx`):** Uma única página [React](https://www.corbado.com/blog/react-passkeys) que
  inicia o fluxo de verificação e exibe o resultado. Ela interage com a
  [API de Credenciais Digitais](https://www.corbado.com/pt/blog/digital-credentials-api) do navegador.
- **Rotas de API do Backend (`src/app/api/verify/...`):**
    - `start/route.ts`: Gera a solicitação OpenID4VP e um nonce de segurança.
    - `finish/route.ts`: Recebe a apresentação da wallet (via navegador), valida o nonce e
      decodifica a credencial.
- **Biblioteca (`src/lib/`):**
    - `database.ts`: Gerencia todas as interações com o banco de dados (criação de
      desafios, verificação de sessões).
    - `crypto.ts`: Lida com a decodificação da credencial mDoc baseada em CBOR.

Aqui está um diagrama ilustrando a arquitetura interna:

![Arquitetura Interna do NextJS](https://s3.eu-central-1.amazonaws.com/corbado-cloud-staging-website-assets/Mermaid_Chart_Create_complex_visual_diagrams_with_text_A_smarter_way_of_creating_diagrams_2025_07_25_091202_f96ccb049f.svg)

### 4.3 Construindo o Frontend

Nosso frontend é intencionalmente leve. Sua principal responsabilidade é atuar como o
gatilho voltado para o usuário para o fluxo de verificação e se comunicar tanto com nosso
backend quanto com as capacidades nativas de manipulação de credenciais do navegador. Ele
não contém nenhuma lógica de protocolo complexa; tudo isso é delegado.

Especificamente, o frontend lidará com o seguinte:

- **Interação do Usuário:** Fornece uma interface simples, como um botão "Verificar", para
  o usuário iniciar o processo.
- **Gerenciamento de Estado:** Gerencia o estado da UI, mostrando indicadores de
  carregamento enquanto a verificação está em andamento e exibindo a mensagem final de
  sucesso ou erro.
- **Comunicação com o Backend (Solicitação):** Chama `/api/verify/start` e recebe um
  payload JSON estruturado (`protocol`, `request`, `state`) descrevendo exatamente o que a
  wallet deve apresentar.
- **Invocação da API do Navegador:** Entrega esse objeto JSON para
  `navigator.credentials.get()`, que renderiza um QR code nativo e aguarda a resposta da
  wallet.
- **Comunicação com o Backend (Resposta):** Assim que a API do navegador retorna a
  Apresentação Verificável, ele envia esses dados para nosso endpoint `/api/verify/finish`
  em uma solicitação POST para a validação final do lado do servidor.
- **Exibição de Resultados:** Atualiza a UI para informar ao usuário se a verificação foi
  bem-sucedida ou falhou, com base na resposta do backend.

A lógica principal está na função `startVerification`:

```typescript
// src/app/page.tsx

const startVerification = async () => {
    setLoading(true);
    setVerificationResult(null);

    try {
        // 1. Verifica se o navegador suporta a API
        if (!navigator.credentials?.get) {
            throw new Error("O navegador não suporta a Credential API.");
        }

        // 2. Pede ao nosso backend um objeto de solicitação
        const res = await fetch("/api/verify/start");
        const { protocol, request } = await res.json();

        // 3. Entrega esse objeto ao navegador – isso aciona o QR code nativo
        const credential = await (navigator.credentials as any).get({
            mediation: "required",
            digital: {
                requests: [
                    {
                        protocol, // "openid4vp"
                        data: request, // contém dcql_query, nonce, etc.
                    },
                ],
            },
        });

        // 4. Encaminha a resposta da wallet (do navegador) para nosso endpoint de finalização para verificações no lado do servidor
        const verifyRes = await fetch("/api/verify/finish", {
            method: "POST",
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify(credential),
        });

        const result = await verifyRes.json();

        if (verifyRes.ok && result.verified) {
            setVerificationResult(`Sucesso: ${result.message}`);
        } else {
            throw new Error(result.message || "Falha na verificação.");
        }
    } catch (err) {
        setVerificationResult(`Erro: ${(err as Error).message}`);
    } finally {
        setLoading(false);
    }
};
```

Esta função mostra as quatro etapas principais da lógica do frontend: verificar o suporte
da API, buscar a solicitação do backend, chamar a API do navegador e enviar o resultado de
volta para verificação. O restante do arquivo é boilerplate padrão do
[React](https://www.corbado.com/blog/react-passkeys) para gerenciamento de estado e renderização da UI, que você
pode ver no
[repositório do GitHub](https://github.com/corbado/digital-credentials-example).

#### Por que `digital` e `mediation: 'required'`?

Você pode notar que nossa chamada para `navigator.credentials.get()` parece diferente de
exemplos mais simples. Isso ocorre porque estamos aderindo estritamente à
[especificação oficial da API de Credenciais Digitais do W3C](https://www.w3.org/TR/digital-credentials/#the-digital-credentials-api).

- **Membro `digital`:** A especificação exige que todas as solicitações de credenciais
  digitais estejam aninhadas dentro de um objeto `digital`. Isso fornece um namespace
  claro e padronizado для esta API, distinguindo-a de outros tipos de credenciais (como
  `password` ou `federated`) e permitindo extensões futuras sem conflitos.

- **`mediation: 'required'`:** Esta opção é um recurso crucial de segurança e experiência
  do usuário. Ela impõe que o usuário deva interagir ativamente com um prompt (por
  exemplo, uma verificação biométrica, inserção de PIN ou uma tela de consentimento) para
  aprovar a solicitação da credencial. Sem isso, um site poderia potencialmente tentar
  acessar credenciais silenciosamente em segundo plano, o que representa um risco
  significativo à privacidade. Ao exigir a mediação, garantimos que o usuário esteja
  sempre no controle e dê consentimento explícito para cada transação.

### 4.4 Construindo os Endpoints do Backend

Com a UI do React no lugar, agora precisamos de duas rotas de API que fazem o trabalho
pesado no servidor:

1. **`/api/verify/start`** – constrói uma solicitação OpenID4VP, persiste um desafio de
   uso único no MySQL e entrega tudo de volta ao navegador.
2. **`/api/verify/finish`** – recebe a resposta da wallet, valida o desafio, verifica e
   decodifica a credencial e, finalmente, retorna um resultado JSON conciso para a UI.

#### 4.4.1 `/api/verify/start`: Gerar a Solicitação OpenID4VP

```typescript
// src/app/api/verify/start/route.ts
import { NextResponse } from "next/server";
import { v4 as uuidv4 } from "uuid";
import { createChallenge, cleanupExpiredChallenges } from "@/lib/database";

export async function GET() {
    // 1️⃣ Cria um nonce (desafio) aleatório e de curta duração
    const challenge = uuidv4();
    const challengeId = uuidv4();
    const expiresAt = new Date(Date.now() + 5 * 60 * 1000);

    await createChallenge(challengeId, challenge, expiresAt);
    cleanupExpiredChallenges().catch(console.error);

    // 2️⃣ Constrói uma query DCQL que descreve *o que* queremos
    const dcqlQuery = {
        credentials: [
            {
                id: "cred1",
                format: "mso_mdoc",
                meta: { doctype_value: "eu.europa.ec.eudi.pid.1" },
                claims: [
                    { path: ["eu.europa.ec.eudi.pid.1", "family_name"] },
                    { path: ["eu.europa.ec.eudi.pid.1", "given_name"] },
                    { path: ["eu.europa.ec.eudi.pid.1", "birth_date"] },
                ],
            },
        ],
    };

    // 3️⃣ Retorna um objeto que o navegador pode passar para navigator.credentials.get()
    return NextResponse.json({
        protocol: "openid4vp", // informa ao navegador qual protocolo de wallet usar
        request: {
            dcql_query: dcqlQuery, // O QUE apresentar
            nonce: challenge, // anti-replay
            response_type: "vp_token",
            response_mode: "dc_api", // a wallet fará POST diretamente para /finish
        },
        state: {
            credential_type: "mso_mdoc", // mantido para verificações posteriores
            nonce: challenge,
            challenge_id: challengeId,
        },
    });
}
```

> **Parâmetros chave**
>
> • **`nonce`** – desafio criptográfico que vincula a solicitação e a resposta (previne
> replay attacks). • **`dcql_query`** – Um objeto que descreve as claims exatas que
> precisamos. Para este guia, usamos uma estrutura `dcql_query` inspirada em rascunhos
> recentes da Digital Credential Query Language, embora este ainda não seja um padrão
> finalizado. • **`state`** – JSON arbitrário retornado pela wallet para que possamos
> localizar o registro no banco de dados.

#### 4.4.2 Ajudantes do Banco de Dados

O arquivo `src/lib/database.ts` encapsula as operações básicas do MySQL para desafios e
sessões de verificação (inserir, ler, marcar como usado). Manter essa lógica em um único
módulo facilita a troca do armazenamento de dados posteriormente.

---

### 4.5 `/api/verify/finish`: Validar e Decodificar a Apresentação

```typescript
// src/app/api/verify/finish/route.ts
import { NextResponse, NextRequest } from "next/server";
import { v4 as uuidv4 } from "uuid";
import {
    getChallenge,
    markChallengeAsUsed,
    createVerificationSession,
    updateVerificationSession,
} from "@/lib/database";
import { decodeDigitalCredential, decodeAllNamespaces } from "@/lib/crypto";

export async function POST(request: NextRequest) {
    const body = await request.json();

    // 1️⃣ Extrai as partes da apresentação verificável
    const vpTokenMap = body.vp_token ?? body.data?.vp_token;
    const state = body.state;
    const mdocToken = vpTokenMap?.cred1; // pedimos por este ID na dcqlQuery

    if (!vpTokenMap || !state || !mdocToken) {
        return NextResponse.json(
            { verified: false, message: "Resposta malformada" },
            { status: 400 },
        );
    }

    // 2️⃣ Validação do desafio de uso único
    const stored = await getChallenge(state.nonce);
    if (!stored) {
        return NextResponse.json(
            { verified: false, message: "Desafio inválido ou expirado" },
            { status: 400 },
        );
    }

    const sessionId = uuidv4();
    await createVerificationSession(sessionId, stored.id);

    // 3️⃣ Verificações criptográficas (pseudo) – substitua por validação mDL real em produção
    // Em uma aplicação real, você usaria uma biblioteca dedicada para realizar a validação
    // criptográfica completa da assinatura mdoc contra a chave pública do issuer.
    const isValid = mdocToken.length > 0;
    if (!isValid) {
        await updateVerificationSession(sessionId, "failed", {
            reason: "falha na validação do mdoc",
        });
        return NextResponse.json(
            { verified: false, message: "Falha na validação da credencial" },
            { status: 400 },
        );
    }

    // 4️⃣ Decodifica o payload da mobile-DL (mdoc) para JSON legível
    const decoded = await decodeDigitalCredential(mdocToken);
    const readable = decodeAllNamespaces(decoded)["eu.europa.ec.eudi.pid.1"];

    await markChallengeAsUsed(state.nonce);
    await updateVerificationSession(sessionId, "verified", { readable });

    return NextResponse.json({
        verified: true,
        message: "Credencial mdoc verificada com sucesso!",
        credentialData: readable,
        sessionId,
    });
}
```

> **Campos importantes na resposta da wallet**
>
> • **`vp_token`** – mapa que contém _cada_ credencial que a wallet retorna. Para nossa
> demonstração, pegamos `vp_token.cred1`. • **`state`** – eco do blob que fornecemos em
> `/start`; contém o `nonce` para que possamos procurar o registro no BD. •
> **`mdocToken`** – uma estrutura CBOR codificada em Base64URL que representa o ISO mDoc.

### 4.6 Decodificando a Credencial mdoc

Quando o Verifier recebe uma credencial mdoc do navegador, ela é uma string Base64URL
contendo dados binários codificados em CBOR. Para extrair as claims reais, o endpoint
`finish` realiza um processo de decodificação em várias etapas usando funções auxiliares
de `src/lib/crypto.ts`.

#### 4.6.1 Etapa 1: Decodificação Base64URL e CBOR

A função `decodeDigitalCredential` lida com a conversão da string codificada para um
objeto utilizável:

```typescript
// src/lib/crypto.ts
export async function decodeDigitalCredential(encodedCredential: string) {
    // 1. Converte Base64URL para Base64 padrão
    const base64UrlToBase64 = (input: string) => {
        let base64 = input.replace(/-/g, "+").replace(/_/g, "/");
        const pad = base64.length % 4;
        if (pad) base64 += "=".repeat(4 - pad);
        return base64;
    };

    const base64 = base64UrlToBase64(encodedCredential);

    // 2. Decodifica Base64 para binário
    const binaryString = atob(base64);
    const byteArray = Uint8Array.from(binaryString, (char) => char.charCodeAt(0));

    // 3. Decodifica CBOR
    const decoded = await cbor.decodeFirst(byteArray);
    return decoded;
}
```

- **Base64URL para Base64:** Converte a credencial de Base64URL para a codificação Base64
  padrão.
- **Base64 para Binário:** Decodifica a string Base64 em um array de bytes binário.
- **Decodificação CBOR:** Usa a biblioteca `cbor-web` para decodificar os dados binários
  em um objeto JavaScript estruturado.

#### 4.6.2 Etapa 2: Extraindo Claims com Namespace

A função `decodeAllNamespaces` processa ainda mais o objeto CBOR decodificado para extrair
as claims reais dos namespaces relevantes:

```typescript
// src/lib/crypto.ts
export function decodeAllNamespaces(jsonObj) {
    const decoded = {};

    try {
        jsonObj.documents.forEach((doc, idx) => {
            // 1) issuerSigned.nameSpaces:
            const issuerNS = doc.issuerSigned?.nameSpaces || {};
            Object.entries(issuerNS).forEach(([nsName, entries]) => {
                if (!decoded[nsName]) decoded[nsName] = {};
                (entries as any[]).forEach((entry) => {
                    const bytes = Uint8Array.from(entry.value);
                    const decodedEntry = cbor.decodeFirstSync(bytes);
                    Object.assign(decoded[nsName], decodedEntry);
                });
            });

            // 2) deviceSigned.nameSpaces (se presente):
            const deviceNS = doc.deviceSigned?.nameSpaces;
            if (deviceNS?.value?.data) {
                const bytes = Uint8Array.from(deviceNS.value);
                decoded[`deviceSigned_ns_${idx}`] = cbor.decodeFirstSync(bytes);
            }
        });
    } catch (e) {
        console.error(e);
    }

    return decoded;
}
```

- **Itera sobre todos os documentos** na credencial decodificada.
- **Decodifica cada namespace** (por exemplo, `eu.europa.ec.eudi.pid.1`) para extrair os
  valores reais das claims (como nome, data de nascimento, etc.).
- **Lida com namespaces assinados pelo issuer e pelo dispositivo**, se presentes.

#### Exemplo de Saída

Após passar por essas etapas, o endpoint `finish` obtém um objeto legível por humanos
contendo as claims do mdoc, por exemplo:

```json
{
    "family_name": "Doe",
    "given_name": "John",
    "birth_date": "1990-01-01"
}
```

Este processo garante que o Verifier possa extrair de forma segura e confiável as
informações necessárias da credencial mdoc para exibição e processamento posterior.

### 4.7 Apresentando o Resultado na UI

O endpoint `finish` retorna um objeto JSON mínimo para o frontend:

```json
{
    "verified": true,
    "message": "Credencial mdoc verificada com sucesso!",
    "credentialData": {
        "family_name": "Doe",
        "given_name": "John",
        "birth_date": "1990-01-01"
    }
}
```

O frontend recebe esta resposta em `startVerification()` e simplesmente a persiste no
estado do React para que possamos renderizar um cartão de confirmação agradável ou exibir
claims individuais – por exemplo, _“Bem-vindo, John Doe (nascido em 1990-01-01)!”_.

## 5. Executando o Verifier e Próximos Passos

Você agora tem um Verifier completo e funcional que usa as capacidades nativas de
manipulação de credenciais do navegador. Veja como executá-lo localmente e o que você pode
fazer para levá-lo de uma prova de conceito a uma aplicação pronta para produção.

### 5.1 Como Executar o Exemplo

1. **Clone o Repositório:**

    ```bash
    git clone https://github.com/corbado/digital-credentials-example.git
    cd digital-credentials-example
    ```

2. **Instale as Dependências:**

    ```bash
    npm install
    ```

3. **Inicie o Banco de Dados:** Certifique-se de que o Docker está em execução na sua
   máquina e, em seguida, inicie o contêiner MySQL:

    ```bash
    docker-compose up -d
    ```

4. **Execute a Aplicação:**

    ```bash
    npm run dev
    ```

    Abra seu navegador em `http://localhost:3000`, e você deverá ver a UI do Verifier.
    Agora você pode usar sua CMWallet para escanear o QR code e completar o fluxo de
    verificação.

### 5.2 Próximos Passos: Do Demo à Produção

Este tutorial fornece os blocos de construção fundamentais para um Verifier. Para torná-lo
pronto para produção, você precisaria implementar vários recursos adicionais:

- **Validação Criptográfica Completa:** A implementação atual usa uma verificação de
  placeholder (`mdocToken.length > 0`). Em um cenário real, você deve realizar a validação
  criptográfica completa da assinatura mdoc contra a [chave pública](https://www.corbado.com/pt/glossary/jwks) do
  Issuer (por exemplo, resolvendo seu DID ou buscando seu certificado de chave pública).
  Para padrões de resolução de DID, consulte a
  [especificação de Resolução de DID do W3C](https://www.w3.org/TR/did-resolution/).

- **Verificação de Revogação do Issuer:** As credenciais podem ser revogadas pelo emissor
  antes de sua data de expiração. Um Verifier de produção deve verificar o status da
  credencial consultando uma lista de revogação ou um endpoint de status fornecido pelo
  emissor. A
  [Lista de Status de Credenciais Verificáveis do W3C](https://www.w3.org/TR/vc-bitstring-status-list/)
  fornece o padrão para listas de revogação de credenciais.

- **Tratamento de Erros e Segurança Robustos:** Adicione tratamento de erros abrangente,
  validação de entrada, limitação de taxa (rate-limiting) nos endpoints da API e garanta
  que toda a comunicação seja via HTTPS (TLS) para proteger os dados em trânsito. As
  [Diretrizes de Segurança de API da OWASP](https://owasp.org/www-project-api-security/)
  fornecem práticas recomendadas abrangentes de segurança de API.

- **Suporte para Múltiplos Tipos de Credenciais:** Estenda a lógica para lidar com
  diferentes valores de `doctype` e formatos de credencial se você espera receber mais do
  que apenas a credencial PID da
  [Identidade Digital](https://www.corbado.com/pt/blog/credenciais-digitais-passkeys) Europeia (EUDI). O
  [Modelo de Dados de Credenciais Verificáveis do W3C](https://www.w3.org/TR/vc-data-model/)
  fornece especificações abrangentes de formato de VC.

### 5.3 O Que Está Fora do Escopo Deste Tutorial

Este exemplo é intencionalmente focado no fluxo principal mediado pelo navegador para
torná-lo fácil de entender. Os seguintes tópicos são considerados fora do escopo:

- **Segurança Pronta para Produção:** O Verifier é para fins educacionais e carece do
  endurecimento necessário para um ambiente de produção.
- **Credenciais Verificáveis W3C:** Este tutorial foca exclusivamente no formato ISO mDoc
  para carteiras de motorista móveis. Não cobre outros formatos populares como JWT-VCs ou
  VCs com Linked Data Proofs (LD-Proofs).
- **Fluxos Avançados do OpenID4VP:** Não implementamos recursos mais complexos do
  OpenID4VP, como comunicação direta da wallet com o backend usando um `redirect_uri` ou
  registro dinâmico de cliente.

Ao construir sobre esta base e incorporar esses próximos passos, você pode desenvolver um
Verifier robusto e seguro, capaz de confiar e validar credenciais digitais em suas
próprias aplicações.

## Conclusão

É isso! Com menos de 250 linhas de TypeScript, agora temos um Verifier de ponta a ponta
que:

1. Publica uma solicitação para a API de credenciais do navegador.
2. Permite que qualquer wallet compatível forneça uma Apresentação Verificável.
3. Valida a apresentação no servidor.
4. Atualiza a UI em tempo real.

Em produção, você substituiria a validação de placeholder por verificações completas do
[ISO 18013-5](https://www.corbado.com/glossary/iso-18013-5), adicionaria consultas de revogação do emissor,
limitação de taxa, logs de auditoria e, claro, TLS de ponta a ponta — mas os blocos de
construção principais permanecem exatamente os mesmos.

## Recursos

Aqui estão alguns dos principais recursos, especificações e ferramentas usadas ou
referenciadas neste tutorial:

- **Repositório do Projeto:**
    - [Código Fonte Completo no GitHub](https://github.com/corbado/digital-credentials-example)

- **Especificações Chave:**
    - [W3C Verifiable Credentials Data Model](https://www.w3.org/TR/vc-data-model/): O
      padrão fundamental para VCs.
    - [OpenID for Verifiable Presentations (OpenID4VP)](https://openid.net/specs/openid-4-verifiable-presentations-1_0.html):
      O protocolo de apresentação usado para a troca de credenciais.
    - [ISO/IEC 18013-5 (mDoc)](https://www.iso.org/standard/69084.html): O padrão
      internacional para Carteiras de Motorista móveis (mDLs).
    - [W3C Digital Credentials API](https://www.w3.org/TR/digital-credentials/#the-digital-credentials-api):
      A API do navegador usada para solicitar credenciais de uma wallet.

- **Ferramentas:**
    - [CMWallet for Android](https://github.com/digitalcredentialsdev/CMWallet/actions/runs/16407676816/artifacts/3574255220):
      A wallet de teste usada neste guia.

- **Bibliotecas:**
    - Next.js: O framework React para construir o frontend e o backend.
    - [cbor-web](https://github.com/hildjj/cbor-web): Para decodificar credenciais mdoc
      codificadas em CBOR.
    - [mysql2](https://github.com/sidorares/node-mysql2): O cliente MySQL para
      [Node.js](https://www.corbado.com/blog/nodejs-passkeys).
