Request Signing Process
Step 1: Prepare Your Private Key
Ensure your private key is ready. It must be a 2048-bit RSA key.// Load private key from environment or secure storage
const privateKey = process.env.REBELL_PRIVATE_KEY;
// Or from file
const privateKey = fs.readFileSync('private_key.pem', 'utf-8');
from cryptography.hazmat.primitives import serialization
# Load private key
with open('private_key.pem', 'rb') as f:
private_key = serialization.load_pem_private_key(f.read(), password=None)
Step 2: Construct Content to Sign
Build a string combining the HTTP method, URI, client identifier, timestamp, and request body:<HTTP_METHOD> <HTTP_URI>
<Client-Id>.<Request-Time>.<HTTP_BODY>
| Component | Description | Example |
|---|---|---|
| HTTP_METHOD | The HTTP method | POST |
| HTTP_URI | The API endpoint path | /v1/payments/pay |
| Client-Id | Your assigned client ID | TEST_5X00000000000000 |
| Request-Time | ISO 8601 timestamp | 2024-01-10T12:12:12+01:00 |
| HTTP_BODY | JSON request body | {"paymentRequestId":"..."} |
POST /v1/payments/pay
TEST_5X00000000000000.2024-01-10T12:12:12+01:00.{"paymentRequestId":"REQ_001","paymentAmount":{"currency":"EUR","value":"1000"}}
Step 3: Generate Signature
Apply RSA with SHA-256 algorithm to generate the signature:const crypto = require('crypto');
function generateSignature(contentToSign, privateKey) {
const signer = crypto.createSign('RSA-SHA256');
signer.update(contentToSign);
const signature = signer.sign(privateKey, 'base64');
return signature;
}
// Build content to sign
const method = 'POST';
const uri = '/v1/payments/pay';
const clientId = 'YOUR_CLIENT_ID';
const requestTime = new Date().toISOString();
const body = JSON.stringify(requestBody);
const contentToSign = `${method} ${uri}\n${clientId}.${requestTime}.${body}`;
const signature = generateSignature(contentToSign, privateKey);
import base64
from datetime import datetime
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import padding
def generate_signature(content_to_sign: str, private_key) -> str:
signature = private_key.sign(
content_to_sign.encode('utf-8'),
padding.PKCS1v15(),
hashes.SHA256()
)
return base64.b64encode(signature).decode('utf-8')
# Build content to sign
method = 'POST'
uri = '/v1/payments/pay'
client_id = 'YOUR_CLIENT_ID'
request_time = datetime.utcnow().isoformat() + 'Z'
body = json.dumps(request_body, separators=(',', ':'))
content_to_sign = f"{method} {uri}\n{client_id}.{request_time}.{body}"
signature = generate_signature(content_to_sign, private_key)
Step 4: Add Signature to Header
Format and add the signature header to your request:Signature: algorithm=SHA256withRSA, keyVersion=1, signature=<generated_signature>
| Field | Description |
|---|---|
algorithm | Always SHA256withRSA |
keyVersion | Your key version (provided during onboarding) |
signature | Base64-encoded signature from Step 3 |
Complete Request Example
curl -X POST https://api.rebellapp.com/v1/payments/pay \
-H 'Content-Type: application/json' \
-H 'Client-Id: TEST_5X00000000000000' \
-H 'Request-Time: 2024-01-10T12:12:12+01:00' \
-H 'Signature: algorithm=SHA256withRSA, keyVersion=1, signature=BASE64_SIGNATURE_HERE' \
-d '{
"paymentRequestId": "REQ_001",
"paymentAmount": {
"currency": "EUR",
"value": "1000"
}
}'
const crypto = require('crypto');
async function callAPI(endpoint, body) {
const method = 'POST';
const clientId = process.env.REBELL_CLIENT_ID;
const keyVersion = '1';
const privateKey = process.env.REBELL_PRIVATE_KEY;
const requestTime = new Date().toISOString();
const bodyString = JSON.stringify(body);
// Build content to sign
const contentToSign = `${method} ${endpoint}\n${clientId}.${requestTime}.${bodyString}`;
// Generate signature
const signer = crypto.createSign('RSA-SHA256');
signer.update(contentToSign);
const signature = signer.sign(privateKey, 'base64');
// Make request
const response = await fetch(`https://api.rebellapp.com${endpoint}`, {
method,
headers: {
'Content-Type': 'application/json',
'Client-Id': clientId,
'Request-Time': requestTime,
'Signature': `algorithm=SHA256withRSA, keyVersion=${keyVersion}, signature=${signature}`
},
body: bodyString
});
return response.json();
}
import json
import base64
import requests
from datetime import datetime
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import padding
def call_api(endpoint: str, body: dict) -> dict:
method = 'POST'
client_id = os.environ['REBELL_CLIENT_ID']
key_version = '1'
request_time = datetime.utcnow().isoformat() + 'Z'
body_string = json.dumps(body, separators=(',', ':'))
# Load private key
with open('private_key.pem', 'rb') as f:
private_key = serialization.load_pem_private_key(f.read(), password=None)
# Build content to sign
content_to_sign = f"{method} {endpoint}\n{client_id}.{request_time}.{body_string}"
# Generate signature
signature = private_key.sign(
content_to_sign.encode('utf-8'),
padding.PKCS1v15(),
hashes.SHA256()
)
signature_b64 = base64.b64encode(signature).decode('utf-8')
# Make request
response = requests.post(
f'https://api.rebellapp.com{endpoint}',
headers={
'Content-Type': 'application/json',
'Client-Id': client_id,
'Request-Time': request_time,
'Signature': f'algorithm=SHA256withRSA, keyVersion={key_version}, signature={signature_b64}'
},
data=body_string
)
return response.json()
Response Signature Validation
Always verify the response signature before processing the data.Construct Content to Validate
Mirror the request signing process using response data:<HTTP_METHOD> <HTTP_URI>
<Client-Id>.<Response-Time>.<HTTP_BODY>
Verify Signature
function verifySignature(method, uri, clientId, responseTime, body, signature, publicKey) {
const contentToVerify = `${method} ${uri}\n${clientId}.${responseTime}.${body}`;
const verifier = crypto.createVerify('RSA-SHA256');
verifier.update(contentToVerify);
return verifier.verify(publicKey, signature, 'base64');
}
// Usage
const isValid = verifySignature(
'POST',
'/v1/payments/pay',
clientId,
response.headers['response-time'],
JSON.stringify(response.body),
extractSignature(response.headers['signature']),
rebellPublicKey
);
if (!isValid) {
throw new Error('Invalid response signature');
}
from cryptography.hazmat.primitives.asymmetric import padding
from cryptography.hazmat.primitives import hashes
def verify_signature(method, uri, client_id, response_time, body, signature_b64, public_key):
content_to_verify = f"{method} {uri}\n{client_id}.{response_time}.{body}"
signature = base64.b64decode(signature_b64)
try:
public_key.verify(
signature,
content_to_verify.encode('utf-8'),
padding.PKCS1v15(),
hashes.SHA256()
)
return True
except Exception:
return False
Key Points
Security Alert: Never log or expose the full signature content or private key. If you need to debug signature issues, log only non-sensitive parts like the method and URI.