Skip to content
โ—‡ AirawatOS Developer
๐Ÿšง Under development โ€” this portal is being built track by track. Content will keep growing, and some sections are still placeholders.

Tutorials

Verify a person across states with a credential (issue โ†’ carry โ†’ verify)

A common federation need: one state's agency has to trust a fact another state's agency issued โ€” a migrant worker registered by their home state, a degree from another state's university, a birth certificate issued elsewhere. The wrong way is a live database-to-database integration between every pair of agencies. The right way on AirawatOS is a Verifiable Credential (VC): the home agency issues the person a signed claim, the person carries it, and the destination agency verifies the signature offline against the issuer's published key โ€” no call between the two agencies at verify time.

Worked example: Bihar's labour board issues a construction-worker registration; the worker migrates; Maharashtra's board verifies it before porting benefits. Three roles: the issuer (home state), the holder (the migrant), the verifier (destination state).

Reference URLs (local dev): app-host http://localhost:8099 ยท network http://localhost:8090 ยท identity :8093.
The two agencies are two tenants on the same network. Set HOME=bihar-labour and DEST=maharashtra-labour
(substitute your own tenant ids โ€” each must be a network participant with a steward key).

Part 1 โ€” The ISSUER (home state) issues a signed credential

1a. Govern the credential type (once)

A credential's type must be a governed credential.* noun โ€” the network only lets an agency issue a type everyone has agreed on. Propose it, a steward approves it (the governed change-request loop):

DEV=$(curl -s -X POST http://localhost:8093/realms/bihar-labour/login \
  -H 'content-type: application/json' -d '{"username":"bihar-labour-admin"}' | jq -r .access_token)

# propose the type (its claims contract) โ€ฆ
curl -s -X POST http://localhost:8090/v1/schema-requests -H "Authorization: Bearer $DEV" \
  -H 'content-type: application/json' -d '{
    "schema_id":"credential.bocw_registration","version":"0.1.0","x_kind":"fragment",
    "definition":{"type":"object","x-kind":"fragment","properties":{
      "reg_no":{"type":"string"},"name":{"type":"string"},"trade":{"type":"string"}}},
    "justification":"Inter-state portability of BOCW worker registration"}'
# โ€ฆ then a network steward approves it (POST /v1/schema-requests/decide {decision:"approve"}).

1b. Issue the credential to the worker

Once the type is governed, the agency issues a VC to the holder (the worker's identity). It's signed with the issuer tenant's steward Ed25519 key, held in Vault (born there, never exported):

curl -s -X POST http://localhost:8090/v1/credentials/issue -H "Authorization: Bearer $DEV" \
  -H 'content-type: application/json' -d '{
    "issuer_tenant":"bihar-labour",
    "holder":"user://bihar-labour/asha",
    "type":"credential.bocw_registration",
    "title":"BOCW Worker Registration",
    "claims":{"reg_no":"BR-2024-0091","name":"Asha Devi","trade":"mason"},
    "expires_at":"2027-03-31T00:00:00Z"
  }'
# โ†’ {"issued":"ds:bihar-labour:credential/credential.bocw_registration-โ€ฆ","credential":{โ€ฆ,"signature":{โ€ฆ}}}
You usually don't call issue directly. In a real service, issuance is the last step of a workflow: a
workflow step declares issues: credential.bocw_registration, and when the registration is approved the
platform mints the VC into the worker's wallet automatically. Direct issue is shown here
so you can see the shape.

Part 2 โ€” The HOLDER (the migrant) carries it in their wallet

The worker owns the credential โ€” it lives in their wallet (the My Documents app), not on an agency server. Issuance creates an offer; the holder accepts it, which deposits their own signed copy into their own tenant (genuine holder-controlled storage). The app calls three app-host bridges:

Bridge (POST)Does
/bridge/my-credentialsthe wallet: offers (awaiting accept) + held (accepted)
/bridge/credential-accept {credential_id}accept an offer โ†’ deposit the signed VC into the holder's tenant
/bridge/credential-verify {credential}verify any held VC (used to show a green tick)

The worker never has to be online with Bihar again โ€” the signed credential is theirs to present.


Part 3 โ€” The VERIFIER (destination state) verifies it

Maharashtra's board verifies the credential the worker presents. It resolves Bihar's published steward public key from the network directory and checks the signature โ€” no call to Bihar. Verification checks both authenticity and validity:

curl -s -X POST http://localhost:8099/bridge/credential-verify \
  -H 'content-type: application/json' -d '{"credential": <the presented VC object>}'
{
  "verified": true,              // โ† the one field to gate on: authentic AND currently valid
  "signature_valid": true,       // signature checks out against the issuer's published key
  "revoked": false,              // issuer has not revoked it
  "expired": false,              // within expires_at
  "revocation_checked": true,    // the network held an authoritative record for this id
  "key_source": "directory",     // issuer key came from the CA-signed directory (cross-tenant), not a local guess
  "issuer_tenant": "bihar-labour", "type": "credential.bocw_registration", "holder": "user://bihar-labour/asha"
}

Gate on verified. It is true only when the signature holds and the credential is not revoked and not expired. A revoked or lapsed registration returns verified:false with a reason, even though its signature is still genuine โ€” authenticity is not validity, and for "verify a migrant" you need both.

Verify as part of applying for a service (the common case)

Usually the worker isn't verified in the abstract โ€” they apply for a Maharashtra service that requires the credential. Declare it on the offering, and the platform verifies the presented VC for you and pins it to the case as evidence:

// Maharashtra's service offering
{ "tenant":"maharashtra-labour", "service_id":"benefit-porting", โ€ฆ,
  "required_credentials":["credential.bocw_registration"] }

When the worker files, their app presents the held VC in credential_refs; the provider re-verifies it (verified && holder==applicant && type matches) before the case proceeds. This is the stronger form of "upload your certificate" โ€” a tamper-evident credential re-checked against the issuer's key, not a PDF.


Part 4 โ€” Revocation: keeping verification honest over time

A registration can be cancelled. The issuer revokes it; from then on verification reports it invalid โ€” the signature is still genuine, but the credential is no longer valid:

# Bihar (the issuer) revokes โ€” only the issuing tenant may:
curl -s -X POST http://localhost:8099/bridge/credential-revoke \
  -b bihar_cookies -H 'content-type: application/json' \
  -d '{"credential_id":"ds:bihar-labour:credential/โ€ฆ","reason":"registration cancelled"}'

# Maharashtra verifies again โ†’ now rejected:
# { "verified": false, "signature_valid": true, "revoked": true, "reason": "revoked", โ€ฆ }

This is what makes cross-state verification trustworthy: a signature proves it was issued; revocation and expiry prove whether it is still valid.


What must be true

For any cross-agency credential check to be sound:


Current limits (reference-grade โ€” read before you ship)

Related: Interaction (how requests + receipts work),
Data Ownership & Consent (who owns a record and how sharing is
consented), and Participants (identity + roles on the network).