Form Validation
Add credential verification and signature checks to your existing form workflows. Verify identity, professional credentials, or document signatures before allowing a form submission.
Use Cases
- KYC before submit — require a verified identity credential before accepting a registration form
- Professional credential check — confirm the user holds a valid professional license (e.g., licensed lawyer, certified engineer)
- Document signature validation — verify a signed document attached to the form
- Age/residency verification — request selective disclosure of specific claims without revealing the full credential
Form Validation Hook
TypeScript
import { pickWallet, verifyPresentation } from '@attestto/id-wallet-adapter' async function validateWithCredential(form: HTMLFormElement) { // 1. Pick a wallet and request a presentation const wallet = await pickWallet({ render: 'modal' }) const vp = await wallet.requestPresentation({ challenge: crypto.randomUUID(), credentialType: 'ProfessionalLicense', }) // 2. Attach VP to form data const vpField = document.createElement('input') vpField.type = 'hidden' vpField.name = 'verifiable_presentation' vpField.value = JSON.stringify(vp) form.appendChild(vpField) return true } // Attach to form submit document.querySelector('form').addEventListener('submit', async (e) => { e.preventDefault() const valid = await validateWithCredential(e.target) if (valid) e.target.submit() })
Server-side Middleware
middleware/form-verify.ts
import { verifyPresentation } from '@attestto/id-wallet-adapter' export async function verifyFormCredential(req, res, next) { const vpJson = req.body.verifiable_presentation if (!vpJson) return res.status(400).json({ error: 'Credential required' }) const vp = JSON.parse(vpJson) const result = await verifyPresentation(vp, { trustedIssuers: ['did:web:colegio-abogados.cr'], checkRevocation: true, }) if (!result.valid) { return res.status(403).json({ errors: result.errors }) } req.verifiedDid = result.holderDid next() }
Selective Disclosure Request
For age or residency verification, request only the claims you need. The wallet shows the user exactly which fields will be shared.
TypeScript
const vp = await wallet.requestPresentation({ challenge: crypto.randomUUID(), selectiveDisclosure: { credentialType: 'NationalID', requestedFields: ['ageOver18', 'countryOfResidence'], }, }) // Only ageOver18 and countryOfResidence are disclosed // Full name, ID number, etc. remain private
Error Handling
| Error | Meaning | Action |
|---|---|---|
CREDENTIAL_REVOKED | The credential has been revoked by the issuer | Reject the form. Inform the user their credential is no longer valid. |
ISSUER_UNTRUSTED | The credential issuer is not in your trusted list | Reject or flag for manual review. |
SIGNATURE_INVALID | The presentation signature does not verify | Reject. Possible tampering. |
Embed Verify Widget
For a visual verification indicator inside your form, embed the
<attestto-verify> Web Component. It shows a verification
badge once the credential is confirmed.
HTML
<form> <!-- Your form fields --> <attestto-verify credential-type="ProfessionalLicense" trusted-issuers="did:web:colegio-abogados.cr" ></attestto-verify> <button type="submit">Submit</button> </form>