Authentication
Client ID/Secret ModelCopied!
All API requests require proper signing with your Client Secret. The Client ID alone cannot be used to access the API.
-
Client ID: Your public project identifier
-
Client Secret: Your private signing key (must be kept secure)
Important Security Note: Knowing just your Client ID is not enough to access the API. All requests must be signed with your Client Secret.
Security BenefitsCopied!
This authentication model offers several security advantages:
-
Two-factor authentication: Access requires both the Client ID and a valid signature
-
No secret transmission: Your Client Secret is never sent to our servers
-
Request integrity: The signature ensures requests haven't been tampered with
-
Reduced risk: Even if your Client ID is exposed, attackers can't make API calls without the secret
-
Non-repudiation: Signed requests provide a strong audit trail
Authentication HeadersCopied!
All API requests to orda must include these headers:
Header |
Description |
---|---|
|
Your project's client ID |
|
HMAC-SHA256 signature derived from your client secret |
|
Usually application/json for requests with a body |
Optional Headers
Header |
Description |
---|---|
|
Optional timestamp (in milliseconds since epoch) for preventing replay attacks |
Creating a SignatureCopied!
The signature is an HMAC-SHA256 hash of the canonicalized request body, using your Client Secret as the key.
Signature Process
-
Canonicalize your request body to ensure consistent JSON serialization
-
For GET requests with no body, use an empty string
-
Create an HMAC-SHA256 hash of the canonical string using your Client Secret as the key
-
Convert the resulting hash to a hexadecimal string
-
Include this hex string in the x-signature header
Canonical JSON Serialization
The request body is canonicalized to ensure consistent signatures regardless of JSON key ordering:
-
Object keys are sorted alphabetically
-
No whitespace between elements
-
Consistent string escaping
-
Handles nested objects and arrays recursively
Example:
// Original JSON (key order may vary)
{"name": "John", "age": 30, "city": "New York"}
// Canonical JSON (always same output)
{"age":30,"city":"New York","name":"John"}
Implementation Examples
const crypto = require('crypto');
function canonicalizeJSON(obj, seenObjects = new WeakSet()) {
if (obj === null) {
return 'null';
}
if (typeof obj === 'undefined') {
return 'undefined';
}
if (typeof obj === 'boolean' || typeof obj === 'number') {
return String(obj);
}
if (typeof obj === 'string') {
return JSON.stringify(obj);
}
if (obj instanceof Date) {
return JSON.stringify(obj.toISOString());
}
if (Array.isArray(obj)) {
if (seenObjects.has(obj)) {
return '[Circular]';
}
seenObjects.add(obj);
const items = obj.map(item => canonicalizeJSON(item, seenObjects));
seenObjects.delete(obj);
return `[${items.join(',')}]`;
}
if (typeof obj === 'object') {
if (seenObjects.has(obj)) {
return '{Circular}';
}
seenObjects.add(obj);
// Sort keys to ensure consistent ordering
const sortedKeys = Object.keys(obj).sort();
const pairs = sortedKeys.map(key => {
const value = canonicalizeJSON(obj[key], seenObjects);
return `${JSON.stringify(key)}:${value}`;
});
seenObjects.delete(obj);
return `{${pairs.join(',')}}`;
}
return JSON.stringify(obj);
}
function createSignature(clientSecret, requestBody) {
// For GET requests with no body, use an empty string
const canonicalBody = requestBody ? canonicalizeJSON(requestBody) : '';
// Create HMAC using client secret
const hmac = crypto.createHmac('sha256', clientSecret);
// Update HMAC with the canonical body and get the hex digest
const signature = hmac.update(canonicalBody).digest('hex');
return signature;
}
// Example usage for a POST request
const clientId = 'client_12345abcde';
const clientSecret = 'secret_67890fghij';
const requestBody = {
name: 'Test Account',
toChain: '1',
toToken: 'ETH',
toAddress: '0x742d35Cc6634C0532925a3b844Bc454e4438f44b'
};
const signature = createSignature(clientSecret, requestBody);
// Making the request with axios
const headers = {
'Content-Type': 'application/json',
'x-client-id': clientId,
'x-signature': signature
};
axios.post('https://api.orda.network/v1.1/projects/proj_id/accounts',
requestBody,
{ headers })
.then(response => console.log(response.data))
.catch(error => console.error('Error:', error));
// For GET requests with no body
const getSignature = createSignature(clientSecret, null);
axios.get('https://api.orda.network/v1.1/projects/proj_id/accounts', {
headers: {
'x-client-id': clientId,
'x-signature': getSignature
}
})
.then(response => console.log(response.data))
.catch(error => console.error('Error:', error));
import hmac
import hashlib
import json
import requests
from typing import Any, Set
def canonicalize_json(obj: Any, seen_objects: Set[int] = None) -> str:
if seen_objects is None:
seen_objects = set()
if obj is None:
return 'null'
elif isinstance(obj, bool):
return 'true' if obj else 'false'
elif isinstance(obj, (int, float)):
return str(obj)
elif isinstance(obj, str):
return json.dumps(obj)
elif isinstance(obj, list):
obj_id = id(obj)
if obj_id in seen_objects:
return '[Circular]'
seen_objects.add(obj_id)
items = [canonicalize_json(item, seen_objects) for item in obj]
seen_objects.remove(obj_id)
return f"[{','.join(items)}]"
elif isinstance(obj, dict):
obj_id = id(obj)
if obj_id in seen_objects:
return '{Circular}'
seen_objects.add(obj_id)
sorted_keys = sorted(obj.keys())
pairs = [f'"{key}":{canonicalize_json(obj[key], seen_objects)}' for key in sorted_keys]
seen_objects.remove(obj_id)
return f"{{{','.join(pairs)}}}"
else:
return json.dumps(obj)
def create_signature(client_secret, request_body=None):
# For GET requests with no body, use an empty string
canonical_body = canonicalize_json(request_body) if request_body else ''
# Create HMAC using client secret
signature = hmac.new(
client_secret.encode('utf-8'),
canonical_body.encode('utf-8'),
hashlib.sha256
).hexdigest()
return signature
# Example usage for a POST request
client_id = 'client_12345abcde'
client_secret = 'secret_67890fghij'
request_body = {
'name': 'Test Account',
'toChain': '1',
'toToken': 'ETH',
'toAddress': '0x742d35Cc6634C0532925a3b844Bc454e4438f44b'
}
signature = create_signature(client_secret, request_body)
headers = {
'Content-Type': 'application/json',
'x-client-id': client_id,
'x-signature': signature
}
response = requests.post(
'https://api.orda.network/v1.1/projects/proj_id/accounts',
headers=headers,
json=request_body
)
print(response.json())
# For GET requests with no body
get_signature = create_signature(client_secret)
get_headers = {
'x-client-id': client_id,
'x-signature': get_signature
}
get_response = requests.get(
'https://api.orda.network/v1.1/projects/proj_id/accounts',
headers=get_headers
)
print(get_response.json())
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.*;
import org.apache.commons.codec.binary.Hex;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
public class HmacSigner {
public static String canonicalizeJSON(Object obj, Set<Object> seenObjects) {
if (seenObjects == null) {
seenObjects = new HashSet<>();
}
if (obj == null) {
return "null";
}
if (obj instanceof Boolean || obj instanceof Number) {
return obj.toString();
}
if (obj instanceof String) {
return "\"" + obj.toString().replace("\\", "\\\\").replace("\"", "\\\"") + "\"";
}
if (obj instanceof List) {
if (seenObjects.contains(obj)) {
return "[Circular]";
}
seenObjects.add(obj);
List<?> list = (List<?>) obj;
List<String> items = new ArrayList<>();
for (Object item : list) {
items.add(canonicalizeJSON(item, seenObjects));
}
seenObjects.remove(obj);
return "[" + String.join(",", items) + "]";
}
if (obj instanceof Map) {
if (seenObjects.contains(obj)) {
return "{Circular}";
}
seenObjects.add(obj);
Map<?, ?> map = (Map<?, ?>) obj;
List<String> keys = new ArrayList<>();
for (Object key : map.keySet()) {
keys.add(key.toString());
}
Collections.sort(keys);
List<String> pairs = new ArrayList<>();
for (String key : keys) {
String value = canonicalizeJSON(map.get(key), seenObjects);
pairs.add("\"" + key + "\":" + value);
}
seenObjects.remove(obj);
return "{" + String.join(",", pairs) + "}";
}
return "\"" + obj.toString() + "\"";
}
public static String createSignature(String clientSecret, Object requestBody) throws Exception {
// Convert request body to canonical JSON string, or use empty string for null
String canonicalBody = "";
if (requestBody != null) {
canonicalBody = canonicalizeJSON(requestBody, null);
}
// Create HMAC-SHA256 signature
Mac hmac = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKey = new SecretKeySpec(
clientSecret.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
hmac.init(secretKey);
byte[] hash = hmac.doFinal(canonicalBody.getBytes(StandardCharsets.UTF_8));
// Convert to hex string
return Hex.encodeHexString(hash);
}
public static void main(String[] args) {
try {
String clientId = "client_12345abcde";
String clientSecret = "secret_67890fghij";
// Create request body
Map<String, Object> requestBody = new HashMap<>();
requestBody.put("name", "Test Account");
requestBody.put("toChain", "1");
requestBody.put("toToken", "ETH");
requestBody.put("toAddress", "0x742d35Cc6634C0532925a3b844Bc454e4438f44b");
// Generate signature
String signature = createSignature(clientSecret, requestBody);
// Make HTTP request
CloseableHttpClient client = HttpClients.createDefault();
HttpPost httpPost = new HttpPost("https://api.orda.network/v1.1/projects/proj_id/accounts");
// Set headers
httpPost.setHeader("Content-Type", "application/json");
httpPost.setHeader("x-client-id", clientId);
httpPost.setHeader("x-signature", signature);
// Set body
ObjectMapper mapper = new ObjectMapper();
String jsonBody = mapper.writeValueAsString(requestBody);
httpPost.setEntity(new StringEntity(jsonBody));
// Execute request
client.execute(httpPost);
// For GET requests, signature would be created with null requestBody
String getSignature = createSignature(clientSecret, null);
} catch (Exception e) {
e.printStackTrace();
}
}
}
require 'openssl'
require 'json'
require 'net/http'
require 'uri'
def canonicalize_json(obj, seen_objects = Set.new)
case obj
when nil
'null'
when true, false
obj.to_s
when Numeric
obj.to_s
when String
obj.to_json
when Array
if seen_objects.include?(obj.object_id)
return '[Circular]'
end
seen_objects.add(obj.object_id)
items = obj.map { |item| canonicalize_json(item, seen_objects) }
seen_objects.delete(obj.object_id)
"[#{items.join(',')}]"
when Hash
if seen_objects.include?(obj.object_id)
return '{Circular}'
end
seen_objects.add(obj.object_id)
sorted_keys = obj.keys.sort
pairs = sorted_keys.map do |key|
value = canonicalize_json(obj[key], seen_objects)
"#{key.to_json}:#{value}"
end
seen_objects.delete(obj.object_id)
"{#{pairs.join(',')}}"
else
obj.to_json
end
end
def create_signature(client_secret, request_body = nil)
# For GET requests with no body, use an empty string
canonical_body = request_body ? canonicalize_json(request_body) : ''
# Create HMAC using client secret
signature = OpenSSL::HMAC.hexdigest(
'SHA256',
client_secret,
canonical_body
)
return signature
end
# Example usage for a POST request
client_id = 'client_12345abcde'
client_secret = 'secret_67890fghij'
request_body = {
name: 'Test Account',
toChain: '1',
toToken: 'ETH',
toAddress: '0x742d35Cc6634C0532925a3b844Bc454e4438f44b'
}
signature = create_signature(client_secret, request_body)
uri = URI('https://api.orda.network/v1.1/projects/proj_id/accounts')
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Post.new(uri,
'Content-Type' => 'application/json',
'x-client-id' => client_id,
'x-signature' => signature
)
request.body = request_body.to_json
response = http.request(request)
puts response.body
# For GET requests with no body
get_signature = create_signature(client_secret)
get_uri = URI('https://api.orda.network/v1.1/projects/proj_id/accounts')
get_request = Net::HTTP::Get.new(get_uri,
'x-client-id' => client_id,
'x-signature' => get_signature
)
get_response = http.request(get_request)
puts get_response.body
package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"fmt"
"reflect"
"sort"
"strings"
"bytes"
"net/http"
)
func canonicalizeJSON(obj interface{}, seenObjects map[uintptr]bool) string {
if seenObjects == nil {
seenObjects = make(map[uintptr]bool)
}
if obj == nil {
return "null"
}
v := reflect.ValueOf(obj)
switch v.Kind() {
case reflect.Bool:
if v.Bool() {
return "true"
}
return "false"
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return fmt.Sprintf("%d", v.Int())
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
return fmt.Sprintf("%d", v.Uint())
case reflect.Float32, reflect.Float64:
return fmt.Sprintf("%g", v.Float())
case reflect.String:
jsonBytes, _ := json.Marshal(v.String())
return string(jsonBytes)
case reflect.Slice, reflect.Array:
ptr := v.Pointer()
if seenObjects[ptr] {
return "[Circular]"
}
seenObjects[ptr] = true
defer delete(seenObjects, ptr)
var items []string
for i := 0; i < v.Len(); i++ {
items = append(items, canonicalizeJSON(v.Index(i).Interface(), seenObjects))
}
return "[" + strings.Join(items, ",") + "]"
case reflect.Map:
ptr := v.Pointer()
if seenObjects[ptr] {
return "{Circular}"
}
seenObjects[ptr] = true
defer delete(seenObjects, ptr)
keys := v.MapKeys()
sort.Slice(keys, func(i, j int) bool {
return fmt.Sprintf("%v", keys[i].Interface()) < fmt.Sprintf("%v", keys[j].Interface())
})
var pairs []string
for _, key := range keys {
keyStr, _ := json.Marshal(fmt.Sprintf("%v", key.Interface()))
valueStr := canonicalizeJSON(v.MapIndex(key).Interface(), seenObjects)
pairs = append(pairs, string(keyStr)+":"+valueStr)
}
return "{" + strings.Join(pairs, ",") + "}"
default:
jsonBytes, _ := json.Marshal(obj)
return string(jsonBytes)
}
}
func createSignature(clientSecret string, requestBody interface{}) string {
var canonicalBody string
if requestBody != nil {
canonicalBody = canonicalizeJSON(requestBody, nil)
} else {
canonicalBody = ""
}
h := hmac.New(sha256.New, []byte(clientSecret))
h.Write([]byte(canonicalBody))
return hex.EncodeToString(h.Sum(nil))
}
func main() {
clientID := "client_12345abcde"
clientSecret := "secret_67890fghij"
requestBody := map[string]interface{}{
"name": "Test Account",
"toChain": "1",
"toToken": "ETH",
"toAddress": "0x742d35Cc6634C0532925a3b844Bc454e4438f44b",
}
signature := createSignature(clientSecret, requestBody)
// Create HTTP request
jsonBody, _ := json.Marshal(requestBody)
req, _ := http.NewRequest("POST", "https://api.orda.network/v1.1/projects/proj_id/accounts", bytes.NewBuffer(jsonBody))
req.Header.Set("Content-Type", "application/json")
req.Header.Set("x-client-id", clientID)
req.Header.Set("x-signature", signature)
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
fmt.Printf("Error: %v\n", err)
return
}
defer resp.Body.Close()
// For GET requests with no body
getSignature := createSignature(clientSecret, nil)
getReq, _ := http.NewRequest("GET", "https://api.orda.network/v1.1/projects/proj_id/accounts", nil)
getReq.Header.Set("x-client-id", clientID)
getReq.Header.Set("x-signature", getSignature)
fmt.Printf("POST signature: %s\n", signature)
fmt.Printf("GET signature: %s\n", getSignature)
}
use hmac::{Hmac, Mac};
use sha2::Sha256;
use serde_json::{Map, Value};
use std::collections::{HashMap, HashSet};
use reqwest;
use serde_json;
type HmacSha256 = Hmac<Sha256>;
fn canonicalize_json(obj: &Value, seen_objects: &mut HashSet<*const Value>) -> String {
let obj_ptr = obj as *const Value;
match obj {
Value::Null => "null".to_string(),
Value::Bool(b) => b.to_string(),
Value::Number(n) => n.to_string(),
Value::String(s) => serde_json::to_string(s).unwrap(),
Value::Array(arr) => {
if seen_objects.contains(&obj_ptr) {
return "[Circular]".to_string();
}
seen_objects.insert(obj_ptr);
let items: Vec<String> = arr.iter()
.map(|item| canonicalize_json(item, seen_objects))
.collect();
seen_objects.remove(&obj_ptr);
format!("[{}]", items.join(","))
}
Value::Object(map) => {
if seen_objects.contains(&obj_ptr) {
return "{Circular}".to_string();
}
seen_objects.insert(obj_ptr);
let mut keys: Vec<&String> = map.keys().collect();
keys.sort();
let pairs: Vec<String> = keys.iter()
.map(|key| {
let key_str = serde_json::to_string(key).unwrap();
let value_str = canonicalize_json(map.get(*key).unwrap(), seen_objects);
format!("{}:{}", key_str, value_str)
})
.collect();
seen_objects.remove(&obj_ptr);
format!("{{{}}}", pairs.join(","))
}
}
}
fn create_signature(client_secret: &str, request_body: Option<&Value>) -> Result<String, Box<dyn std::error::Error>> {
let canonical_body = match request_body {
Some(body) => canonicalize_json(body, &mut HashSet::new()),
None => String::new(),
};
let mut mac = HmacSha256::new_from_slice(client_secret.as_bytes())?;
mac.update(canonical_body.as_bytes());
let result = mac.finalize();
Ok(hex::encode(result.into_bytes()))
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let client_id = "client_12345abcde";
let client_secret = "secret_67890fghij";
let request_body = serde_json::json!({
"name": "Test Account",
"toChain": "1",
"toToken": "ETH",
"toAddress": "0x742d35Cc6634C0532925a3b844Bc454e4438f44b"
});
let signature = create_signature(client_secret, Some(&request_body))?;
let client = reqwest::Client::new();
let response = client
.post("https://api.orda.network/v1.1/projects/proj_id/accounts")
.header("Content-Type", "application/json")
.header("x-client-id", client_id)
.header("x-signature", &signature)
.json(&request_body)
.send()
.await?;
println!("Response: {:?}", response.status());
// For GET requests with no body
let get_signature = create_signature(client_secret, None)?;
let get_response = client
.get("https://api.orda.network/v1.1/projects/proj_id/accounts")
.header("x-client-id", client_id)
.header("x-signature", &get_signature)
.send()
.await?;
println!("GET Response: {:?}", get_response.status());
Ok(())
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
using System.Net.Http;
using System.Threading.Tasks;
public class HmacSigner
{
private static readonly HashSet<object> SeenObjects = new HashSet<object>();
public static string CanonicalizeJson(object obj, HashSet<object> seenObjects = null)
{
seenObjects = seenObjects ?? new HashSet<object>();
if (obj == null)
return "null";
if (obj is bool boolVal)
return boolVal.ToString().ToLower();
if (obj is int || obj is long || obj is double || obj is float || obj is decimal)
return obj.ToString();
if (obj is string strVal)
return JsonSerializer.Serialize(strVal);
if (obj is JsonElement jsonElement)
{
switch (jsonElement.ValueKind)
{
case JsonValueKind.Null:
return "null";
case JsonValueKind.True:
return "true";
case JsonValueKind.False:
return "false";
case JsonValueKind.Number:
return jsonElement.ToString();
case JsonValueKind.String:
return JsonSerializer.Serialize(jsonElement.GetString());
case JsonValueKind.Array:
if (seenObjects.Contains(jsonElement))
return "[Circular]";
seenObjects.Add(jsonElement);
var arrayItems = jsonElement.EnumerateArray()
.Select(item => CanonicalizeJson(item, seenObjects))
.ToArray();
seenObjects.Remove(jsonElement);
return $"[{string.Join(",", arrayItems)}]";
case JsonValueKind.Object:
if (seenObjects.Contains(jsonElement))
return "{Circular}";
seenObjects.Add(jsonElement);
var objectPairs = jsonElement.EnumerateObject()
.OrderBy(prop => prop.Name)
.Select(prop => $"{JsonSerializer.Serialize(prop.Name)}:{CanonicalizeJson(prop.Value, seenObjects)}")
.ToArray();
seenObjects.Remove(jsonElement);
return $"{{{string.Join(",", objectPairs)}}}";
}
}
return JsonSerializer.Serialize(obj);
}
public static string CreateSignature(string clientSecret, object requestBody = null)
{
string canonicalBody = requestBody != null
? CanonicalizeJson(requestBody)
: string.Empty;
using (var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(clientSecret)))
{
byte[] hashBytes = hmac.ComputeHash(Encoding.UTF8.GetBytes(canonicalBody));
return Convert.ToHexString(hashBytes).ToLower();
}
}
public static async Task Main(string[] args)
{
string clientId = "client_12345abcde";
string clientSecret = "secret_67890fghij";
var requestBody = new
{
name = "Test Account",
toChain = "1",
toToken = "ETH",
toAddress = "0x742d35Cc6634C0532925a3b844Bc454e4438f44b"
};
string signature = CreateSignature(clientSecret, requestBody);
using (var client = new HttpClient())
{
var request = new HttpRequestMessage(HttpMethod.Post,
"https://api.orda.network/v1.1/projects/proj_id/accounts");
request.Headers.Add("x-client-id", clientId);
request.Headers.Add("x-signature", signature);
request.Content = new StringContent(
JsonSerializer.Serialize(requestBody),
Encoding.UTF8,
"application/json"
);
var response = await client.SendAsync(request);
Console.WriteLine($"POST Response: {response.StatusCode}");
// For GET requests with no body
string getSignature = CreateSignature(clientSecret);
var getRequest = new HttpRequestMessage(HttpMethod.Get,
"https://api.orda.network/v1.1/projects/proj_id/accounts");
getRequest.Headers.Add("x-client-id", clientId);
getRequest.Headers.Add("x-signature", getSignature);
var getResponse = await client.SendAsync(getRequest);
Console.WriteLine($"GET Response: {getResponse.StatusCode}");
}
}
}
import * as crypto from 'crypto';
import axios from 'axios';
function canonicalizeJSON(obj: any, seenObjects: WeakSet<object> = new WeakSet()): string {
if (obj === null) {
return 'null';
}
if (typeof obj === 'undefined') {
return 'undefined';
}
if (typeof obj === 'boolean' || typeof obj === 'number') {
return String(obj);
}
if (typeof obj === 'string') {
return JSON.stringify(obj);
}
if (obj instanceof Date) {
return JSON.stringify(obj.toISOString());
}
if (Array.isArray(obj)) {
if (seenObjects.has(obj)) {
return '[Circular]';
}
seenObjects.add(obj);
const items = obj.map(item => canonicalizeJSON(item, seenObjects));
seenObjects.delete(obj);
return `[${items.join(',')}]`;
}
if (typeof obj === 'object') {
if (seenObjects.has(obj)) {
return '{Circular}';
}
seenObjects.add(obj);
const sortedKeys = Object.keys(obj).sort();
const pairs = sortedKeys.map(key => {
const value = canonicalizeJSON(obj[key], seenObjects);
return `${JSON.stringify(key)}:${value}`;
});
seenObjects.delete(obj);
return `{${pairs.join(',')}}`;
}
return JSON.stringify(obj);
}
function createSignature(clientSecret: string, requestBody?: any): string {
const canonicalBody = requestBody ? canonicalizeJSON(requestBody) : '';
const hmac = crypto.createHmac('sha256', clientSecret);
const signature = hmac.update(canonicalBody).digest('hex');
return signature;
}
interface RequestBody {
name: string;
toChain: string;
toToken: string;
toAddress: string;
}
// Example usage for a POST request
const clientId: string = 'client_12345abcde';
const clientSecret: string = 'secret_67890fghij';
const requestBody: RequestBody = {
name: 'Test Account',
toChain: '1',
toToken: 'ETH',
toAddress: '0x742d35Cc6634C0532925a3b844Bc454e4438f44b'
};
const signature = createSignature(clientSecret, requestBody);
const headers = {
'Content-Type': 'application/json',
'x-client-id': clientId,
'x-signature': signature
};
axios.post('https://api.orda.network/v1.1/projects/proj_id/accounts', requestBody, { headers })
.then(response => console.log(response.data))
.catch(error => console.error('Error:', error));
// For GET requests with no body
const getSignature = createSignature(clientSecret);
axios.get('https://api.orda.network/v1.1/projects/proj_id/accounts', {
headers: {
'x-client-id': clientId,
'x-signature': getSignature
}
})
.then(response => console.log(response.data))
.catch(error => console.error('Error:', error));
export { createSignature, canonicalizeJSON };
Security Recommendations
-
Never share your Client Secret: Your Client Secret should be treated like a password and never shared publicly or committed to version control.
-
Store secrets securely: Use environment variables, secret management services, or secure storage solutions to manage your Client Secret.
-
Regenerate secrets if compromised: If you suspect your Client Secret has been compromised, regenerate it immediately through the orda Dashboard.
-
Use HTTPS: Always make API requests over HTTPS to ensure the security of your Client ID and signature.
Implementation Tips
-
Canonical JSON serialization: The canonical serialization ensures consistent signatures regardless of object key ordering or JSON library differences.
-
Empty body handling: For requests without a body (like GET requests), use an empty string as the input to the HMAC function.
-
Character encoding: Always use UTF-8 encoding when converting strings to bytes for HMAC calculation.
-
Error handling: Include proper error handling to diagnose signature creation issues during development.
Common Issues and TroubleshootingCopied!
Invalid Signature Errors
If you receive "Invalid signature" errors:
-
Check your Client Secret: Ensure you're using the correct Client Secret for the Client ID.
-
Verify canonical serialization: Ensure you're using the canonical JSON serialization method shown above.
-
HTTP method: Confirm you're using the correct HTTP method (GET, POST, PUT, DELETE).
-
String encoding: Verify you're using UTF-8 encoding for string conversions.
-
Empty bodies: For GET requests, ensure you're signing an empty string, not "null" or "undefined".
SupportCopied!
If you encounter any issues implementing this authentication method, reach out!