Skip to Content
ReferenceServicesVerification Engine

Verification Engine — Service Reference

Module: backends/verification-engine · REST: 8082 · gRPC: 50052 · Stateless — no local mutable state, no database of its own.

RPC surface (verification.proto)

verifyCredential(VerifyCredentialRequest) -> VerifyCredentialResponse

message VerifyCredentialRequest { bytes credential_json = 1; bool check_status = 2; bool check_expiration = 3; } message VerifyCredentialResponse { bool is_valid = 1; string signature_status = 2; // "VALID", "INVALID", "UNVERIFIABLE" string status_check_result = 3; // "ACTIVE", "REVOKED", "UNKNOWN" string expiration_status = 4; // "VALID", "EXPIRED" string issuer_did = 5; int64 verified_at = 6; repeated VerificationError errors = 7; }

Errors: INVALID_ARGUMENT (missing/invalid credential JSON), NOT_FOUND (issuer not in registry), INTERNAL (unexpected error).

validateSignature(ValidateSignatureRequest) -> ValidateSignatureResponse

message ValidateSignatureRequest { bytes credential_json = 1; string issuer_did = 2; bytes public_key = 3; // optional — resolved from registry if absent } message ValidateSignatureResponse { bool is_valid = 1; string algorithm = 2; // "eddsa-jcs-2022" string verification_method = 3; string error_message = 4; }

Targeted signature validation without full credential context — simple pass/fail.

checkCredentialStatus(CheckStatusRequest) -> CheckStatusResponse

message CheckStatusRequest { string credential_id = 1; string status_list_url = 2; // accepted, not yet consulted — see note below } message CheckStatusResponse { string credential_id = 1; string status = 2; // "ACTIVE", "DISPUTED", "REVOKED", "UNKNOWN" int64 checked_at = 3; string error_message = 4; string superseded_by_credential_id = 5; // final current successor; empty if none string superseded_by_issuer_name = 6; string superseded_by_provenance_tier = 7; string superseded_by_shareable_id = 8; }

Checks two independent Redis caches (verification:status:v2:, terminal-revocation, 30s TTL; and verification:supersession:v1:, configurable via verification.cache.supersession-ttl-seconds, 300s default). On either cache miss, makes one Credential Issuance getCredential gRPC call for both status and the final successor summary. An unresolved credential or successor chain fails closed for successor disclosure.

status_list_url is accepted (and threaded through Core Engine’s /api/v1/credentials/verify) but not yet consulted — every credential uses the simple ACTIVE/REVOKED status column, not a W3C StatusList2021-style external bitstring. A caller can safely omit the field.

Supporting components

ComponentRole
VerificationService.verifySignature()Ed25519 verification via Bouncy Castle
VerificationService.isNotExpired()Expiration check
VerificationService.checkCredentialStatus()Reads status + successor disclosure from one Credential Issuance response, TTL-cached
GrpcServerConfigNetty server on 50052; registryStub() blocking stub to Issuer Registry (localhost:50051 default, 10 MB max, 30s keep-alive)
GrpcLogInterceptorRequest/response logging, latency tracking, correlation ID via MDC
grpc: server: port: 50052 enable-keep-alive: true keep-alive-time: 30s max-inbound-message-size: 10485760 issuer-registry: grpc: host: localhost # "issuer-registry" in Docker port: 50051

Test coverage

Reject empty credential JSON Verify valid credential with signature Check revocation status Validate Ed25519 signature Reject missing issuer

All 5 tests use CountDownLatch for async synchronization.

Stateless design

  • No local mutable state — every data point fetched on-demand from the request or an external service.
  • Enables horizontal scaling without session affinity; each request is independent and atomic.

Security

  • Never handles private keys — all signing happens in Issuer Registry (or the BYOK issuer’s own custody).
  • Public keys fetched on-demand from Issuer Registry, never cached locally except short-term Redis caching of verification results.
  • Ed25519 only, 32-byte key length validated.

Manual testing

grpcurl -plaintext localhost:50052 list grpcurl -plaintext -d '{"credential_json": "...base64-encoded-json..."}' \ localhost:50052 \ com.attestpro.verification.VerificationEngineService/VerifyCredential

What’s not implemented

Credential result caching beyond the two status/supersession caches, a batch verification RPC, webhook notifications on critical failures, and fetching/caching external revocation lists (BitString StatusList2021Entry).