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_pidreturned byPOST /getpidoid4vp. - Open the Registry Swagger UI.
- Use the same authenticated session and
hash_pidfor every request below.
Do not commit hash_pid, presentation IDs, access tokens, P12 base64 data, or P12 passwords to Git.
1. Authenticate a PID
- Call
GET /authentication. - Open the returned QR code or deep link in a wallet.
- Complete the presentation in the wallet.
- Call
POST /getpidoid4vp?presentation_id=your_presentation_id_here. - Save the returned
hash_pidlocally as a secret or input value.
2. Create Registry records in order
Create the records in this order:
- Law
- Legal Person
- Identifier
- Legal Entity
- Policies
- Provider
- Credential
- Intended Use
- Supervisory Authority
- Wallet Relying Party
- WRPAC certificate
These test IDs came from one staging test flow:
| Resource | Test ID |
|---|---|
| Law | 292 |
| Legal Person | 284 |
| Identifier | 288 |
| Legal Entity | 275 |
| Provider | 277 |
| Credential | 363 |
| Intended Use | 192 |
| Supervisory Authority | 161 |
| Wallet RP | 139 |
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:
{
"hash_pid": "your_hash_pid_here",
"credentials": [
{
"format": "sd-jwt",
"meta": "{\"vct_values\":[\"urn:eudi:pid:1\"]}",
"claims": [
{ "path": ["pid"] }
]
}
]
}Endpoint:
POST https://registry.serviceproviders.eudiw.dev/credential/create
Content-Type: application/jsonExpected result: 201 Created with a credential ID.
Registry response mismatch
metaas an object currently triggers the deployed backend failure.metaas 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
claimsarrays. 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:
{
"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:
POST https://registry.serviceproviders.eudiw.dev/intended_use/createVerify the result immediately:
POST https://registry.serviceproviders.eudiw.dev/intended_use/listDo 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:
{
"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:
POST https://registry.serviceproviders.eudiw.dev/supervisory_authority/createProvide at least one contact method.
7. Create a Wallet Relying Party
Use IDs returned by the previous requests:
{
"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:
POST https://registry.serviceproviders.eudiw.dev/wallet_rp/createUse 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:
http://data.europa.eu/eudi/entitlement/Service_ProviderVerify the result with:
POST https://registry.serviceproviders.eudiw.dev/wallet_rp/list8. Generate the WRPAC PKCS#12 file
Use the authenticated hash_pid, the returned wrp_id, and a password stored securely outside Git:
{
"hash_pid": "your_hash_pid_here",
"password": "your_p12_password_here",
"wrp_id": 1234567890128
}Endpoint:
POST https://registry.serviceproviders.eudiw.dev/wallet_rp/certificateExpected response:
{
"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:
printf '%s' "$WRPAC_BASE64" | base64 --decode > wrpac.p12Validate the P12 with the password used in the request:
openssl pkcs12 -info -in wrpac.p12 -nooutDo 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:
- Select the correct tenant and
stagingenvironment. - Enter the registered display and legal names.
- Upload
wrpac.p12. - Enter the exact P12 password.
- Add only registered origins.
- Select the registered provider or issuer and credential format.
- Submit the request for operator approval.
- 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
DEas a substitute forRS. - Register a real Provider certificate chain instead of
x5c: []. - Remove the
metaserialization 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
201with anullID. - 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.