Skip to content

Registry to Wallet-Relying Party Access Certificate (WRPAC) workaround runbook

This runbook records the staging flow for a test tenant and workarounds used with registry.serviceproviders.eudiw.dev.

All values in this test flow are synthetic. Do not copy them into production.

Preconditions

  • Present a PID or mDOC successfully through the Registry authentication flow.
  • Save the new hash_pid returned by POST /getpidoid4vp.
  • Open the Registry Swagger UI.
  • Use the same authenticated session and hash_pid for every request below.

Do not commit hash_pid, presentation IDs, access tokens, P12 base64 data, or P12 passwords to Git.

1. Authenticate a PID

  1. Call GET /authentication.
  2. Open the returned QR code or deep link in a wallet.
  3. Complete the presentation in the wallet.
  4. Call POST /getpidoid4vp?presentation_id=your_presentation_id_here.
  5. Save the returned hash_pid locally as a secret or input value.

2. Create Registry records in order

Create the records in this order:

  1. Law
  2. Legal Person
  3. Identifier
  4. Legal Entity
  5. Policies
  6. Provider
  7. Credential
  8. Intended Use
  9. Supervisory Authority
  10. Wallet Relying Party
  11. WRPAC certificate

These test IDs came from one staging test flow:

ResourceTest ID
Law292
Legal Person284
Identifier288
Legal Entity275
Provider277
Credential363
Intended Use192
Supervisory Authority161
Wallet RP139

These IDs refer only to that test account. Use the IDs returned by the API in a new session.

3. Country limitation

The Registry test backend rejected RS as the country value. The test record used DE so the flow could continue.

DE is not a valid substitute for production legal data. Confirm supported countries before production and use the actual jurisdiction and legal-entity details.

4. Work around the credential creation mismatch

Symptom: the documented object form returns HTTP 500

POST /credential/create returns HTTP 500 when meta contains the documented JSON object.

Workaround: serialize meta as a JSON string

Send meta as a serialized JSON string, although the Swagger model shows a JSON object:

json
{
  "hash_pid": "your_hash_pid_here",
  "credentials": [
    {
      "format": "sd-jwt",
      "meta": "{\"vct_values\":[\"urn:eudi:pid:1\"]}",
      "claims": [
        { "path": ["pid"] }
      ]
    }
  ]
}

Endpoint:

text
POST https://registry.serviceproviders.eudiw.dev/credential/create
Content-Type: application/json

Expected result: 201 Created with a credential ID.

Registry response mismatch

  • meta as an object currently triggers the deployed backend failure.
  • meta as a serialized string succeeds.
  • Use an array for claims.path.
  • This mismatch between the Registry backend and its documentation is not a long-term API contract.
  • Upstream issue #32 tracks a separate failure for non-empty claims arrays. Do not use it as evidence for this mismatch.
  • Track this mismatch separately until the deployed service accepts the documented object form.

5. Work around the Intended Use date requirement

The create endpoint requires both createdAt and revokedAt.

Use date-only values rather than ISO timestamps:

json
{
  "hash_pid": "your_hash_pid_here",
  "intended_uses": [
    {
      "createdAt": "2030-01-01",
      "revokedAt": "2031-01-01",
      "credential_ids": [1234567890123],
      "intendedUseIdentifier": "USE-your_tenant_here-001",
      "privacyPolicy_id": [1234567890124],
      "purpose": [
        {
          "content": "Identity verification",
          "lang": "en"
        }
      ]
    }
  ]
}

Endpoint:

text
POST https://registry.serviceproviders.eudiw.dev/intended_use/create

Verify the result immediately:

text
POST https://registry.serviceproviders.eudiw.dev/intended_use/list

Do not rely on 201 alone. One failed attempt returned 201 with a null ID, while /intended_use/list remained empty. The successful attempt used YYYY-MM-DD and returned an ID.

6. Create a Supervisory Authority

Wallet RP creation requires a valid Supervisory Authority owned by the same authenticated user.

Example test payload:

