Инструкция по созданию JWT токена:
Rapira использует стандартную схему JWT авторизации (документация: https://jwt.io/ и https://tools.ietf.org/html/rfc7519), то есть для работы с методами API вначале нужно запросить у сервера JWT токен, который уже будет использоваться в Bearer аутентификации.
Полученный токен нужно сохранить и использовать его для запросов. Не нужно создавать новый токен на каждый запрос.
Время жизни JWT токена ограничено, и после его истечения токен становится недействительным.
Время жизни JWT определяется параметрами API ключа, и может быть изменено в настройках для каждого API ключа. Минимальное время жизни JWT 30 минут, максимальное 24 часа. По умолчанию значение TTL 24 часа.
Параметры JWT запроса:
- exp - опциональный, время жизни JWT запроса. Не устанавливайте его слишком большим и не оставляйте пустым, если вы не планируете переиспользовать запрос многократно.
- jti - обязательный, уникальный идентификатор запроса.
- алгоритм подписи JWT - RS256
- все остальные опциональные параметры не используются и устанавливать их не обязательно.
Для декодирования и проверки токенов можно использовать онлайн отладчик на сайте https://jwt.io//
Снизу приведен пример на php.
# requirements:
# pip3 install 'pyjwt[crypto]'
import base64
import time
import datetime
import random
import requests
import jwt
private_key = 'приватный_ключ'
uid = 'uid_апи_ключа'
host = 'api.rapira.net'
key = base64.b64decode(private_key)
iat = int(time.mktime(datetime.datetime.now().timetuple()))
claims = {
"exp": iat + 1*60*60, # JWT Request TTL in seconds since epoch
"jti": hex(random.getrandbits(12)).upper()
}
jwt_token = jwt.encode(claims, key, algorithm="RS256")
print("JWT request token: %s\n" % jwt_token)
ret = requests.post('https://' + host + '/open/generate_jwt',
json={'kid': uid, 'jwt_token': jwt_token})
print("JWT response code: %d" % ret.status_code)
print("JWY response text: %s\n" % ret.text)
token = ret.json().get('token')
print("JWT token: %s\n" % token)
ret = requests.get('https://' + host + '/open/wallet/balance',
headers={'Authorization': 'Bearer ' + token})
print("Test request response code: %d" % ret.status_code)
print("Test request response text: %s" % ret.text)
response = ret.json()
<?php
if(!class_exists('JWT')){
class JWT
{
function __construct(){
}
function encode($payload, $key)
{
$algo = 'RS256';
$header = array('typ' => 'JWT', 'alg' => $algo);
$segments = array();
$segments[] = $this->urlsafeB64Encode($this->jsonEncode($header));
$segments[] = $this->urlsafeB64Encode($this->jsonEncode($payload));
$signing_input = implode('.', $segments);
$signature = $this->sign($signing_input, $key);
$segments[] = $this->urlsafeB64Encode($signature);
return implode('.', $segments);
}
function sign($payload, $key)
{
$passphrase = '';
$algo = OPENSSL_ALGO_SHA256;
$key_type = OPENSSL_KEYTYPE_RSA;
$privateKey = openssl_pkey_get_private($key, $passphrase);
if (is_bool($privateKey)) {
$error = openssl_error_string();
throw new Exception($error);
}
$details = openssl_pkey_get_details($privateKey);
if (!array_key_exists('key', $details) || $details['type'] !== $key_type) {
throw new Exception("Invalid key provided");
}
$signature = '';
if (!openssl_sign($payload, $signature, $privateKey, $algo)) {
$error = openssl_error_string();
throw new Exception($error);
}
return $signature;
}
function jsonDecode($input)
{
$obj = json_decode($input);
if (function_exists('json_last_error') && $errno = json_last_error()) {
$this->_handleJsonError($errno);
} else if ($obj === null && $input !== 'null') {
throw new Exception('Null result with non-null input');
}
return $obj;
}
function jsonEncode($input)
{
$json = json_encode($input);
if (function_exists('json_last_error') && $errno = json_last_error()) {
$this->_handleJsonError($errno);
} else if ($json === 'null' && $input !== null) {
throw new Exception('Null result with non-null input');
}
return $json;
}
function urlsafeB64Decode($input)
{
$remainder = strlen($input) % 4;
if ($remainder) {
$padlen = 4 - $remainder;
$input .= str_repeat('=', $padlen);
}
return base64_decode(strtr($input, '-_', '+/'));
}
function urlsafeB64Encode($input)
{
return str_replace('=', '', strtr(base64_encode($input), '+/', '-_'));
}
function _handleJsonError($errno)
{
$messages = array(
JSON_ERROR_DEPTH => 'Maximum stack depth exceeded',
JSON_ERROR_CTRL_CHAR => 'Unexpected control character found',
JSON_ERROR_SYNTAX => 'Syntax error, malformed JSON'
);
throw new Exception(
isset($messages[$errno])
? $messages[$errno]
: 'Unknown JSON error: ' . $errno
);
}
}
}
$private_key = "{здесь Ваш privateKey}";
$uid= "{Здесь Ваш uid}";
$request = array('exp' => time() + 3600, 'jti' => bin2hex(random_bytes(12)));
$class = new JWT();
$payload = $class->encode($request, base64_decode($private_key, true));
$post_data = array('kid' => $uid, 'jwt_token' => $payload);
print_r($post_data);
?>
<?php
class JWT
{
function __construct(){
}
function encode($payload, $key)
{
$algo = 'RS256';
$header = array('typ' => 'JWT', 'alg' => $algo);
$segments = array();
$segments[] = $this->urlsafeB64Encode($this->jsonEncode($header));
$segments[] = $this->urlsafeB64Encode($this->jsonEncode($payload));
$signing_input = implode('.', $segments);
$signature = $this->sign($signing_input, $key);
$segments[] = $this->urlsafeB64Encode($signature);
return implode('.', $segments);
}
function sign($payload, $key)
{
$passphrase = '';
$algo = OPENSSL_ALGO_SHA256;
$key_type = OPENSSL_KEYTYPE_RSA;
$privateKey = openssl_pkey_get_private($key, $passphrase);
if (is_bool($privateKey)) {
$error = openssl_error_string();
throw new Exception($error);
}
$details = openssl_pkey_get_details($privateKey);
if (!array_key_exists('key', $details) || $details['type'] !== $key_type) {
throw new Exception("Invalid key provided");
}
$signature = '';
if (!openssl_sign($payload, $signature, $privateKey, $algo)) {
$error = openssl_error_string();
throw new Exception($error);
}
return $signature;
}
function jsonDecode($input)
{
$obj = json_decode($input);
if (function_exists('json_last_error') && $errno = json_last_error()) {
$this->_handleJsonError($errno);
} else if ($obj === null && $input !== 'null') {
throw new Exception('Null result with non-null input');
}
return $obj;
}
function jsonEncode($input)
{
$json = json_encode($input);
if (function_exists('json_last_error') && $errno = json_last_error()) {
$this->_handleJsonError($errno);
} else if ($json === 'null' && $input !== null) {
throw new Exception('Null result with non-null input');
}
return $json;
}
function urlsafeB64Decode($input)
{
$remainder = strlen($input) % 4;
if ($remainder) {
$padlen = 4 - $remainder;
$input .= str_repeat('=', $padlen);
}
return base64_decode(strtr($input, '-_', '+/'));
}
function urlsafeB64Encode($input)
{
return str_replace('=', '', strtr(base64_encode($input), '+/', '-_'));
}
function _handleJsonError($errno)
{
$messages = array(
JSON_ERROR_DEPTH => 'Maximum stack depth exceeded',
JSON_ERROR_CTRL_CHAR => 'Unexpected control character found',
JSON_ERROR_SYNTAX => 'Syntax error, malformed JSON'
);
throw new Exception(
isset($messages[$errno])
? $messages[$errno]
: 'Unknown JSON error: ' . $errno
);
}
}
class Rapira {
private $token = "";
public $private_key = '';
public $uid = '';
public $hosts = '';
public $host_type = 0;
function __construct($private_key='', $uid='', $host_type=0){
$this->hosts = array(
'0' => array(
'api' => 'api.rapira.net',
),
'1' => array(
'api' => 'api.rapira.org',
),
);
$this->host_type = intval($host_type);
$this->private_key = trim($private_key);
$this->uid = trim($uid);
$this->set_token();
}
function set_token(){
$token = trim($this->token);
if (!$token) {
$request = array('exp' => time() + 3600, 'jti' => bin2hex(random_bytes(12)));
$class = new JWT();
$payload = $class->encode($request, base64_decode($this->private_key, true));
$post_data = array('kid' => $this->uid, 'jwt_token' => $payload);
$json_data = json_encode($post_data);
$headers = array(
'Content-Type: application/json',
);
$host = $this->hosts[$this->host_type]['api'];
if($ch = curl_init()){
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:65.0) Gecko/20100101 Firefox/65.0');
curl_setopt($ch, CURLOPT_URL, "https://{$host}/open/generate_jwt");
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $json_data);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_TIMEOUT, 20);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 20);
$err = curl_errno($ch);
$result = curl_exec($ch);
curl_close($ch);
$res = @json_decode($result, true);
if (isset($res['token'])) {
$this->token = $res['token'];
}
}
}
}
function create_address($currency, $amount, $nonce){
$currency = trim(strtolower($currency));
$post = array(
'currency' => $currency,
'amount' => $amount,
'nonce' => $nonce
);
$res = $this->request('/open/deposit_address?currency=' . $currency.'&amount='.$amount.'&nonce='.$nonce, $post);
$data = array();
if (isset($res['id'], $res['address']) and !$res['address']) {
$id = intval($res['id']);
for ($i = 1; $i <= 5; $i++) {
sleep(2);
$res2 = $this->request('/open/deposit_address/details?id=' . $id, array());
if (isset($res2['address'])) {
$data['address'] = $res2['address'];
break;
}
}
} elseif (isset($res['id'], $res['address']) and $res['address']) {
$data['address'] = $res['address'];
}
return $data;
}
function get_history_deposits($limit) {
$limit = intval($limit);
$post = array( "pageNo" => 0, "pageSize" => $limit);
$res = $this->request('/open/deposit/records', $post, "multipart/form-data");
$trans = array();
if (is_array($res) and !isset($res['error']) and $res['code'] != 500 and isset($res['data']['content'])) {
$trans = $res['data']['content'];
}
return $trans;
}
function stop_use($address, $nonce, $status) {
$post = array("address" => $address, "nonce" => $nonce, "status" => $status);
$res = $this->request('/open/deposit_address/use/stop', $post, "multipart/form-data");
if ($res['message'] == "Success unuse address" || $res['message'] == "Already unused" || $res['message'] == "Can't unuse address" || str_starts_with($res['message'], "Can't unuse address because start with other bid=")) { // && $res['code'] != 400 || address is empty || unknown address
return true;
}
return false; // "Already close address by id {externalId}"
}
function start_use($address, $nonce, $status) {
$post = array("address" => $address, "nonce" => $nonce, "status" => $status);
$res = $this->request('/open/deposit_address/use/start', $post, "multipart/form-data");
if ($res['message'] == "Success use address"|| $res['message'] == "Can't use address") { // && $res['code'] != 400 || address is empty || unknown address
return true;
}
return false;
}
function request($method, $post=array(), $content_type="application/json"){
$json_data = '';
$headers = array(
"Content-Type: ".$content_type,
"Authorization: Bearer {$this->token}"
);
$host = $this->hosts[$this->host_type]['api'];
if($ch = curl_init()){
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_USERAGENT, 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:65.0) Gecko/20100101 Firefox/65.0');
curl_setopt($ch, CURLOPT_URL, 'https://' . $host . $method);
if (is_array($post) and count($post) > 0) {
if ($content_type=="application/json") { $post = json_encode($post); }
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
}
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_TIMEOUT, 20);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 20);
$err = curl_errno($ch);
$result = curl_exec($ch);
curl_close($ch);
$res = @json_decode($result, true);
return $res;
}
return '';
}
}
$private_key = "";
$uid= "";
$class = new Rapira($private_key, $uid);
$result = $class->create_address('usdttrc20', 1000, 'exchanger.ru_123456');
print_r($result);
const axios = require("axios"); // npm i axios
const jwt = require("jsonwebtoken"); // npm i jsonwebtoken
const crypto = require("crypto");
// Константы
const host = "api.rapira.net";
const privateKey = ""; // приватный ключ, полученный на этапе создания API ключей
const uid = ""; // UID, полученный на этапе создания API ключей
// Получаем токен
const getToken = async () => {
try {
let { data } = await axios.post(
"https://" + host + "/open/generate_jwt",
{
kid: uid,
jwt_token: jwt.sign(
{
exp: Math.round(Date.now() / 1000) + 30 * 60, // JWT Request TTL: 30 minutes
jti: crypto.randomBytes(12).toString("hex"),
},
new Buffer.from(privateKey, "base64").toString("ascii"),
{ algorithm: "RS256" }
),
}
);
console.log("Your JWT token is:", data.token)
return data.token;
} catch (e) {
console.error(e);
return false;
}
};
// Тест работоспособности
(async () => {
try {
let { data } = await axios.post(
"https://" + host + "/open/deposit_address?currency=usdt-trc20",
null,
{
headers: {
Authorization: `Bearer ${await getToken()}`,
},
}
);
console.log(data);
} catch (e) {
console.error(e.message, e.response.data.error);
}
})();
