Skip to content

Secure (Compact JWS / JWE)

JSON APIs for payloads ≤ 5 MB**


1 · Scope

The Secure tag covers synchronous, in-memory cryptographic operations that travel as Base64-encoded JSON:

Function RFC / Format Notes
Sign / Verify RFC 7515 – Compact JWS Post-quantum (ML-DSA, Falcon) and classical (RSA-PSS, ECDSA).
Encrypt / Decrypt RFC 7516 – Compact JWE Hybrid KEM+AEAD (ML-KEM-1024 + A256GCM, RSA-OAEP-256 + A256GCM, etc.).
Re-sign / Re-encrypt Seamless migration flows Move payloads from classical → PQC keys with no plaintext exposure.

Successful responses include a standard metadata envelope:

Field Purpose
jwsToken / jweToken / decryptedData Output of the requested operation.
keyRequested kid supplied by the caller.
actualKeyUsed Effective kid after rotation / alias resolution.
algorithmUsed Canonical algorithm (e.g. ML-KEM-768+A256GCM).
warnings[] Lifecycle hints (soft limits, nearing expiry, sunset dates).

Conditional fieldmigrationMode ← boolean
Included only by the /reencrypt and /resign endpoints (compact and streaming variants).
It is true when the server had to apply sourceKidOverride because the incoming JWE/JWS header had no kid; it is absent otherwise.

All endpoints require a Bearer JWT (Authorization: Bearer <token>).
Maximum decoded payload size is 5 MB — on overflow the API returns 413 Payload Too Large.


2 · Endpoints (tag Secure)

Verb Path Summary Request Schema Success
POST /api/crypto/encrypt Encrypt plaintext → Compact JWE EncryptRequest 200 OK
POST /api/crypto/decrypt Decrypt Compact JWE → plaintext DecryptJweRequest 200 OK
POST /api/crypto/sign Sign data → Compact JWS SignRequest 200 OK
POST /api/crypto/verify Verify Compact JWS VerifyJwsRequest 200 OK
POST /api/crypto/reencrypt Decrypt under oldKid & re-encrypt under newKid ReencryptJweRequest 200 OK
POST /api/crypto/resign Verify with oldKid & re-sign with newKid ResignJwsRequest 200 OK

3 · Core Schemas

Schema Direction Used by
EncryptRequest / EncryptJweResponse /encrypt
DecryptJweRequest / DecryptResponse /decrypt
SignRequest / SignJwsResponse /sign
VerifyJwsRequest / VerifySignatureResponse /verify
ReencryptJweRequest / ReencryptJweResponse /reencrypt
ResignJwsRequest / ResignJwsResponse /resign

