# Authentication The Fordefi API uses two authentication mechanisms: bearer tokens and request signing. All requests must be authenticated using a bearer token (JWT). Certain sensitive operations also require signing with the private key associated with the API User. ## Bearer token API users authenticate their requests by passing their access token in the `Authorization` header with the `Bearer` prefix. All API requests are made to the following endpoint: ``` https://api.fordefi.com/ ``` When making a request, the value for the `Authorization` header must be in the format` Bearer {access token}`. For example: ``` Bearer eyJhbGciOiJFZERTQSIsImtpZCI6ImZ3MFc3aVpocUc0SUEzaXV4ZmhQIiwidHlwIjoiSldUIn0.eyJpc3MiOiJodHRwczovL2FwaS5mb3JkZWZpLmNvbS8iLCJzdWIiOiI2MDlmODVjMi00OWJmLTQwMzItOGM5Yy00NDMyZGEzMzE4MGVAZm9yZGVmaSIsImF1ZCI6WyJodHRwczovL2FwaS5mb3JkZWZpLmNvbS9hcGkvIl0sImV4cCI6MjAxNzI5MDg4NCwiaWF0IjoxNzAxOTMwODg0LCJqdGkiOiJlM2RmNDE0ZS03M2U3LTRkMWEtYmJjYy1iYThiZTE4NDhiOTMifQ.JodHRwczovL2FwaS5mb3JkZWZpLmNvbS8iLCJzdWIiOiI2MDlmODVjMi00OWJmLTQwMzItOGM5Yy00NDMyZGEzMzE4MGVAZm9yZGVmaSIsImF1ZCI6WyJ ``` All API requests must be made over HTTPS. Calls made over plain HTTP or without the`Authorization` header will fail. ## Request signing API requests for sensitive operations, such as creating transactions, require an additional authentication layer. ### Prerequisites Follow the instructions to [create an API User](/developers/getting-started/create-an-api-user) and an [API Signer](/developers/getting-started/set-up-an-api-signer), and [pair them](/developers/getting-started/pair-an-api-client-with-the-api-signer). ### Sign requests 1. Construct the signed message `${path}|${timestamp}|${requestBody}`, where: - `${path}` is the path of the API endpoint for this request. For example, when creating transactions, the path needs to be `/api/v1/transactions`. - `${timestamp}` is the time in milliseconds. - `${requestBody}` is the body of the request. 2. Sign the request body with the API User’s private key, whose public key you have [registered with the API Signer](/developers/getting-started/pair-an-api-client-with-the-api-signer). Use the ECDSA signature scheme over the NIST P-256 curve. 3. Pass the signature in a `x-signature` HTTP header of your `POST` request, and the timestamp used within the signature in the `x-timestamp` HTTP header. 4. Pass the API User's access token in the `Authorization: Bearer ` header, as with regular requests. You can use the following code sample as the basis for any type of request. The API endpoint and body of the request differ, based on the specific type of request you are creating. Shell ```shell #!bash ACCESS_TOKEN='' PRIVATE_KEY_FILE='' ENDPOINT='' BODY='' TIMESTAMP="$(($(date +%s) * 1000))" SIGNATURE="$(echo -n "${ENDPOINT}|${TIMESTAMP}|${BODY}" | openssl dgst -sha256 -sign ${PRIVATE_KEY_FILE} | base64 | tr -d \\n)" echo -n "${ENDPOINT}|${TIMESTAMP}|${BODY}" curl -v "https://api.fordefi.com${ENDPOINT}" \ -H "Authorization: Bearer ${ACCESS_TOKEN}" \ -H "Content-Type: application/json" \ -H "x-signature: ${SIGNATURE}" \ -H "x-timestamp: ${TIMESTAMP}" \ -d "${BODY}" ``` Python ```py import requests import base64 import json import datetime import ecdsa import hashlib access_token = "" private_key_file = "" path = "" request_json = timestamp = datetime.datetime.now().strftime("%s") request_body = json.dumps(request_json) payload = f"{path}|{timestamp}|{request_body}" with open(private_key_file, "r") as f: signing_key = ecdsa.SigningKey.from_pem(f.read()) signature = signing_key.sign( data=payload.encode(), hashfunc=hashlib.sha256, sigencode=ecdsa.util.sigencode_der ) resp_tx = requests.post( f"https://api.fordefi.com{path}", headers={ "Authorization": f"Bearer {access_token}", "x-signature": base64.b64encode(signature), "x-timestamp": timestamp.encode(), }, data=request_body, ) ``` Javascript ```js const crypto = require("crypto"); const fs = require('fs'); const accessToken = "" const privateKeyFile = "" const path = "" const requestJson = const gatewayHost = "api.fordefi.com" const requestBody = JSON.stringify(requestJson) const timestamp = new Date().getTime(); const payload = `${path}|${timestamp}|${requestBody}`; const secretPem = fs.readFileSync(privateKeyFile, 'utf8'); const privateKey = crypto.createPrivateKey(secretPem); const sign = crypto.createSign('SHA256').update(payload, 'utf8').end(); const signature = sign.sign(privateKey, 'base64'); fetch(`https://${gatewayHost}${path}`, { method: 'POST', headers: { 'Content-Type': 'application/json', "Authorization": `Bearer ${accessToken}`, 'X-Timestamp': timestamp, 'X-Signature': signature, }, body: requestBody, }).then((response) => response.text()) .then((json) => console.log(json)); ``` Rust ```rust // Using crate p256 = { version = "0.12.0", features = ["pem"] } use base64::{engine::general_purpose, Engine as _}; use p256::ecdsa::{signature::Signer, Signature, SigningKey}; use std::fs; use std::time::{SystemTime, UNIX_EPOCH}; // This is the main function fn main() -> Result<(), Box> { let access_token = ""; let private_key_file = ""; let path = ""; let request_body = r#" "#; let gateway_host = "api.fordefi.com"; let timestamp = SystemTime::now() .duration_since(UNIX_EPOCH) .unwrap() .as_millis() .to_string(); let payload = format!("{path}|{timestamp}|{request_body}"); let priv_pem = fs::read_to_string(private_key_file).expect("Failed to read pem file"); let private_key = p256::SecretKey::from_sec1_pem(&priv_pem).expect("Failed to decode pem key"); let signing_key: SigningKey = private_key.into(); let signature: Signature = signing_key.sign(payload.as_bytes()); let formatted_signature = general_purpose::STANDARD.encode(signature.to_der().to_bytes()); let client = reqwest::blocking::Client::new(); let res = client .post(format!("https://{gateway_host}{path}")) .body(request_body) .bearer_auth(access_token) .header("Content-Type", "application/json") .header("X-Timestamp", timestamp) .header("X-Signature", formatted_signature) .send()? .text()?; println!("Result: {res}"); Ok(()) } ```