Policy 18+

Objetivo

Entender como configurar a Presentation Definition para verificação de idade (18+) usando o padrão OpenID4VP.

O que é uma Presentation Definition?

A Presentation Definition (PD) é um documento JSON que descreve quais credenciais e campos você quer que o cidadão apresente. Ela segue o padrão DIF Presentation Exchange.

No caso do VerificaIdade, a PD solicita uma credencial do tipo ECACredential.

Presentation Definition para idade 18+

{
  "id": "eca-age-check",
  "input_descriptors": [
    {
      "id": "ECACredential",
      "name": "Comprovante de Maioridade",
      "purpose": "Verificar que o usuário é maior de 18 anos",
      "constraints": {
        "fields": [
          {
            "path": ["$.type"],
            "filter": {
              "type": "string",
              "pattern": "ECACredential"
            }
          }
        ]
      }
    }
  ]
}
Importante

Esta é uma Presentation Definition ilustrativa. A definição exata depende do tipo de credencial emitida pelo governo e do formato suportado. Consulte a documentação do emissor para os campos corretos.

Como usar

App React Native

Passe a Presentation Definition no corpo do POST /v1/verify/vp-request:

await fetch(`${BASE_URL}/v1/verify/vp-request`, {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    clientId: CLIENT_ID,
    presentationDefinition: PRESENTATION_DEFINITION,
  }),
});

Web (SDK React)

Instale o SDK:

npm install @injistack/react-inji-verify-sdk

Passe a Presentation Definition diretamente na prop presentationDefinition:

import { OpenID4VPVerification } from '@injistack/react-inji-verify-sdk';

const presentationDefinition = {
  id: 'eca-age-verification',
  purpose: 'Verificação de idade conforme o Estatuto da Criança e do Adolescente',
  format: { ldp_vc: { proof_type: ['Ed25519Signature2020'] } },
  input_descriptors: [
    {
      id: 'eca credential',
      format: { ldp_vc: { proof_type: ['Ed25519Signature2020'] } },
      constraints: {
        fields: [
          {
            path: ['$.type'],
            filter: { type: 'object', pattern: 'ECACredential' },
          },
        ],
      },
    },
  ],
};

<OpenID4VPVerification
  verifyServiceUrl="<VERIFY_BASE_URL>/v1/verify"
  clientId="did:web:<SEU_DOMINIO>:v1:verify"
  protocol="openid4vp://"
  isSameDeviceFlowEnabled={true}
  presentationDefinition={presentationDefinition}
  onVPProcessed={(results) => {
    const ok = results.some((r) => r.vcStatus === 'SUCCESS');
    console.log('Verificado:', ok);
  }}
  onError={(error) => console.error(error)}
  onQrCodeExpired={() => console.log('Expirou')}
/>
Nota

No contexto web, o SDK detecta automaticamente se o dispositivo é mobile e escolhe entre Deep Link (isSameDeviceFlowEnabled={true}) ou QR Code.

O que você recebe

Após o wallet submeter a VP, GET /v1/verify/vp-result/{transactionId} retorna:

{
  "vpResultStatus": "SUCCESS",
  "vcResults": [
    {
      "vc": { "credentialSubject": { "isOver18": true } },
      "vcStatus": "SUCCESS"
    }
  ]
}

O campo relevante para a decisão é vcResults[0].vc.credentialSubject.isOver18.

O que o INJI Verify Service valida

  1. Assinatura criptográfica — a credencial foi emitida por um emissor confiável?
  2. Formato — a credencial segue o padrão esperado (SD-JWT, CWT)?
  3. Expiração — a credencial ainda é válida?
  4. Revogação — a credencial foi revogada?
  5. Constraints — os campos solicitados na PD foram satisfeitos?

Minimização de dados

A Presentation Definition solicita apenas o tipo da credencial (ECACredential). O campo isOver18 é derivado da credencial pelo Verify Service — o app nunca recebe data de nascimento ou outros dados pessoais.

Nota

Isso é privacy by design. Você confirma que a pessoa tem 18+ sem saber a idade exata ou qualquer outro dado pessoal.

Próximo passo

Entenda as práticas de Segurança e LGPD.