A REST API for generating cryptographic keys, signing JSON documents, and verifying signatures using JSON Signature Scheme (JSS) as defined in ITU-T X.590 (10/2023).
Requires .NET 8.0 SDK or later.
dotnet run --project src/CoderPatros.Jss.ApiThe API starts on http://localhost:5000 by default. Browse to http://localhost:5000/swagger for the interactive Swagger UI.
Build and run using the provided script:
./src/CoderPatros.Jss.Api/docker-run.shThis builds the Docker image and runs the API on http://localhost:8080. Browse to http://localhost:8080/swagger for the interactive Swagger UI.
Or build and run manually from the repository root:
docker build -f src/CoderPatros.Jss.Api/Dockerfile -t coderpatros-jss-api .
docker run --rm -p 8080:8080 coderpatros-jss-apiGenerate a cryptographic key pair.
Request:
{
"algorithm": "ES256"
}Response:
{
"privateKeyPem": "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----",
"publicKeyPem": "-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----",
"publicKeyPemBody": "MFkwEwYH..."
}Sign a JSON document. The public key is always embedded in the signature per ITU-T X.590 clause 6.2.1.
Request:
{
"document": { "message": "hello" },
"algorithm": "ES256",
"hashAlgorithm": "sha-256",
"privateKeyPem": "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----"
}| Field | Required | Description |
|---|---|---|
document |
Yes | The JSON object to sign |
algorithm |
Yes | Signature algorithm identifier (see supported algorithms) |
hashAlgorithm |
Yes | Hash algorithm identifier (sha-256, sha-384, sha-512) |
privateKeyPem |
Yes | Private key in PEM format |
Response:
{
"document": {
"message": "hello",
"signatures": [{ "algorithm": "ES256", "hash_algorithm": "sha-256", "public_key": "...", "value": "..." }]
}
}Verify a signed JSON document.
Request:
{
"document": { "message": "hello", "signatures": [{ "algorithm": "ES256", "hash_algorithm": "sha-256", "value": "..." }] },
"publicKeyPem": "-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----",
"allowEmbeddedKey": false,
"acceptedAlgorithms": ["ES256", "ES384"]
}| Field | Required | Description |
|---|---|---|
document |
Yes | The signed JSON object to verify |
publicKeyPem |
No | Public key in PEM format. Optional if using an embedded key |
algorithm |
No | Algorithm hint for key parsing (auto-detected from document if not provided) |
allowEmbeddedKey |
No | Allow verification using the public key embedded in the signature (default: false) |
acceptedAlgorithms |
No | Whitelist of accepted algorithm identifiers |
Response:
{
"isValid": true,
"error": null
}Verify all signatures in a document.
Request and response follow the same format as POST /api/verify.
Countersign a specific signature in a signed document.
Request:
{
"document": { "message": "hello", "signatures": [{ "algorithm": "ES256", "hash_algorithm": "sha-256", "value": "..." }] },
"algorithm": "ES256",
"hashAlgorithm": "sha-256",
"privateKeyPem": "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----",
"signatureIndex": 0,
"embedPublicKey": true
}| Field | Required | Description |
|---|---|---|
document |
Yes | The signed JSON object |
algorithm |
Yes | Signature algorithm identifier |
hashAlgorithm |
Yes | Hash algorithm identifier |
privateKeyPem |
Yes | Private key in PEM format |
signatureIndex |
No | Index of the signature to countersign (default: 0) |
embedPublicKey |
No | Embed the public key in the countersignature (default: false) |
Response:
{
"document": { "message": "hello", "signatures": [{ "algorithm": "ES256", "hash_algorithm": "sha-256", "value": "...", "countersignature": { ... } }] }
}When a request fails, the API returns a 400 Bad Request with an error message:
{
"error": "Description of what went wrong."
}| Family | Algorithms |
|---|---|
| ECDSA | ES256, ES384, ES512 |
| RSA PKCS#1 v1.5 | RS256, RS384, RS512 |
| RSA-PSS | PS256, PS384, PS512 |
| EdDSA | Ed25519, Ed448 |
Hash algorithms: sha-256, sha-384, sha-512
# Generate a key pair
curl -s -X POST http://localhost:5000/api/keys/generate \
-H "Content-Type: application/json" \
-d '{"algorithm":"ES256"}' > keys.json
# Extract keys
PRIVATE_KEY_PEM=$(jq -r '.privateKeyPem' keys.json)
# Sign a document
SIGNED=$(curl -s -X POST http://localhost:5000/api/sign \
-H "Content-Type: application/json" \
-d "{\"document\":{\"message\":\"hello\"},\"algorithm\":\"ES256\",\"hashAlgorithm\":\"sha-256\",\"privateKeyPem\":$(jq '.privateKeyPem' keys.json)}")
# Verify the signature using the embedded public key
SIGNED_DOC=$(echo "$SIGNED" | jq '.document')
curl -s -X POST http://localhost:5000/api/verify \
-H "Content-Type: application/json" \
-d "{\"document\":$SIGNED_DOC,\"allowEmbeddedKey\":true}"
# Output: {"isValid":true,"error":null}Apache-2.0