---
title: "CSR Workflows"
description: "The X.509 Certificate Service supports PKCS#10 Certificate Signing Request (CSR) creation and CSR-based certificate issuance. This enables proof-of-possession workflows where the certificate requester proves control of…"
stack: "Enterprise Stack (commercial) — version 0.21.0"
stack_version: "0.21.0"
stack_comparison: https://docs.walt.id/community-vs-enterprise.md
canonical_url: https://docs.walt.id/enterprise-stack/services/x509-service/csr-workflows
generated: 2026-07-08
---
# CSR Workflows

The X.509 Certificate Service supports PKCS#10 Certificate Signing Request (CSR) creation and CSR-based certificate issuance. This enables proof-of-possession workflows where the certificate requester proves control of the private key.

Service reference: [Swagger API Reference](https://enterprise.sandbox.walt.id/swagger/index.html#/Service%20%7C%20X.509%20Certificate%20Service)

## Shared Path Parameters

- `orgID`: When performing operations within an organization, use the organization's Base URL or another valid host alias. For example, if your organization is named `test`, your default Base URL will be `test.enterprise-sandbox.waltid.dev` when using the sandbox environment.
- `target`: The full X.509 Certificate service path (`{organizationID}.{tenantID}.{x509ServiceID}`), for example `test.tenant1.x509-service-1`.

## Create a CSR

Create a PKCS#10 Certificate Signing Request. The CSR is signed by the subject key, proving possession of the private key. The returned CSR PEM can be submitted to an external CA or used as a subject public key source when creating certificates through this service.

**Option: Generic CSR**

**Option: CURL**

Endpoint: `/v1/{target}/x509-service-api/csrs` | [API Reference](https://enterprise.sandbox.walt.id/swagger/index.html#/Service%20%7C%20X.509%20Certificate%20Service)

**Example Request**

```bash
curl -X 'POST' \
  'https://{orgID}.enterprise-sandbox.waltid.dev/v1/{target}/x509-service-api/csrs' \
  -H 'accept: application/json' \
  -H 'Authorization: Bearer {yourToken}' \
  -H 'Content-Type: application/json' \
  -d '{
  "type": "generic",
  "subjectKeyDescriptor": {
    "type": "kms-hosted-key-descriptor",
    "keyIdPath": "test.tenant1.kms1.leaf-secp256r1"
  },
  "subjectName": {
    "commonName": "Example Leaf",
    "country": "US",
    "organizationName": "Example Org"
  },
  "subjectAlternativeNames": {
    "dnsNames": ["leaf.example.com"]
  }
}'
```

**Body Parameters**

- `type`: _String_ - Set to `"generic"` for generic CSR.
- `subjectKeyDescriptor`: _Object_ - Key descriptor for the subject key.
  - `type`: _String_ - Descriptor type. Use `"kms-hosted-key-descriptor"` for keys stored in a KMS service or `"jwk-encoded-key-descriptor"` for directly provided JWK keys.
  - `keyIdPath`: _String_ - (For KMS-hosted keys) The full key path in format `{organizationID}.{tenantID}.{kmsServiceID}.{keyID}`, e.g. `test.tenant1.kms1.leaf-secp256r1`.
- `subjectName`: _Object_ - Distinguished name fields (`commonName`, `country`, `organizationName`, `stateOrProvinceName`, `localityName`, `organizationalUnitName`).
- `subjectAlternativeNames`: _Object_ (optional) - SAN values (`dnsNames`, `uris`, `emails`, `ipAddresses`).

---

**Example Response**

```json
{
  "csrPEM": "-----BEGIN CERTIFICATE REQUEST-----
MIIB...
-----END CERTIFICATE REQUEST-----",
  "csrData": {
    "subjectName": {
      "commonName": "Example Leaf",
      "country": "US",
      "organizationName": "Example Org"
    },
    "subjectAlternativeNames": {
      "dnsNames": ["leaf.example.com"]
    },
    "publicKeyJwk": {
      "kty": "EC",
      "crv": "P-256",
      "x": "q0xi21uudhkC1QMykfYryN9bcDx480iJLSaRI05CWgY",
      "y": "NhD-09xqrUgE2-qSt8g5imePgKPPNVpYoHmsTL2f4io"
    }
  }
}
```

**Response Codes**

- `200` - CSR created successfully.

**Option: ISO Document Signer CSR**

**Option: CURL**

Endpoint: `/v1/{target}/x509-service-api/csrs` | [API Reference](https://enterprise.sandbox.walt.id/swagger/index.html#/Service%20%7C%20X.509%20Certificate%20Service)

**Example Request**

```bash
curl -X 'POST' \
  'https://{orgID}.enterprise-sandbox.waltid.dev/v1/{target}/x509-service-api/csrs' \
  -H 'accept: application/json' \
  -H 'Authorization: Bearer {yourToken}' \
  -H 'Content-Type: application/json' \
  -d '{
  "type": "iso-document-signer",
  "subjectKeyDescriptor": {
    "type": "kms-hosted-key-descriptor",
    "keyIdPath": "test.tenant1.kms1.ds-secp256r1"
  },
  "certificateData": {
    "country": "US",
    "commonName": "Example DS",
    "crlDistributionPointUri": "https://crl-example.com"
  }
}'
```

**Body Parameters**

- `type`: _String_ - Set to `"iso-document-signer"` for ISO Document Signer CSR.
- `subjectKeyDescriptor`: _Object_ - Key descriptor for the Document Signer key.
  - `type`: _String_ - Descriptor type. Use `"kms-hosted-key-descriptor"` for keys stored in a KMS service or `"jwk-encoded-key-descriptor"` for directly provided JWK keys.
  - `keyIdPath`: _String_ - (For KMS-hosted keys) The full key path in format `{organizationID}.{tenantID}.{kmsServiceID}.{keyID}`, e.g. `test.tenant1.kms1.ds-secp256r1`.
- `certificateData`: _Object_ - Document Signer profile data (`country`, `commonName`, `crlDistributionPointUri`, and optional `stateOrProvinceName`, `organizationName`, `localityName`).

---

**Example Response**

```json
{
  "csrPEM": "-----BEGIN CERTIFICATE REQUEST-----
MIHcMIGEAgEAMCIxCzAJBgNVBAYTAlVTMRMwEQYDVQQDDApFeGFtcGxlIERTMFkw
EwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEjVOxFXwcpNWbLsvSCzVW9aU3sdgvr7hu
eF/tR3nGYPaParfLDME3ehFy9yDGq5sntm8BaOvt11uoYkaCcadHZ6AAMAoGCCqG
SM49BAMCA0cAMEQCIBIXGH273+3dv0nvyftf7qToNCmCK/DB4qSYv93HvSAAAiBK
r5aymSNZaILhKCQxOa1xirT3RmZ3Rw/w+OBTfEDk4A==
-----END CERTIFICATE REQUEST-----",
  "csrData": {
    "subjectName": {
      "commonName": "Example DS",
      "country": "US"
    },
    "publicKeyJwk": {
      "kty": "EC",
      "crv": "P-256",
      "x": "jVOxFXwcpNWbLsvSCzVW9aU3sdgvr7hueF_tR3nGYPY",
      "y": "j2q3ywzBN3oRcvcgxqubJ7ZvAWjr7ddbqGJGgnGnR2c"
    }
  }
}
```

**Response Codes**

- `200` - CSR created successfully.

**Note:**

The CSR endpoint is stateless. The service does not persist CSR state. Store the returned `csrPEM` for later use when creating certificates.

## Issue a certificate from a CSR

Both generic certificates and Document Signer certificates can be issued using a CSR as the subject public key source. This workflow verifies proof-of-possession before issuing the certificate.

### Generic certificate from CSR

**Option: CURL**

Endpoint: `/v1/{target}/x509-service-api/certificate` | [API Reference](https://enterprise.sandbox.walt.id/swagger/index.html#/Service%20%7C%20X.509%20Certificate%20Service)

```bash
curl -X 'POST' \
  'https://{orgID}.enterprise-sandbox.waltid.dev/v1/{target}/x509-service-api/certificate' \
  -H 'accept: application/json' \
  -H 'Authorization: Bearer {yourToken}' \
  -H 'Content-Type: application/json' \
  -d '{
  "storedCertificateId": "generic-leaf-from-csr",
  "certificateData": {
    "subjectName": {
      "commonName": "Example Leaf From CSR",
      "country": "US"
    },
    "keyUsage": ["DigitalSignature"]
  },
  "subjectPublicKeySource": {
    "type": "csr",
    "csrPEM": "-----BEGIN CERTIFICATE REQUEST-----
MIIB...
-----END CERTIFICATE REQUEST-----"
  },
  "issuer": {
    "type": "ca-signed",
    "issuerKeyDescriptor": {
      "type": "kms-hosted-key-descriptor",
      "keyIdPath": "test.tenant1.kms1.iaca-secp256r1"
    }
  }
}'
```

**Body Parameters**

- `subjectPublicKeySource`: _Object_ - Source of the subject's public key.
  - `type`: _String_ - Set to `"csr"` for CSR-based issuance.
  - `csrPEM`: _String_ - The CSR in PEM format (begins with `-----BEGIN CERTIFICATE REQUEST-----`).
- `issuer`: _Object_ - Issuer configuration. Must be `ca-signed` for CSR-based issuance. Self-signed certificates cannot use CSR input.
  - `type`: _String_ - Set to `"ca-signed"`.
  - `issuerKeyDescriptor`: _Object_ - Key descriptor for the CA signing key.
    - `type`: _String_ - Descriptor type. Use `"kms-hosted-key-descriptor"` for keys stored in a KMS service or `"jwk-encoded-key-descriptor"` for directly provided JWK keys.
    - `keyIdPath`: _String_ - (For KMS-hosted keys) The full key path in format `{organizationID}.{tenantID}.{kmsServiceID}.{keyID}`, e.g. `test.tenant1.kms1.iaca-secp256r1`.
- Other parameters are the same as [generic certificate creation](https://docs.walt.id/enterprise-stack/services/x509-service/issue-certificates.md#create-a-generic-certificate).

**Response Codes**

- `200` - Certificate issued successfully.

### Document Signer certificate from CSR

**Option: CURL**

Endpoint: `/v1/{target}/x509-service-api/iso/document-signers` | [API Reference](https://enterprise.sandbox.walt.id/swagger/index.html#/Service%20%7C%20X.509%20Certificate%20Service)

```bash
curl -X 'POST' \
  'https://{orgID}.enterprise-sandbox.waltid.dev/v1/{target}/x509-service-api/iso/document-signers' \
  -H 'accept: application/json' \
  -H 'Authorization: Bearer {yourToken}' \
  -H 'Content-Type: application/json' \
  -d '{
  "storedCertificateId": "ds-from-csr-2026-01",
  "iacaSigner": {
    "type": "iaca-cert-data-descriptor",
    "iacaKeyDesc": {
      "type": "kms-hosted-key-descriptor",
      "keyIdPath": "test.tenant1.kms1.iaca-secp256r1"
    },
    "certificateData": {
      "country": "US",
      "commonName": "Example IACA",
      "notBefore": "2025-05-28T12:23:01Z",
      "notAfter": "2040-05-24T12:23:01Z",
      "issuerAlternativeNameConf": {
        "uri": "https://iaca.example.com"
      }
    }
  },
  "certificateData": {
    "country": "US",
    "commonName": "Example DS",
    "crlDistributionPointUri": "https://crl-example.com"
  },
  "dsPublicKeySource": {
    "type": "csr",
    "csrPEM": "-----BEGIN CERTIFICATE REQUEST-----
MIIB...
-----END CERTIFICATE REQUEST-----"
  }
}'
```

**Body Parameters**

- `dsPublicKeySource`: Set `type` to `csr` and provide the `csrPEM` string. This replaces the legacy `dsKeyDescriptor` field.
- Other parameters are the same as [Document Signer certificate creation](https://docs.walt.id/enterprise-stack/services/x509-service/issue-certificates.md#create-a-document-signer-certificate).

**Note:**

  The `dsKeyDescriptor` field is still supported for backward compatibility, but `dsPublicKeySource` is preferred for new integrations. The two fields are mutually exclusive.

**Response Codes**

- `200` - Document Signer certificate issued successfully.

## End-to-end CSR workflow example

This example demonstrates a complete CSR-based issuance workflow:

1. **Create a CSR** using a key hosted in the KMS
2. **Submit the CSR** to create a CA-signed certificate

```bash
# Step 1: Create a CSR
CSR_RESPONSE=$(curl -s -X 'POST' \
  'https://{orgID}.enterprise-sandbox.waltid.dev/v1/{target}/x509-service-api/csrs' \
  -H 'accept: application/json' \
  -H 'Authorization: Bearer {yourToken}' \
  -H 'Content-Type: application/json' \
  -d '{
  "type": "generic",
  "subjectKeyDescriptor": {
    "type": "kms-hosted-key-descriptor",
    "keyIdPath": "test.tenant1.kms1.leaf-secp256r1"
  },
  "subjectName": {
    "commonName": "Example Leaf",
    "country": "US"
  }
}')

# Extract the CSR PEM (requires jq)
CSR_PEM=$(echo "$CSR_RESPONSE" | jq -r '.csrPEM')

# Step 2: Create a certificate from the CSR
curl -X 'POST' \
  'https://{orgID}.enterprise-sandbox.waltid.dev/v1/{target}/x509-service-api/certificate' \
  -H 'accept: application/json' \
  -H 'Authorization: Bearer {yourToken}' \
  -H 'Content-Type: application/json' \
  -d "{
  \"certificateData\": {
    \"subjectName\": {
      \"commonName\": \"Example Leaf\",
      \"country\": \"US\"
    },
    \"keyUsage\": [\"DigitalSignature\"]
  },
  \"subjectPublicKeySource\": {
    \"type\": \"csr\",
    \"csrPEM\": $(echo "$CSR_PEM" | jq -Rs .)
  },
  \"issuer\": {
    \"type\": \"ca-signed\",
    \"issuerKeyDescriptor\": {
      \"type\": \"kms-hosted-key-descriptor\",
      \"keyIdPath\": \"test.tenant1.kms1.ca-secp256r1\"
    }
  }
}"
```

## Use cases

### External CA integration

Generate CSRs through the X.509 Certificate Service and submit them to external Certificate Authorities. The CSR proves possession of the private key stored in your KMS.

### Delegated key management

Allow external parties to generate their own key pairs and submit CSRs. The X.509 Certificate Service can then issue certificates using the CSR's public key while the private key remains with the requester.

### Compliance workflows

Some compliance frameworks require proof-of-possession during certificate issuance. CSR-based workflows satisfy this requirement by having the certificate requester sign the CSR with their private key.
