Перейти к содержанию

Аутентификация приложения и аккаунта

Процесс аутентификации cTrader Open API основан на стандарте OAuth 2.0.

Эта платформа позволяет сторонним приложениям получать ограниченный доступ к сервису либо от имени владельца ресурса путем организации взаимодействия по утверждению между владельцем ресурса и сервисом, либо позволяя стороннему приложению получать доступ от своего имени.

Процесс аутентификации

Согласно стандарту OAuth 2.0, аутентификация аккаунта требует как код авторизации, так и токен доступа.

Определение токенов

Код авторизации — это краткосрочный токен, который выдается для отдельного cTID. Срок его действия составляет одну минуту. Токен доступа — это долгосрочный токен, который позволяет приложению отправлять и получать сообщения в бэкенд cTrader и из него. После получения код авторизации необходимо быстро обменять на токен доступа; после этого все сообщения, отправляемые в бэкенд cTrader, должны быть подписаны полученным токеном доступа для аутентификации вашего приложения. Срок действия токена доступа составляет 2 628 000 секунд (приблизительно 30 дней). После истечения срока действия новый токен доступа может быть сгенерирован с помощью токена обновления. Токен обновления не имеет срока действия.

Обычно процесс начала использования вашего приложения новым пользователем выглядит следующим образом:

1. Пользователь с определенным cTID получает доступ к вашему приложению, где бы оно ни было развернуто; пользователь взаимодействует с кнопкой действия или эквивалентом.

2. Приложение использует встроенный браузер (или любое другое подходящее средство) для перенаправления пользователя на определенный URI, где он предоставит приложению необходимые разрешения.

Завоевание доверия

Перед перенаправлением пользователя на этот URI убедитесь, что пользователь доверяет вашему приложению и знает о том, что ему потребуется предоставить дополнительные разрешения.

3. Пользователь перенаправляется на предопределенный URL перенаправления. Этот URL содержит токен доступа в качестве значения параметра запроса code.

4. Пользователь возвращается в приложение либо самостоятельно, либо автоматически. Приложение получает информацию о значении параметра code.

5. Приложение отправляет запрос на обмен кода авторизации на токен доступа на определенную конечную точку.

6. Приложение получает ответ, содержащий токен доступа в качестве значения ключа accessToken.

7. Приложение отправляет сообщение ProtoOAApplicationAuthReq, содержащее поля clientId и clientSecret.

8. Приложение отправляет сообщение ProtoOAGetAccountListByAccessTokenReq, содержащее поле accessToken. Ответ (ProtoOAGetAccountListByAccessTokenRes) содержит повторяющееся поле ctidTraderAccountId.

9. После получения ответа приложение отправляет сообщение ProtoOAAccountAuthReq, содержащее поля ctidTraderAccountId и accessToken.

После этого пользователь должен быть аутентифицирован под аккаунтом, ctidTraderAccountId которого соответствует ctidTraderAccountId, предоставленному на шаге 8.

Диаграмма ниже объясняет, как работает базовый процесс аутентификации с точки зрения вашего приложения Open API.

graph TB
  A([Перенаправьте пользователя <br/> на заданный URI]) ==> B([Получите код <br/> авторизации]);
  B ==> C([Отправьте запрос <br/> на получение <br/> кода доступа]);
  C ==> D([Отправьте <br/> сообщение <br/> ProOAApplicationAuthReq]);
  D ==> E([Отправьте <br/> сообщение <br/> ProtoOAAccountAuthReq]);

В подразделах ниже мы подробно объясняем ключевые этапы процесса аутентификации.

Добавление URI перенаправления

Как показано ранее, вашему приложению необходимо получить код авторизации после того, как пользователь будет отправлен на определенный URI перенаправления. Этот URI будет включать код авторизации в качестве значения параметра запроса code.

Чтобы добавить новый URI перенаправления, выполните следующие действия:

1. Откройте страницу Приложения на портале Open API.

2. Нажмите кнопку Изменить в строке с приложением, в которое вы хотите добавить URL перенаправления.

3. На появившемся экране прокрутите вниз до раздела URI перенаправления.

4. Добавьте URL перенаправления в доступное пустое поле ввода текста. Если доступные поля не отображаются, нажмите кнопку Добавить URI перенаправления.

