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"
}
}
]
}
}
]
}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-sdkPasse 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')}
/>
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
- Assinatura criptográfica — a credencial foi emitida por um emissor confiável?
- Formato — a credencial segue o padrão esperado (SD-JWT, CWT)?
- Expiração — a credencial ainda é válida?
- Revogação — a credencial foi revogada?
- 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.
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.