Skip to content

Install the Verification Service

This article sets up an instance of the credential verification service. If you have not run either service before, work through the quickstart first — it brings up the verifier, the issuer and their database together and covers the prerequisites once.

Requirements

  • Docker with the Compose plugin.
  • OpenSSL, to generate the signing certificate.
  • Access to Partisia's container registry: docker login registry.gitlab.com. Please book a call with us to arrange it.
  • A PostgreSQL database the service can reach, with a database created for it. See Database.

Configure the service

The service reads a single JSON configuration file, conventionally server.json. This example is a complete working configuration:

server.json
{
  "port": 8081, // (1)!
  "baseUrl": "http://localhost:8081", // (2)!
  "database": { // (3)!
    "persistenceUnitName": "model",
    "driver": "org.postgresql.Driver",
    "url": "jdbc:postgresql://postgres:5432/verifier",
    "user": "postgres",
    "password": "postgres"
  },
  "clientMetadata": { // (4)!
    "clientName": "Verifier",
    "logoFile": "conf/static/partisia-logo.png"
  },
  "signing": { // (5)!
    "keyFile": "conf/signing-key/verifier-localhost.key",
    "certificateFiles": [
      "conf/signing-key/verifier-localhost.pem"
    ]
  },
  "integrations": { // (6)!
    "authentication": {
      "api-key": "Local development"
    }
  }
}
  1. REST endpoint port. Required.
  2. The address this service advertises to wallets. Required — the wallet uses it to fetch the authorization request and to submit the presentation, so it must be an address the wallet can reach.
  3. PostgreSQL connection. Required.
    • For a full explanation of this field see Database.
  4. Information about this verifier, shown to the holder on the wallet's consent screen.
  5. The signing key and certificate chain. Required — the service will not start without them, and this certificate is what determines the verifier's identity to a wallet.
  6. API keys accepted on the administrative endpoints. The JSON key is the token; the value is a label.
    • For a full explanation of this field see API keys.

Every other setting is optional — holder binding, trust anchors, the results callback. For the complete list see the configuration reference.

Add trust anchors before you verify in earnest

This configuration starts and serves, which is what an install page is for. Checking which issuers you accept is one more setting, issuerTrustAnchors, and a verifier started without it logs a warning saying so. See Issuer trust anchors.

Paths are relative to the container

keyFile, certificateFiles and logoFile are resolved against the container's working directory, /app. Mount your configuration directory there — ./verifier/conf:/app/conf:ro — and a path of conf/signing-key/x.key then refers to verifier/conf/signing-key/x.key on the host.

Generate the signing certificate

mkdir -p verifier/conf/signing-key
openssl req -x509 -newkey ec -pkeyopt ec_paramgen_curve:P-256 -nodes \
  -keyout verifier/conf/signing-key/verifier-localhost.key \
  -out    verifier/conf/signing-key/verifier-localhost.pem \
  -days 365 -subj "/CN=localhost" -sha256

This certificate is more than a formality on the verifier: its hash is the verifier's OID4VP client_id, and a wallet validates it before showing the holder a consent screen. A self-signed pair works with a wallet you configure yourself; wallets you do not operate will refuse it. See Trust model.

Run it

Run the image with your configuration directory mounted:

docker run -d \
  -p 8081:8081 \
  -w /app \
  -v "$(pwd)/verifier/conf:/app/conf:ro" \
  registry.gitlab.com/secata/platform/did/release/verifier-backend:latest

The issuer and verifier are released independently but tested as pairs, so pull both at the same time. See Going to production for recording which version you run.

In practice you will run this alongside the database with Compose; the quickstart has a complete docker-compose.yml.

The log prints Starting server when the service is ready. Navigate to http://localhost:8081/openapi for the API specification, where you can try the endpoints directly. Remember to supply your API key — the administrative endpoints return 401 without it.

Check it works

Create a verification query, then start a session from it:

curl -X POST http://localhost:8081/presentation/oid4vp/new-session \
  -H 'Authorization: Bearer api-key' \
  -H 'Content-Type: application/json' \
  -d '{ "verification_query_id": "<your query id>" }'

A successful call returns a session_id and a request_uri. Confirm the session exists with GET /presentation/oid4vp/status/{session_id}, which should report VERIFICATION_STARTED.

A 400 Bad Request here means verification_query_id was missing or names a query that does not exist — a session cannot be started without one.

What's next?

The verification service is now able to talk to wallets and verify the presentations they send.

  1. Create a verification query. State which credentials and claims you are asking for. Required before any session can start.
  2. Request a presentation. What your own application calls, and when.
  3. Receive verified data. Configure a callback so results are pushed to your application instead of polled.
  4. Issuer trust anchors. Decide which issuers this verifier accepts.

Troubleshooting

Startup, connection and request failures are collected in Troubleshooting.