Руководство по интеграции
Общее описание
Данный документ описывает общие принципы работы с командами API платежной системы paytocrypt
, а именно:
- формат команд;
- работу с ошибками;
- аутентификация.
Формат команд
API системы paytocrypt
построено с использованием REST-API
, где тип операции определяется по пути и методу HTTP-запроса, а данные операций содержатся в JSON-формате в теле HTTP-запросов и ответов. Аутентификация осуществляется с использованием соответствующих токенов, передаваемых в HTTP-заголовках (см. ниже).
Описание команд самого REST-API
для проведения транзакций приводится в отдельном документе.
Обработка ошибок
В случае ошибки сервер возвращает HTTP-статус с кодом большим или равным 400. В случае получения такого кода необходимо проверить тело отклика. Стандартные ответы ошибок сервера имеют формат JSON-документов со строковыми полями:
code
message
details
(может отсутствовать)data
(может отсутствовать)
Пример:
{
"code":"login_credentials_required",
"message":"Credentials hash must be provided in request",
"details":"hash not found in header",
"data":{}
}
Поле code
содержит код ошибки. Поле message
содержит текстовое описание ошибки, которое можно показывать пользователю. Поле details
может содержать дополнительные сведения об ошибки. Поле data
может содержать дополнительные данные об ошибке в виде JSON-объекта.
При получении от сервера ответа с HTTP-статусом >=400 необходимо выполнить следующие шаги.
Попробовать десериализовать JSON-тело ответа в соответствии с форматом, приведенным выше. Если десериализация не удается, то это означает, что ошибка выявлена либо на стороне клиента, либо на уровне сети, либо сервер недоступен. В таком случае необходимо отображать пользователю ошибку как есть из тела отклика.
Проверить
code
ошибки в обработчиках схем аутентификации в соответствии с правилами, приведенными ниже для каждой схемы. Для части кодов ошибок схем аутентификации необходимо выполнить дополнительные действия со стороны клиента, после чего повторить запрос с теми же данными, но заполненными или обновленными полями заголовка запроса.Во всех остальных случаях обрабатывать ошибку в рамках текущей операции. В большинстве случаев это означает, что необходимо просто показать пользователю сообщение об ошибке из поля
message
. Но, возможно, какие-то операции требуют специальной дополнительной обработки ошибки.
Схема аутентификации
Аутентификация работает с использованием специальных дополнительных полей в заголовках запросов HTTP.
Аутентификация с использованием токенов
Получение токенов аутентификации
Получить токены можно, выполнив авторизацию с помощью логина и пароля. Авторизация выполняется в два запроса:
Клиент производит запрос
POST /auth/login
с HTTP-заголовкомX-Auth-Login
, в котором указывает логин пользователя. Пример:curl -v -i https://example.com/api/v1.0.0/auth/login \ -X POST \ -H "Content-Type: application/json" \ -H "X-Auth-Login: user1@example.com"
Сервер в ответ вернет ошибку
login_credentials_required
, при этом ответ содержит HTTP-заголовокX-Auth-Login-Salt
, в котором записана соль для вычисления хэша от пароля. Пример:Header: X-Auth-Login-Salt: AVast5zVNKoVJoPQ Data: {"code":"login_credentials_required","message":"Credentials hash must be provided in request","details":""}
Клиент должен вычислить хэш по формуле
hash=base64(sha256(salt+password))
, гдеsalt
иpassword
объединяются в одну строку без разделителей, после чего строка подается на вход hash-функции.Пример на Golang:
salt="AVast5zVNKoVJoPQ"; // значение salt в реальных условиях следует брать из заголовка X-Auth-Login-Salt password="12345678"; str := salt+password hh := sha256.New() hh.Write([]byte(str)) hashed := hh.Sum(nil) phash := base64.StdEncoding.EncodeToString(hashed)
Пример на PHP:
$salt="AVast5zVNKoVJoPQ"; // значение salt в реальных условиях следует брать из заголовка X-Auth-Login-Salt $password="12345678"; $str = $salt.$password; // строка str равна "AVast5zVNKoVJoPQ12345678" $phash = base64_encode(hash('sha256', $str, true)); // USX0DFXfMu6bQLE26Mbdx/B+7G15lf+YID74+ZKtY5A=
Затем на сервер отправляется повторный запрос, в котором установлены HTTP-заголовки
X-Auth-Login
иX-Auth-Login-Phash
:curl -v -i https://example.com/api/v1.0.0/auth/login \ -X POST \ -H "Content-Type: application/json" \ -H "X-Auth-Login: user1@example.com" \ -H "X-Auth-Login-Phash: USX0DFXfMu6bQLE26Mbdx/B+7G15lf+YID74+ZKtY5A="
В случае успешного логина сервер вернет HTTP-статус 200. Ответ будет содержать токен доступа в HTTP-заголовке X-Auth-Access-Token
и токен обновления в HTTP-заголовке X-Auth-Refresh-Token
. Пример:
X-Auth-Access-Token: aFSaDr2gRD6FDCw4OfgOMWUBJpCjqt31u5EcK6njFxg77rsnFaCCwUibtqHCYhGWXOcM6+AGJaEa/Iw5yW33v2XHzzdBruUEnAMqIInPaEw s2RsOcpQPAK+l0FconDqrgy0YbWsuikck/giV54iUluLYNYZSslzreBemOiwM6oqP1JLWHH9aAtKYbnhX0J9ewVDbHXso2sJKI5SL6aEMcYjGDLD0k4pw3JSL/yRVd0qbcj9bZfkUjyHcgSD6KmMMrNX9RZzcXzbvhR5L66WdfCYuXxdnu72bKUqT7es/+8X2mX0=
X-Auth-Refresh-Token: CDxVrL3rN8IAqPKgK1Rx9eeqz76haZS1QNQZaK9thz9WB/ptqQpuTmkpxiwHzVcnchLr/MDcgjJqvYahz1pkg2TojKowoAfUYeCYgnBA1s5BEFdSKLIB/Uv31poQfU+8zF931Pi4Wl2FPqzs9B99rHUCRGcEfc5zV8Qvf0kAmtkZnNeXtLlvd5EvI2PbsJKq6aLwBMzo37xJSYbQUECjG6IY+RLV4Dej6MwSAmRcGU3xQ8n1w+hRQ1XO+QfEe2KenCb53TuGWcwMwoRN4ee6v3KJPsOtj5k6RE1bnDJKqeWH3SQ=
В случае неверного логина или пароля сервер вернет ошибку login_failed
, которую надо отобразить пользователю и проверить правильность написания логина или пароля.
Обновление X-Auth-Access-Token
Для обновления токена доступа можно использовать команду POST /auth/refresh
без необходимости повторной авторизации и получения токенов до тех пор, пока токен обновления не устареет. Пример:
curl -v -i https://example.com/api/v1.0.0/auth/refresh \
-X POST \
-H "Content-Type: application/json" \
-H "X-Auth-Refresh-Token: CDxVrL3rN8IAqPKgK1Rx9eeqz76haZS1QNQZaK9thz9WB/ptqQpuTmkpxiwHzVcnchLr/MDcgjJqvYahz1pkg2TojKowoAfUYeCYgnBA1s5BEFdSKLIB/Uv31poQfU+8zF931Pi4Wl2FPqzs9B99rHUCRGcEfc5zV8Qvf0kAmtkZnNeXtLlvd5EvI2PbsJKq6aLwBMzo37xJSYbQUECjG6IY+RLV4Dej6MwSAmRcGU3xQ8n1w+hRQ1XO+QfEe2KenCb53TuGWcwMwoRN4ee6v3KJPsOtj5k6RE1bnDJKqeWH3SQ="
Заголовки в ответе:
X-Auth-Access-Token: aFSaDr2gRD6FDCw4OfgOMWUBJpCjqt31u5EcK6njFxg77rsnFaCCwUibtqHCYhGWXOcM6+AGJaEa/Iw5yW33v2XHzzdBruUEnAMqIInPaEws2RsOcpQPAK+l0FconDqrgy0YbWsuikck/giV54iUluLYNYZSslzreBemOiwM6oqP1JLWHH9aAtKYbnhX0J9ewVDbHXso2sJKI5SL6aEMcYjGDLD0k4pw3JSL/yRVd0qbcj9bZfkUjyHcgSD6KmMMrNX9RZzcXzbvhR5L66WdfCYuXxdnu72bKUqT7es/+8X2mX0=
X-Auth-Refresh-Token: CDxVrL3rN8IAqPKgK1Rx9eeqz76haZS1QNQZaK9thz9WB/ptqQpuTmkpxiwHzVcnchLr/MDcgjJqvYahz1pkg2TojKowoAfUYeCYgnBA1s5BEFdSKLIB/Uv31poQfU+8zF931Pi4Wl2FPqzs9B99rHUCRGcEfc5zV8Qvf0kAmtkZnNeXtLlvd5EvI2PbsJKq6aLwBMzo37xJSYbQUECjG6IY+RLV4Dej6MwSAmRcGU3xQ8n1w+hRQ1XO+QfEe2KenCb53TuGWcwMwoRN4ee6v3KJPsOtj5k6RE1bnDJKqeWH3SQ=
При устаревании X-Auth-Refresh-Token
, следует авторизоваться повторно и получить новую пару токенов. Срок жизни X-Auth-Access-Token
составляет 24 часа, X-Auth-Refresh-Token
- 30 дней.
Работа с токенами аутентификации
Каждый запрос через API к серверу аутентифицируется с использованием токена доступа в HTTP-заголовке X-Auth-Access-Token
. То есть все запросы к серверу в рамках API должны включать заполненный заголовок X-Auth-Access-Token
. Основные принципы использования токенов сводятся к следующему:
Первый раз клиент получает токен доступа в ответе от сервера в результате успешно пройденной процедуры авторизации.
Клиент должен отслеживать поле заголовка
X-Auth-Access-Token
во всех ответах с сервера. В случае наличия такого заголовка в ответе с сервера необходимо сохранить и использовать новый полученный токен доступа для всех последующих запросов к серверу.Для длительного сохранения авторизации можно хранить токен обновления, полученный с сервера в HTTP-заголовке
X-Auth-Refresh-Token
в результате авторизации. Этот токен используется для регулярного обновления токена доступа командойPOST /auth/refresh
. Обновление токена необходимо производить при получении от сервера ошибкиauth_token_expired
на любой запрос, кроме самого запросаPOST /auth/refresh
. Если на сам запрос обновленияPOST /auth/refresh
сервер вернул ошибкуauth_token_expired
, это означает, что токен обновления также устарел и необходимо заново логиниться в систему. ЗаголовокX-Auth-Refresh-Token
необходимо проверять в каждом отклике от сервера, и если он там есть, то переписывать соответствующий токен в локальном хранилище и в дальнейшем использовать только новый токен обновления.При ошибках
auth_token_invalid
илиsession_expired
необходимо заново проводить процедуру авторизации.
Прекращение авторизации
Деавторизация происходит автоматически после устаревания токенов доступа и обновления.
Также можно выполнить запрос POST /auth/logout
. Данный запрос должен содержать HTTP-заголовок X-Auth-Access-Token
. Пример:
curl -v -i https://example.com/api/v1.0.0/auth/logout \
-X POST \
-H "Content-Type: application/json" \
-H "X-Auth-Access-Token: aFSaDr2gRD6FDCw4OfgOMWUBJpCjqt31u5EcK6njFxg77rsnFaCCwUibtqHCYhGWXOcM6+AGJaEa/Iw5yW33v2XHzzdBruUEnAMqIInPaEws2RsOcpQPAK+l0FconDqrgy0YbWsuikck/giV54iUluLYNYZSslzreBemOiwM6oqP1JLWHH9aAtKYbnhX0J9ewVDbHXso2sJKI5SL6aEMcYjGDLD0k4pw3JSL/yRVd0qbcj9bZfkUjyHcgSD6KmMMrNX9RZzcXzbvhR5L66WdfCYuXxdnu72bKUqT7es/+8X2mX0="
Цифровая подпись команд
Некоторые команды API могут дополнительного требовать использования цифровой подписи, алгоритм формирования которой описан в разделе Формирование подписи этого документа
Полученное в результате генерации подписи значение заносится в HTTP-заголовок X-Auth-Signature
:
curl -v -i https://example.com/api/v1.0.0/creation-service/create-object \
-X POST \
-H "Content-Type: application/json" \
-H "X-Auth-Access-Token: aFSaDr2gRD6FDCw4OfgOMWUBJpCjqt31u5EcK6njFxg77rsnFaCCwUibtqHCYhGWXOcM6+AGJaEa/Iw5yW33v2XHzzdBruUEnAMqIInPaEws2RsOcpQPAK+l0FconDqrgy0YbWsuikck/giV54iUluLYNYZSslzreBemOiwM6oqP1JLWHH9aAtKYbnhX0J9ewVDbHXso2sJKI5SL6aEMcYjGDLD0k4pw3JSL/yRVd0qbcj9bZfkUjyHcgSD6KmMMrNX9RZzcXzbvhR5L66WdfCYuXxdnu72bKUqT7es/+8X2mX0=" \
-H "X-Auth-Signature: A91jmqj28/8t3J4DSTwTvGDTh4JnJGK2kcI9f906e2JMF/iX7K3FKDj8MWCQLxrfZOgYbZNKgpj+vqColYsD/v2npoCNbGsBsUfo2/e3SFOg7Xku0uUrVGL+AWsA8zN4AFcfbYJ+ho5ZX8b+gHPmiJLsb2Ea3852gGTZbFVi7QuCPCbnAWld+O5sxKal/KFCIbo+Qb7hZHiGLc05ruvbo4zB8xnsWcEbw/TKRaST3p4M9qLY96afaS6pxT2Bujh8bekS0yFmlLTcd9Q14Mqu2jyziYgAhPq7F+K298Lod3hpsGbZGjclOdLY1avFOPzAOE4ztFCse0dGp51CdIqNZA==" \
-d '{"field1":"value1","field2":100}'
Подготовка ключей
Для подписи запросов необходимо предварительно сгенерировать ключевую пару RSA и передать поставщику услуг публичный ключ от сгенерированной пары. Ключевая пара может быть сгенерирована с использованием команды openssl:
openssl genrsa -out private_key.pem 3072
openssl rsa -in private_key.pem -outform PEM -pubout -out public_key.pem
Формирование подписи
Подпись запроса к серверу вычисляется следующим образом:
- Вычисляется значение хэш-функции SHA-256 строки, полученой путем конкатенации содержимого HTTP-пакета (body), метода запроса и пути запроса в рамках API:
str = body + method + path hash = SHA256(str)
- Полученное значение хэш-функции подписывается с использованием приватного RSA-ключа
- Результат кодируется в строку base64
Пример на Golang:
// Подготовим приватный ключ:
pemData := []byte(`-----BEGIN RSA PRIVATE KEY-----
....
-----END RSA PRIVATE KEY-----`)
pemBlock, _ := pem.Decode(pemData)
key, err := x509.ParsePKCS1PrivateKey(pemBlock.Bytes)
if err != nil {
... // обработка ошибки
}
/*
Формируем строку для подписи, например, для запроса /payment/reverse:
{"order_id":"a701748f0851","order_date":"2022-04-10","transaction_id":"64510775012565440000","reason":"Some reason","reference_id":"r-124997"}POST/payment/reverse
*/
body := '{"order_id":"a701748f0851","order_date":"2022-04-10","transaction_id":"64510775012565440000","reason":"Some reason","reference_id":"r-124997"}'
method := "POST"
path := "/payment/reverse"
str := body + method + path
// Cчитаем хэш
hh := sha256.New()
hh.Write([]byte(str))
hash := hh.Sum(nil)
// Подписываем полученное значение с использованием приватного RSA-ключа
binSig, err := rsa.SignPKCS1v15(nil, key, crypto.SHA256, hash)
if err !=nil {
... // обработка ошибки
}
// Кодируем полученные бинарные данные в строку base64. Это результирующее значение:
sig := base64.RawStdEncoding.WithPadding(base64.StdPadding).EncodeToString(binSig)
В некоторых языках программирования стандартные функции цифровой подписи уже объединяют этап вычисления хэш-функции с вычислением цифровой подписи. Например, в PHP
функция openssl_sign()
выполняет предварительное вычисление хэша, а затем подписывает значение цифровой подписью.
Пример на PHP:
// Подготовка ключа и контрольной строки:
$key = "-----BEGIN RSA PRIVATE KEY-----
....
-----END RSA PRIVATE KEY-----";
$data = '{"order_id":"a701748f0851","order_date":"2022-04-10","transaction_id":"64510775012565440000","reason":"Some reason","reference_id":"r-124997"}'
."POST"
."/payment/reverse";
// Формирование подписи и получение результирующей строки:
if (openssl_sign($data, $binSig, $key, OPENSSL_ALGO_SHA256)) {
$sig = base64_encode($binSig);
}
else {
... // обработка ошибки формирования подписи
}
Во всех случаях результат вычисления цифровой подписи должен совпадать с результатом выполнения цепочки команд openssl
, где data.txt - файл с содержимым контрольной строки:
openssl dgst -sign key.pem -keyform PEM -sha256 -binary data.txt | openssl enc -base64