5. Нажмите кнопку Сохранить внизу страницы, чтобы применить изменения.

Управление URI перенаправления

Самый первый URI перенаправления предназначен для сервиса Playground, который позволяет вам протестировать приложение перед предоставлением доступа обычным пользователям. Он никогда не должен использоваться для производственного приложения. При необходимости вы можете добавить неограниченное количество URI перенаправления.

Получение кода авторизации

Чтобы получить код авторизации для конкретного cTID, ваше приложение должно отправить пользователя по следующему URI.

https://id.ctrader.com/my/settings/openapi/grantingaccess/?client_id={clientId}&redirect_uri={your_redirectURI}&scope={scope}&product=web

Примечание

На этом этапе пользователю необходимо будет разрешить вашему приложению или сервису доступ к его торговым счетам. В связи с этим крайне важно, чтобы вы предоставили пользователю полное понимание того, какие разрешения, хранение данных и обработка данных потребуются для использования вашего приложения или сервиса.

Этот URI имеет следующие параметры запроса.

Параметр Обязательно? Определение
client_id Да Уникальный идентификатор вашего приложения Open API.
redirect_uri Да Действительный URI перенаправления, указанный в настройках вашего приложения.
scope Да Область разрешений, которые вы хотите предоставить вашему приложению. Принимаются следующие значения:
accounts. Предоставляется доступ только для просмотра. Ваше приложение сможет получать доступ к информации о счете и статистике; выполнение торговых операций будет невозможно.
trading. Предоставляется полный доступ к информации о счете и статистике, а также ко всем разрешенным торговым операциям.
product Нет Если этот параметр указан и установлен как web, на экране авторизации отсутствуют верхний и нижний колонтитулы, что делает его более удобным для просмотра на мобильных устройствах. Хотя параметр является необязательным, мы рекомендуем установить его как web.

Чтобы просмотреть ваш client_id, перейдите на страницу Applications и нажмите кнопку View в столбце Credentials.

После того как пользователь будет отправлен по указанному выше URI (и при условии, что оба параметра действительны), он должен увидеть экран входа/регистрации с предложением авторизоваться под своим cTID. После этого пользователю будет показано диалоговое окно, в котором он сможет разрешить приложению получить доступ к одному или нескольким счетам, привязанным к его cTID.

Когда пользователь нажмет кнопку Allow access, он будет перенаправлен на redirect_uri, который вы указали изначально. Как показано в примере ниже, код авторизации будет добавлен к этому URI в качестве параметра запроса.

https://my-redirect-uri.com/?code=123ASDASffdg_as234_GCllkoq14adRB7_tvN

На этом этапе ваше приложение должно получить и сохранить значение параметра code. Его необходимо быстро обменять на токен доступа до истечения срока действия кода авторизации.

Дополнительные счета

Если пользователь создаст дополнительные счета после выполнения действий, описанных выше, эти счета не будут авторизованы в приложении. Вместо этого пользователя необходимо будет перенаправить обратно на URL, указанный выше, чтобы он мог предоставить приложению доступ к любым дополнительным счетам, которые он создал с момента последнего входа.

Аутентификация через Google

Если указанный выше URI открывается через WebView и пользователь выбирает Google для входа, Google отобразит страницу Access blocked, не позволяя пользователю продолжить.

Чтобы предотвратить это, убедитесь, что подпись user-agent устройства, открывающего страницу, выглядит следующим образом.

'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'

Получение токена доступа

Чтобы получить токен доступа, выполните следующий вызов REST API.

Относительный URL

URL запроса является относительным к https://openapi.ctrader.com.

Метод URL
GET apps/token

Этот запрос включает следующие параметры запроса.

Параметр Обязательно? Определение
grant_type Да Тип токена, отправляемого на эту конечную точку. Принимаются следующие значения.
authorization_code. Код авторизации отправляется на конечную точку для обмена на токен доступа.
refresh_token. Токен обновления отправляется на конечную точку для обновления существующего токена доступа.
code Нет Токен, отправляемый на конечную точку. Этот параметр обязателен, если grant_type=authorization_code.
redirect_uri Нет Действительный URI перенаправления, указанный в настройках вашего приложения. Этот параметр обязателен, если grant_type=authorization_code.
client_id Да Уникальный идентификатор вашего приложения Open API.
client_secret Да Секретный ключ, назначенный вашему приложению Open API.

