Common signing patterns
The Due API uses two distinct signing patterns for different operations:
Pattern 1: Direct JSON Signing (Credential Creation Only)
Used only when creating credentials. You construct and sign a JSON object directly.
Flow:
1. API returns: challenge + clientDataHash
2. You create: JSON object with {clientDataHash, publicKey}
3. You sign: SHA256 hash of the JSON
4. Signature format: Hex-encoded
Example: See Create Credential guide
Pattern 2: Challenge-Response Flow (Everything Else)
Used for all other secured operations: vault creation, transaction signing, credential approval/deactivation, and any future secured endpoints.
Universal Request Structure
All Pattern 2 operations follow the same request/response structure:
Step 1: Initial Request
Send your operation payload:
{
"payload": {
// Your operation-specific data
// Can be empty object {} for some operations like vault creation
}
}Examples of payloads:
- Vault creation:
{}(empty payload) - Transaction signing:
{"keyId": "key_xxx", "hash": "0xabc..."} - Credential approval:
{"credentialId": "passkey_xxx"} - Credential deactivation:
{"credentialId": "passkey_xxx"}
Step 2: Challenge Response (403)
The API always returns a 403 error with a challenge:
{
"success": false,
"message": "Please sign the following challenge to proceed",
"httpCode": 403,
"code": "ACTION_SIGNATURE_REQUIRED",
"data": {
"factors": {
"Key": {
"credId": "",
"clientData": "eyJ0eXBlIjoia2V5LmdldCIsImNoYWxsZW5nZS...", // Base64 encoded challenge
"signature": null
}
},
"challengeIdentifier": "chid1DLr5F2ij7oyYLrGy6ekLnouxbE5SiiaN"
}
}Key fields:
clientData: Base64-encoded challenge data to signchallengeIdentifier: Unique ID for this challenge (valid for a limited time)
Step 3: Sign the Challenge
Decode and sign the clientData:
# Decode base64 → Sign with SHA256 → Encode to base64 URL-safe format
echo -n "<clientData_from_response>" | base64 -d | openssl dgst -sha256 -sign private.pem | base64 -w 0 | tr '+/' '-_' | tr -d '='Important: The signature must be in base64 URL-safe format (not hex like Pattern 1).
Step 4: Retry with Signature
Send the same request with both payload and signature:
{
"payload": {
// Same payload as Step 1
},
"signature": {
"challengeIdentifier": "<challengeIdentifier_from_step2>",
"firstFactor": {
"kind": "Key",
"credentialAssertion": {
"credId": "<your_credential_id>",
"clientData": "<original_clientData_from_step2>",
"signature": "<your_base64_url_safe_signature>"
}
}
}
}Response: Success with operation-specific result.
Complete Example: Vault Creation
Request 1 (Initial):
curl -X POST 'https://api.due.network/v1/vaults' \
-H 'Authorization: Bearer <token>' \
-H 'Content-Type: application/json' \
-d '{}' # Empty payload for vault creationResponse 1 (Challenge):
{
"success": false,
"httpCode": 403,
"code": "ACTION_SIGNATURE_REQUIRED",
"data": {
"factors": {
"Key": {
"clientData": "eyJ0eXBlIjoia2V5LmdldCIsImNoYWxsZW5nZS..."
}
},
"challengeIdentifier": "chid1DLZSWZlpvQSGTmMrwhUZTpCIFOwaneRi"
}
}Sign:
echo -n "eyJ0eXBlIjoia2V5LmdldCIsImNoYWxsZW5nZS..." | base64 -d | openssl dgst -sha256 -sign private.pem | base64 -w 0 | tr '+/' '-_' | tr -d '='Request 2 (With Signature):
curl -X POST 'https://api.due.network/v1/vaults' \
-H 'Authorization: Bearer <token>' \
-H 'Content-Type: application/json' \
-d '{
"signature": {
"challengeIdentifier": "chid1DLZSWZlpvQSGTmMrwhUZTpCIFOwaneRi",
"firstFactor": {
"kind": "Key",
"credentialAssertion": {
"credId": "passkey_xonETR6gAv3wIyhy8ehjx",
"clientData": "eyJ0eXBlIjoia2V5LmdldCIsImNoYWxsZW5nZS...",
"signature": "MEUCIAlkmdPEf0B_5xVr4DKK6uvsN0y1YVzsFe4vAOMlPcn4AiEA..."
}
}
}
}'Response 2 (Success):
{
"id": "key_2lRmxX5KBYRzMg",
"address": "0x08bEB4Ad3D8D607646E4d5311eb355Ec2d2396F5"
}Operations Using Pattern 2
| Operation | Endpoint | Payload Structure |
|---|---|---|
| Create Vault | POST /v1/vaults | {} (empty) |
| Sign Transaction | POST /v1/vaults/sign | {"keyId": "<vault_id>", "hash": "..."} |
| Approve Credential | POST /v1/vaults/credentials/approve | {"credentialId": "..."} |
| Deactivate Credential | POST /v1/vaults/credentials/deactivate | {"credentialId": "..."} |
| Activate Credential | POST /v1/vaults/credentials/activate | {"credentialId": "..."} |
Note: In Sign Transaction, keyId is the Due Vault ID (e.g., key_2lRmxX5KBYRzMg) returned when creating the vault.
Sequence Diagram
sequenceDiagram
participant Client
participant API as Due API
participant Signer as Private Key
Note over Client,API: Pattern 1: Credential Creation
Client->>API: POST /credentials/init
API-->>Client: challenge + clientDataHash
Client->>Client: Create JSON {clientDataHash, publicKey}
Client->>Signer: Sign SHA256(JSON)
Signer-->>Client: Hex signature
Client->>API: POST /credentials with signature
API-->>Client: Credential created
Note over Client,API: Pattern 2: Challenge-Response (All Other Operations)
Client->>API: POST /endpoint with {payload}
API-->>Client: 403 with base64 challenge
Client->>Client: Decode base64 challenge
Client->>Signer: Sign SHA256(decoded)
Signer-->>Client: Base64 URL-safe signature
Client->>API: POST /endpoint with {payload, signature}
API-->>Client: Success responseUpdated about 1 month ago