json
{
  "hash_pid": "your_hash_pid_here",
  "supervisoryAuthority": [
    {
      "country": "DE",
      "name": "your_supervisory_authority_here",
      "email": ["operator@example.com"],
      "formURI": ["https://example.com/contact"],
      "phone": ["+49123456789"]
    }
  ]
}

Endpoint:

text
POST https://registry.serviceproviders.eudiw.dev/supervisory_authority/create

Provide at least one contact method.

7. Create a Wallet Relying Party

Use IDs returned by the previous requests:

json
{
  "hash_pid": "your_hash_pid_here",
  "WalletRelyingParty": [
    {
      "entitlements": [
        "http://data.europa.eu/eudi/entitlement/Service_Provider"
      ],
      "intendedUse_ids": [1234567890125],
      "isPSB": false,
      "provider_id": 1234567890126,
      "providesAttestations_id": [],
      "registryURI": "https://registry.example",
      "srvDescription": [
        {
          "content": "your_service_description_here",
          "lang": "en"
        }
      ],
      "supervisoryAuthority": 1234567890127,
      "supportURI": ["https://example.com/support"],
      "tradeName": "your_trade_name_here",
      "usesIntermediary": []
    }
  ]
}

Endpoint:

text
POST https://registry.serviceproviders.eudiw.dev/wallet_rp/create

Use the entitlement URI accepted by the backend

The Swagger example uses AGE_VERIFICATION, but the deployed backend rejected it. Use a full entitlement URI accepted by the backend, such as:

text
http://data.europa.eu/eudi/entitlement/Service_Provider

Verify the result with:

text
POST https://registry.serviceproviders.eudiw.dev/wallet_rp/list

8. Generate the WRPAC PKCS#12 file

Use the authenticated hash_pid, the returned wrp_id, and a password stored securely outside Git:

json
{
  "hash_pid": "your_hash_pid_here",
  "password": "your_p12_password_here",
  "wrp_id": 1234567890128
}

Endpoint:

text
POST https://registry.serviceproviders.eudiw.dev/wallet_rp/certificate

Expected response:

json
{
  "code": 200,
  "data": {
    "file_base64": "your_base64_p12_here",
    "filename": "document_with_signature.json"
  },
  "status": "success"
}

The filename is misleading: file_base64 contains PKCS#12 material even when the response filename ends in .json.

Decode the file locally and do not commit it:

bash
printf '%s' "$WRPAC_BASE64" | base64 --decode > wrpac.p12

Validate the P12 with the password used in the request:

bash
openssl pkcs12 -info -in wrpac.p12 -noout

Do not paste the base64 value or password into tickets, GitHub issues, logs, or chat.

9. Upload the certificate in the dashboard

In the staging dashboard integration form:

  1. Select the correct tenant and staging environment.
  2. Enter the registered display and legal names.
  3. Upload wrpac.p12.
  4. Enter the exact P12 password.
  5. Add only registered origins.
  6. Select the registered provider or issuer and credential format.
  7. Submit the request for operator approval.
  8. Confirm that the operator review payload is present before approving.

If the request says Resubmission required with “no review payload,” submit it again through the current integration flow instead of approving the stale request.

Enterprise readiness checklist

Resolve these items before production:

  • Replace test legal-entity, Supervisory Authority, URL, email, and phone values.
  • Confirm the correct member state. Do not use DE as a substitute for RS.
  • Register a real Provider certificate chain instead of x5c: [].
  • Remove the meta serialization workaround only after a live registry regression check accepts both the documented object form and the serialized form with equivalent results.
  • Fix the misleading WRPAC filename and provide a direct binary download.
  • Make all create endpoints transactional; never return 201 with a null ID.
  • Verify every create request with its corresponding list endpoint.
  • Store P12 passwords in a secret manager, never in source or frontend state.
  • Add audit logging, idempotency, retry handling, and clear application-level error responses.
  • Keep generated WRPAC private-key material out of logs and support tickets.

Built for developers integrating privacy-preserving identity verification.