Пример запроса можно найти ниже.

curl -X GET 'https://openapi.ctrader.com/apps/token?grant_type=authorization_code&code=0ssdgds98as9_QSF56FVC_22dfdf&redirect_uri=https://spotware.com&client_id=5430012&client_secret=012sds23dlkjQsd' -H 'Accept: application/json' -H 'Content-Type: application/json'

Чтобы просмотреть ваш client_secret, вернитесь на страницу Applications и нажмите кнопку View в столбце Credentials.

При успешном запросе вы должны получить ответ со следующими ключами.

Ключ Тип значения Определение
"accessToken" строка Токен доступа, который ваше приложение будет использовать для аутентификации сообщений, отправляемых в cTrader Open API.
"tokenType" строка Тип токена доступа (значением этого ключа должно быть "bearer", так как для выполнения запроса используется стандарт REST).
"expiresIn" строка Количество секунд, которое должно пройти до истечения срока действия токена доступа (по умолчанию значение этого ключа равно 2628000).
"refreshToken" строка Токен обновления, который необходимо использовать для продления токена доступа после истечения его срока действия. Сам токен обновления не имеет срока действия.
"errorCode" string/null Код ошибки, описывающий причину неудачного запроса. Для успешного запроса значение этого ключа должно быть null.
"description" string/null Описание ошибки, возникшей во время неудачного запроса. Для успешного запроса значение этого ключа должно быть null.

Пример успешного ответа см. во фрагменте ниже.

{
    "accessToken":"mos8Bw3D4EG0fRPd4Eqq0JxaFT4zjd8e4YijNezh_ag",
    "tokenType":"bearer",
    "expiresIn":2628000,
    "refreshToken":"VCuafFhy81AFZjsWkbuEzdOhhRj5YTWz8fWUwHam7KM",
    "errorCode":null,
    "description":null,
}

Отправьте необходимые ProtoBuf сообщения

После получения действительного кода доступа ваше приложение должно будет отправить сообщения ProtoOAApplicationAuthReq, ProtoOAGetAccountListByAccessTokenReq и ProtoOAAccountAuthReq. Это можно сделать следующим образом.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
private static RepeatedField<ProtoOACtidTraderAccount> _ctidTraderAccounts;

List<IDisposable> _disposables = new();
_disposables.Add(_client.OfType<ProtoOAGetAccountListByAccessTokenRes>().Subscribe(OnAccountIdReceived));

private static void OnAccountIdReceived(ProtoOAGetAccountListByAccessTokenRes response)
{

    Console.WriteLine($"\nMessage Received:\n{response}");

    _ctidTraderAccounts = response.CtidTraderAccount;

    var accountAuthReq = new ProtoOAAccountAuthReq
    {
        CtidTraderAccountId = (long)_ctidTraderAccounts[0].CtidTraderAccountId,
        AccessToken = _token.AccessToken,
    };

    _client.SendMessage(accountAuthReq);

}

var _client = new OpenClient(host, ApiInfo.Port, TimeSpan.FromSeconds(10), useWebSocket: false);
var applicationAuthReq = new ProtoOAApplicationAuthReq
{
    ClientId = {your_client_id}, // Add your client ID here
    ClientSecret = {your_app_secret}, // Add your app secret here
};
await _client.SendMessage(applicationAuthReq);
await Task.Delay(5000);
var getAccountListByAccessToken = new ProtoOAGetAccountListByAccessTokenReq 
{
    AccessToken = {access_token} // Add your access token here
}
var accountAuthReq = new ProtoOAAccountAuthReq 
{
    ctidTraderAccountId = {account_id}, // Add the ctidTraderAccountId of the account you want to authorize here
    AccessToken = {access_token} // Add your access token here
};
await _client.SendMessage(accountAuthReq);
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
currentAccountId = None
client = Client(EndPoints.PROTOBUF_LIVE_HOST if hostType.lower() == "live" else EndPoints.PROTOBUF_DEMO_HOST, EndPoints.PROTOBUF_PORT, TcpProtocol)

def connected(client): # Callback for client connection
    print("\nConnected")
    request = ProtoOAApplicationAuthReq()
    request.clientId = appClientId
    request.clientSecret = appClientSecret
    deferred = client.send(request)