See the OpenAPI spec (#/components/schemas/*) for full field lists.


4 · Encrypt – Quick Start

POST /api/crypto/encrypt
Content-Type: application/json
Authorization: Bearer <JWT>
{
  "kid" : "myPublicKid",
  "data": "SGVsbG8gQW5rYQ=="
}
200 OK

{
  "jweToken"      : "eyJraWQiOiJteVB1YmxpY0tpZCIsImFsZyI6Ik1MLUtFTS0xMDI0K0EyNTZHQ00ifQ..iv.ciphertext.tag",
  "keyRequested"  : "myPublicKid",
  "actualKeyUsed" : "myPublicKid_v2",
  "algorithmUsed" : "ML-KEM-1024+A256GCM",
  "warnings"      : []
}

5 - Decrypt -- Quick Start

POST /api/crypto/decrypt
Content-Type: application/json
Authorization: Bearer <JWT>
{
  "jweToken": "<compact-jwe-string>"
}

200 OK

{
  "decryptedData" : "SGVsbG8gQW5rYQ==",
  "keyRequested"  : "myPrivateKid",
  "actualKeyUsed" : "myPrivateKid",
  "algorithmUsed" : "ML-KEM-768",
  "warnings"      : []
}

6 - Sign -- Quick Start

POST /api/crypto/sign
Content-Type: application/json
Authorization: Bearer <JWT>
{
  "kid" : "mySigningKid",
  "data": "SGVsbG8gQW5rYQ=="
}
200 OK

{
  "jwsToken"      : "eyJraWQiOiJteVNpZ25pbmdLaWQiLCJhbGciOiJGQUxDT04tNTEyIn0.SGVsbG8gQW5rYQ.<sig>",
  "keyRequested"  : "mySigningKid",
  "actualKeyUsed" : "mySigningKid",
  "algorithmUsed" : "Falcon-512",
  "warnings"      : []
}

7 - Verify -- Quick Start

POST /api/crypto/verify
Content-Type: application/json
Authorization: Bearer <JWT>
{
  "jws": "eyJraWQiOiJteVNpZ25pbmdLaWQiLCJhbGciOiJGQUxDT04tNTEyIn0.SGVsbG8gQW5rYQ.<sig>"
}
200 OK

{
  "valid"         : true,
  "keyRequested"  : "myVerifyKid",
  "actualKeyUsed" : "myVerifyKid",
  "algorithmUsed" : "Falcon-512",
  "warnings"      : []
}

8 - Re-encrypt -- Quick Start

POST /api/crypto/reencrypt
Content-Type: application/json
Authorization: Bearer <JWT>
{
  "jweToken"         : "<legacy-rsa-jwe>",
  "newKid"           : "pqk-mlkem-768",
  "sourceKidOverride": "oldRsaKid"          // OPTIONAL – use only when the JWE header has no kid
}

Two possible 200 OK response

- Standard response (header already contained a kid)
{
  "jweToken"            : "<new-pq-jwe>",
  "oldKeyRequested"     : "oldRsaKid",
  "oldKeyUsed"          : "oldRsaKid_v2",
  "oldKeyAlgorithmUsed" : "RSA-2048",
  "newKeyRequested"     : "pqk-mlkem-768",
  "newKeyUsed"          : "pqk-mlkem-768",
  "newKeyAlgorithmUsed" : "ML-KEM-768",
  "warnings"            : []
}
- Response when sourceKidOverride was applied
{
  "jweToken"            : "<new-pq-jwe>",
  "oldKeyRequested"     : "oldRsaKid",      // came from sourceKidOverride
  "oldKeyUsed"          : "oldRsaKid_v2",
  "oldKeyAlgorithmUsed" : "RSA-2048",
  "newKeyRequested"     : "pqk-mlkem-768",
  "newKeyUsed"          : "pqk-mlkem-768",
  "newKeyAlgorithmUsed" : "ML-KEM-768",
  "migrationMode"       : true,             // indicates override
  "warnings"            : ["Old key sunset in 30 days"]
}

9 - Re-sign -- Quick Start

POST /api/crypto/resign
Content-Type: application/json
Authorization: Bearer <JWT>
{
  "jwsToken"         : "<rsa-ps256-token>",
  "newKid"           : "pqk-falcon-512",
  "sourceKidOverride": "oldRsaKid"          // OPTIONAL – only if Compact JWS header has no kid
}

Two possible 200 OK responses

- Standard response (header contained kid)
{
  "jwsToken"            : "<new-falcon-token>",
  "oldKeyRequested"     : "oldRsaKid",
  "oldKeyUsed"          : "oldRsaKid_v2",
  "oldKeyAlgorithmUsed" : "PS256",
  "newKeyRequested"     : "pqk-falcon-512",
  "newKeyUsed"          : "pqk-falcon-512",
  "newKeyAlgorithmUsed" : "Falcon-512",
  "warnings"            : []
}
- Response when sourceKidOverride was applied
{
  "jwsToken"            : "<new-falcon-token>",
  "oldKeyRequested"     : "oldRsaKid",      // came from sourceKidOverride
  "oldKeyUsed"          : "oldRsaKid_v2",
  "oldKeyAlgorithmUsed" : "PS256",
  "newKeyRequested"     : "pqk-falcon-512",
  "newKeyUsed"          : "pqk-falcon-512",
  "newKeyAlgorithmUsed" : "Falcon-512",
  "migrationMode"       : true,             // indicates override
  "warnings"            : []
}

10 - Compact JWE / JWS Anatomy

10.1 Compact JWE (5 parts)

BASE64URL(header).BASE64URL(encryptedKey).BASE64URL(iv).BASE64URL(ciphertext).BASE64URL(tag)
- header -- JSON with alg, enc, kid, ...

  • encryptedKey -- CEK wrapped by the recipient's public key (absent when alg=dir).

  • iv -- IV of the AEAD cipher.

  • ciphertext -- Encrypted payload.

  • tag -- Authentication tag.

10.2 Compact JWS (3 parts)

BASE64URL(header).BASE64URL(payload).BASE64URL(signature)
- header -- JSON with alg, kid, ...

  • payload -- Data (Base64URL).

  • signature -- Digital signature over header.payload.

Tip -- Clients can decode the first segment (header) locally to inspect kid and alg before calling the API.


11 - Error Handling (RFC 7807)

Code type URI Trigger
400 /errors/invalid-input Malformed JSON/Base64, missing field, incompatible algorithm.
401 /errors/unauthorized Missing or invalid credentials.
404 /errors/not-found kid unsuitable or absent.
409 /errors/conflict Key revoked, suspended, or lifecycle mismatch.
413 /errors/payload-too-large Payload > 5 MB (decoded).
422 /errors/unprocessable-entity Malformed Compact JWE/JWS.
500 /errors/internal Unexpected crypto-engine failure.

Problem documents include timestamp, detail, and instance, and honour Accept-Language: en | es.


12 - Best Practices

  1. Monitor warnings[] --- rotate keys before hard limits hit.

  2. Cache algorithmUsed to avoid extra discovery calls.

  3. Prefer ML-KEM-1024 for archival data ≥ 30 years.

  4. Switch to streaming endpoints for files approaching 5 MB.

  5. Schedule periodic re-encrypt/re-sign to maintain forward secrecy.


13 - Security

All Secure endpoints use the bearerAuth scheme defined in the OpenAPI:

  • Authorization: Bearer <JWT> --- obtain the token from your OIDC IdP.

Document version 2.1 -- generated from OpenAPI build 2025-05-31.\ © 2025 AnkaTech Co. All rights reserved.