iGrant.io OID4VC API - Key Management group
When to use
Use this skill when you:
- choose or configure the secure vault that holds the organisation signing keys;
- create, list or delete a signing key;
- get a CSR, send it to a Certificate Authority, and upload the signed
chain so that the key carries an
x5cvalue (needed for thex509_san_dnsandx509_hashclient ID schemes and for ISO 18013-7 Annex C); - attach a QTSP signing credential for remote qualified electronic signatures.
Base URL for demo: https://demo-api.igrant.io.
Auth header: Authorization: ApiKey <key> (note the trailing space in the
prefix). A bearer access token also works.
Endpoint reference
| Method | Path | Purpose | Docs |
|---|---|---|---|
| GET | /v2/config/digital-wallet/openid/key-managements |
List the vault types the platform supports | config-list-digital-wallet-open-id-list-secure-vaults |
| POST | /v2/config/digital-wallet/openid/key-management |
Configure the secure vaults of the organisation | config-digital-wallet-open-id-configure-secure-vault |
| GET | /v2/config/digital-wallet/openid/key-management |
Read the vault configuration of the organisation | config-digital-wallet-open-id-read-secure-vault |
| PUT | /v2/config/digital-wallet/openid/key-management |
Update the vault configuration | config-digital-wallet-open-id-update-secure-vault |
| GET | /v2/config/digital-wallet/openid/key-management/keys |
List all keys of all vaults, as JWKs with their DIDs | config-digital-wallet-open-id-list-keys |
| POST | /v2/config/digital-wallet/openid/key-management/keys |
Create an ECDSA P-256 key in a vault | config-digital-wallet-open-id-create-key |
| DELETE | /v2/config/digital-wallet/openid/key-management/keys/{keyId} |
Delete a key (needs a confirmation body) | config-digital-wallet-open-id-delete-key |
| POST | /v2/config/digital-wallet/openid/key-management/keys/{keyId}/csr |
Generate a Certificate Signing Request in PEM | config-digital-wallet-open-id-generate-csr |
| POST | /v2/config/digital-wallet/openid/key-management/keys/{keyId}/certificate-chain |
Upload the signed X.509 chain and link it to the key | config-digital-wallet-open-id-upload-certificate-chain |
| GET | /v2/config/digital-wallet/openid/key-management/qtsp/credentials |
List the QTSP signing credentials available | config-digital-wallet-open-id-list-qtsp-credential |
| GET | /v2/config/digital-wallet/openid/key-management/qtsp/{credentialId} |
Read the details of 1 QTSP signing credential | config-digital-wallet-open-id-read-qtsp-credential |
| POST | /v2/config/digital-wallet/openid/key-management/qtsp |
Select the QTSP signing credential to use | config-digital-wallet-open-id-configure-qtsp-credential |
Key fields
The 4 vault IDs
| ID | Configuration field | Display name |
|---|---|---|
| 1 | igrantioVault |
iGrant.io Secure Vault |
| 2 | hashicorpVault |
Hashicorp Secure Vault |
| 3 | qtsp |
Qualified Trust Service Provider |
| 4 | dbBackedVault |
DB-Backed Secure Vault |
GET …/key-managements (plural, no sandbox header) lists these 4 types. It is
the same for every organisation: it tells you which vaults the platform
supports, not which vaults the organisation uses. Read the organisation
configuration with GET …/key-management (singular). The organisation must
have a deployed OpenID digital wallet. This operation answers with 201,
not 200.
Configure and update the vaults
POST and PUT …/key-management take the same body. Required top-level
objects: hashicorpVault, igrantioVault, qtsp. dbBackedVault is
optional. Each object has a required enabled boolean.
{
"hashicorpVault": { "enabled": false },
"igrantioVault": { "enabled": true },
"qtsp": { "enabled": false },
"dbBackedVault": { "enabled": false }
}
- The iGrant.io vault must stay enabled. The request fails if you send
igrantioVault.enabled: false. - With
hashicorpVault.enabled: trueyou must also givevaultUsername,vaultPassword,vaultAddressandvaultNamespace. - With
qtsp.enabled: trueyou must also givecscUrl,clientId,clientSecretanduserID.cscApiVersionisv1(CSC 1.0.4.0) orv2(CSC 2.2.0.0); the service usesv1when you do not send it. - Send the full configuration on every call. The service forwards only the
enabledflag of a vault that hasenabled: false, so it erases the stored credentials of that vault. To keep the credentials of a vault, keep the vault enabled. - Both operations answer with
201and{ "secureVault": [<ids>] }.
GET …/key-management answers with 201, not 200. It gives
hashicorpVault, igrantioVault, qtsp and dbBackedVault, and it omits a
field that has no value. The qtsp object also carries credentialId, the
QTSP signing credential in use.
The read response holds the stored vault credentials in clear text,
including hashicorpVault.vaultPassword and qtsp.clientSecret. Protect the
response as you protect the credentials. The QTSP user PIN is the only secret
that the service never sends back.
List keys - the JWK members
GET …/key-management/keys has no query parameters and no pagination. It
returns every key of every vault, grouped by vault:
keyManagementServices[]
id 1 | 2 | 3 | 4
name "igrantioVault" | "hashicorpVault" | "qtsp" | "dbBackedVault"
keys[]
isDefault boolean - true when the wallet signs with this key by default
jwk the public key
dids[] the decentralised identifiers of the key
JWK members. Only kty is always present:
| Member | Meaning |
|---|---|
kty |
Key type. Always sent. The vault creates elliptic curve keys, so the value is EC. |
crv |
Curve. Usually P-256. An imported key can also use secp256k1. |
x, y |
Coordinates of the elliptic curve point, base64url. |
kid |
Key identifier. |
alg |
Signature algorithm. The vault sets ES256 for a P-256 key. |
x5c |
Array of base64 encoded DER certificates - the uploaded chain. |
x5t |
SHA-1 thumbprint of the leaf certificate. Present only when a chain is linked to the key. |
x5t#S256 |
SHA-256 thumbprint of the leaf certificate. Note the # in the member name - quote it in code. |
These responses never include the private member d. This operation
returns public key material only. The private part never leaves the vault
through this API.
Create and delete a key
Create takes an optional vaultType (1, 2, 3 or 4) and nothing else: the vault
sets the key type, the curve and the algorithm, so there is no parameter for
them. Enable the vault before you create a key in it. The answer is
201 with keyId and a jwk whose kid is the same value as keyId.
Delete needs a request body:
{ "confirm": "DELETE" }
confirm has one allowed value, DELETE. The service refuses the request when
the body is missing. Success is 204 with an empty body.
CSR and certificate chain (X.509)
POST …/keys/{keyId}/csr body: commonName is required; organization,
country (2 letter code), sanDns (array) and sanUri (array) are optional.
The answer is { "csr": "-----BEGIN CERTIFICATE REQUEST-----…" } in PEM.
Send the CSR to a Certificate Authority, then upload the signed chain with
POST …/keys/{keyId}/certificate-chain. That request is
multipart/form-data with the file field certificate_file. The file
must be UTF-8 text in PEM format, with the leaf certificate first, then the
intermediate certificates, then the root certificate.
The service refuses the file when it holds a private key, when the leaf certificate does not use the P-256 curve, when a certificate is expired or not yet valid, or when a chain signature is not correct.
The answer holds key_id, certificates_count, x5t and x5t_s256 (snake
case here; the same thumbprints appear as x5t and x5t#S256 in the list-keys
JWK). After the upload the wallet adds the chain as the x5c value of the key.
QTSP signing credentials
Configure and enable the QTSP vault before you call any QTSP operation.
GET …/qtsp/credentialsanswers with{ "credentials": ["<id>", …] }, the IDs available to the organisation. The service reads them from the QTSP over the Cloud Signature Consortium (CSC) API.GET …/qtsp/{credentialId}answers with acredentialInfoobject that holdscert(withcertificates,issuerDN,subjectDN,serialNumber,status,validFrom,validTo),key(algo,curve,len,status),PIN,OTP,authMode,descriptionandmultisign. The QTSP controls the members ofcredentialInfo, so they can change between providers. You cannot read a credential whose ID is the literal stringcredentials; that path goes to the list operation.POST …/qtspselects the credential. Body:credentialIdanduserPin, both required. The answer is201with an empty body. The service storesuserPinand never sends it back. To see the selected credential ID, read the secure vault and look atqtsp.credentialId.
Sandbox call style
Every operation in this group takes the optional X-SandboxOrgId header,
except GET /v2/config/digital-wallet/openid/key-managements (the platform
vault-type list), which is the same for every organisation. With that header
the service runs the operation against the wallet of the named sandbox
organisation and not against the main wallet of the organisation.
The service reads X-SandboxOrgId only when you authenticate with a bearer
access token. With API-key auth the service takes the sandbox organisation
from the key and ignores the header. To run an API-key call in a sandbox
organisation, bind the key with
PUT /v2/config/admin/apikey/{apiKeyId}/sandbox-org instead.
X-SubwalletId is the deprecated name of the header. The service still accepts
it, but X-SandboxOrgId wins if you send both.
See igrantio-api-sandboxes for creating and deploying a sandbox organisation.
Documentation is the source of truth
If this skill and the linked documentation disagree, the documentation wins. Fetch the linked page, or the raw specification at https://docs.igrant.io/openapispecifications/oid4vc.yaml, to check for updates before you build. Report the drift so the skill can be corrected.
Cross-references
igrantio-ows-overview- architecture and glossary.igrantio-api-trust-anchor- the trust lists that validate the issuers and verifiers your keys meet in a flow.igrantio-dcapi-ios- ISO 18013-7 Annex C, which needs thex509trust anchor and so needs an uploaded certificate chain.igrantio-api-sandboxes- sandbox organisations and the API-key binding.