def disconnected(client, reason): # Callback for client disconnection
    print("\nDisconnected: ", reason)

def onMessageReceived(client, message): # Callback for receiving all messages
    global currentAccountId
    if message.payloadType in [ProtoOASubscribeSpotsRes().payloadType, ProtoOAAccountLogoutRes().payloadType, ProtoHeartbeatEvent().payloadType]:
        return
    elif message.payloadType == ProtoOAApplicationAuthRes().payloadType:
        print("API Application authorized\n")
        if currentAccountId is not None:
            sendProtoOAAccountAuthReq()
            return
        accountListReq = ProtoOAGetAccountListByAccessTokenReq()
        accountListReq.accessToken = accessToken
        deferred = client.send(accountListReq)
    elif message.payloadType == ProtoOAGetAccountListByAccessTokenRes().payloadType:
        protoOAGetAccountListByAccessTokenRes = Protobuf.extract(message)
        currentAccountId = int(protoOAGetAccountListByAccessTokenRes.ctidTraderAccount[0].ctidTraderAccountId)
        accountAuthReq = ProtoOAAccountAuthReq()
        accountAuthReq.ctidTraderAccountId = currentAccountId
        accountAuthReq.accessToken = accessToken
        deferred = client.send(accountAuthReq)
    elif message.payloadType == ProtoOAAccountAuthRes().payloadType:
        protoOAAccountAuthRes = Protobuf.extract(message)
        print(f"Account {protoOAAccountAuthRes.ctidTraderAccountId} has been authorized\n")
        print("This acccount will be used for all future requests\n")
    else:
        print("Message received: \n", Protobuf.extract(message))
    reactor.callLater(3, callable=executeUserCommand)

def onError(failure): # Call back for errors
    print("Message Error: ", failure)
    reactor.callLater(3, callable=executeUserCommand)

Обновите токен доступа

После истечения срока действия токена доступа вам нужно будет обновить его, используя refreshToken, полученный ранее. Вы можете выполнить это действие двумя различными способами.

Отправьте HTTP-запрос

Чтобы получить новый токен доступа (и, следовательно, новый токен обновления), вы можете выполнить тот же HTTP-запрос, описанный выше. Как показано в примере ниже, вам нужно будет установить параметр запроса grant_type в значение refresh_token.

curl -X POST 'https://openapi.ctrader.com/apps/token?grant_type=refresh_token&refresh_token=asdXCVCVAS_218kjashf_asdasd2ASD_223x&client_id=5430012&client_secret=012sds23dlkjQsd' -H 'Accept: application/json' -H 'Content-Type: application/json'

Вы получите ответ, содержащий новые значения ключей accessToken и refreshToken. Вы можете безопасно использовать эти новые значения, в то время как старые значения тех же ключей автоматически аннулируются.

Отправьте Protobuf сообщение

В качестве альтернативы вы можете отправить ProtoOARefreshTokenReq и получить сообщение ProtoOARefreshTokenRes, содержащее новые действительные токены.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
_disposables.Add(_client.OfType<ProtoOARefreshTokenRes>().Subscribe(OnRefreshTokenResponse));
private static void OnRefreshTokenResponse(ProtoOARefreshTokenRes response) 
{
    _token = new Token 
    {
        AccessToken = response.AccessToken,
        RefreshToken = response.RefreshToken,
        ExpiresIn = DateTimeOffset.FromUnixTimeMilliseconds(response.ExpiresIn),
        TokenType = response.TokenType,
    }
}
var refreshTokenReq = new ProtoOARefreshTokenReq
    {
        refreshToken = {your_refresh_token}, // Add your refresh token here
    };
await _client.SendMessage(applicationAuthReq);
1
newToken = auth.refreshToken("refresh_Token")

Используйте Playground

Playground предоставляет быстрый способ получения токена доступа для вашего собственного cTID, позволяя вам быстро и легко разрабатывать и тестировать ваше приложение перед его распространением среди целевой аудитории.

Чтобы получить доступ к Playground, перейдите на страницу Applications и нажмите кнопку Playground. В появившемся окне выберите область действия приложения и нажмите кнопку Get token.

После этого вы должны увидеть следующую страницу.

Вы можете использовать токен доступа и токен обновления для отправки сообщений в API, будучи авторизованным под вашим собственным cTID.