---
title: "CSR Workflows"
description: "The X.509 Certificate Service creates PKCS#10 Certificate Signing Requests (CSRs) and issues certificates from them. A CSR is signed by the subject key, proving control of the private key, so CSR-based issuance gives…"
stack: "Enterprise Stack (commercial) — version 1.1.1"
stack_version: "1.1.1"
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-10-01
---
# CSR Workflows

The X.509 Certificate Service creates PKCS#10 Certificate Signing Requests (CSRs) and issues certificates from them. A CSR is signed by the subject key, proving control of the private key, so CSR-based issuance gives you a proof-of-possession workflow: the requester keeps the private key and only the CSR is submitted for signing.

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 is `test.enterprise-sandbox.waltid.dev` on the sandbox environment.
- `target`: The X.509 Certificate service path (`{organizationID}.{tenantID}.{x509ServiceID}`), for example `test.tenant1.x509-service-1`.

## Create a CSR

The CSR endpoint is stateless — nothing is persisted. Store the returned `csrPEM` for later use.

**Option: CURL**

Endpoint: `POST /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 '{
  "subjectKeyRef": "test.tenant1.kms1.leaf-key",
  "subjectDn": "CN=Example Leaf,O=Example Org,C=US",
  "subjectAlternativeNames": [
    { "type": "dnsName", "name": "leaf.example.com" }
  ]
}'
```

**Body Parameters**

- `subjectKeyRef`: _String_ - KMS key path for the subject key, e.g. `test.tenant1.kms1.leaf-key`. Supply this or `subjectKeyJwk`, not both.
- `subjectKeyJwk`: _Object_ - Subject key as a JWK (private material), used instead of `subjectKeyRef`.
- `subjectDn`: _String_ (required) - Subject distinguished name, e.g. `CN=Example Leaf,O=Example Org,C=US`.
- `subjectAlternativeNames`: _Array_ (optional) - SAN entries, each `{ "type": ..., "name": ... }` with `type` one of `dnsName`, `email`, `uri`, `ipAddress`.
- `signatureAlgorithm`: _String_ (optional) - Signature algorithm for the CSR. Defaults to an algorithm derived from the subject key.

**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 Fields**

- `csrPEM`: _String_ - The PKCS#10 CSR in PEM format. All parsed data is derived from this value.
- `csrData`: _Object_ - Convenience view of the CSR contents (`subjectName`, `subjectAlternativeNames`, `publicKeyJwk`). Deprecated — it may be removed in a future version; read the values from `csrPEM` instead.

**Response Codes**

- `200` - CSR created successfully.
- `400` - Invalid request (e.g. no subject key, both key inputs supplied).
- `401` - Invalid or missing authentication token.

**Note:**

For an ISO Document Signer CSR, supply the Document Signer's `subjectDn` with the ISO fields you need (`CN=`, `C=`, `O=`, `ST=`, `L=`). The Document Signer profile extensions are added when you later issue the certificate with `certificateProfile: "iso-document-signer"`, not at CSR creation.

## Issue a certificate from a CSR

Pass the CSR PEM as `csrPem` on `POST /v1/{target}/x509-service-api/certificates`. The subject DN and subject alternative names come from the CSR and its signature is verified before the certificate is issued. CSR-based issuance always needs an issuer — it cannot be self-signed.

**Option: CURL**

Endpoint: `POST /v1/{target}/x509-service-api/certificates` | [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/certificates' \
  -H 'accept: application/json' \
  -H 'Authorization: Bearer {yourToken}' \
  -H 'Content-Type: application/json' \
  -d '{
  "issuerCertificateRef": "test.tenant1.x509-store-1.example-root-ca",
  "csrPem": "-----BEGIN CERTIFICATE REQUEST-----
MIIB...
-----END CERTIFICATE REQUEST-----",
  "validFrom": "2026-09-01T00:00:00Z",
  "validTo": "2027-09-01T00:00:00Z",
  "keyUsage": ["digitalSignature"]
}'
```

**Body Parameters**

- `csrPem`: _String_ (required) - The CSR in PEM format (begins with `-----BEGIN CERTIFICATE REQUEST-----`). Cannot be combined with `subjectDn` or `selfSigned`.
- `issuerCertificateRef` / `issuerCertificatePem`: _String_ (required) - The issuing certificate. `issuerKeyRef` / `issuerKeyJwk` is also accepted to specify the signing key directly.
- `subjectKeyRef`: _String_ (optional) - When set, the service checks the referenced key matches the CSR public key and records it in `subjectKeyRef` metadata.
- `validFrom` / `validTo`: _String_ (required) - Validity window.
- Other fields are the same as [certificate issuance](https://docs.walt.id/enterprise-stack/services/x509-service/issue-certificates.md#request-fields). To apply a [certificate profile](https://docs.walt.id/enterprise-stack/services/x509-service/issue-certificates.md#certificate-profiles) — e.g. `iso-document-signer` against an IACA, or `etsi-wrpac` / `etsi-wrprc` against a national provider — add `certificateProfile` and the profile's other required fields (e.g. `certificatePolicyOids`) alongside `csrPem`.

**Response Codes**

- `200` / `201` - Certificate issued (persisted when a store is attached).
- `400` - CSR signature validation failed, subject key mismatch, or issuer not resolvable.
- `401` - Invalid or missing authentication token.

## End-to-end CSR workflow

```bash
# Step 1: Create a CSR from a key hosted in the linked KMS
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 '{
  "subjectKeyRef": "test.tenant1.kms1.leaf-key",
  "subjectDn": "CN=Example Leaf,O=Example Org,C=US"
}')

CSR_PEM=$(echo "$CSR_RESPONSE" | jq -r '.csrPEM')

# Step 2: Issue a CA-signed certificate from the CSR
curl -X 'POST' \
  'https://{orgID}.enterprise-sandbox.waltid.dev/v1/{target}/x509-service-api/certificates' \
  -H 'accept: application/json' \
  -H 'Authorization: Bearer {yourToken}' \
  -H 'Content-Type: application/json' \
  -d "{
  \"issuerCertificateRef\": \"test.tenant1.x509-store-1.example-root-ca\",
  \"csrPem\": $(echo "$CSR_PEM" | jq -Rs .),
  \"validFrom\": \"2026-09-01T00:00:00Z\",
  \"validTo\": \"2027-09-01T00:00:00Z\",
  \"keyUsage\": [\"digitalSignature\"]
}"
```

## Use cases

### External CA integration

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

### Delegated key management

Let an external party generate its own key pair and submit a CSR. The service issues a certificate for the CSR's public key while the private key never leaves the requester.

### Compliance workflows

Where a compliance framework requires proof-of-possession during issuance, CSR-based issuance satisfies it: the requester signs the CSR with the private key and the service verifies that signature before issuing.
