Saltar a contenido

Autenticación de aplicación y cuenta

El proceso de autenticación de Open API de cTrader se basa en el estándar OAuth 2.0.

Este marco permite que las aplicaciones de terceros obtengan acceso limitado a un servicio, ya sea en nombre del propietario del recurso, mediante la organización de una interacción de aprobación entre el propietario del recurso y el servicio, o permitiendo que una aplicación de terceros obtenga acceso por sí misma.

Flujo de autenticación

Según el estándar OAuth 2.0, la autenticación de cuenta requiere tanto un código de autorización como un token de acceso.

Definir tokens

Un código de autorización es un token de corto plazo que se emite para un cTID individual. Su período de expiración es de un minuto. Un token de acceso es un token de largo plazo que permite que una aplicación envíe y reciba mensajes hacia y desde el backend de cTrader. Después de recibirlo, un código de autorización debe intercambiarse rápidamente por un token de acceso; posteriormente, todos los mensajes enviados al backend de cTrader deben estar firmados con el token de acceso recibido para autenticar su aplicación. El período de expiración de un token de acceso es de 2.628.000 segundos (aproximadamente 30 días). Después de que expire, se puede generar un nuevo token de acceso utilizando un token de actualización. El token de actualización no tiene período de expiración.

Típicamente, el proceso de alguien nuevo que comienza a usar su aplicación por primera vez se ve así:

1. Un usuario con un determinado cTID accede a su aplicación donde sea que esté implementada; el usuario interactúa con un botón de acción o equivalente.

2. La aplicación utiliza un navegador integrado (o cualquier otro medio adecuado) para redirigir al usuario a un URI específico donde otorgará los permisos necesarios a la aplicación.

Ganar confianza

Antes de redirigir al usuario a este URI, asegúrese de que el usuario confíe en su aplicación y sea consciente de que necesitará proporcionar permisos adicionales.

3. El usuario es transferido a una URL de redirección predefinida. Esta URL contiene el token de acceso como valor del parámetro de consulta code.

4. El usuario es transferido de vuelta a la aplicación ya sea por su propia voluntad o automáticamente. La aplicación es informada del valor del parámetro code.

5. La aplicación envía una solicitud para intercambiar el código de autorización por un token de acceso a un punto final específico.

6. La aplicación recibe una respuesta que contiene el token de acceso como valor de la clave accessToken.

7. La aplicación envía el mensaje ProtoOAApplicationAuthReq que contiene los campos clientId y clientSecret.

8. La aplicación envía el mensaje ProtoOAGetAccountListByAccessTokenReq que contiene el campo accessToken. La respuesta (ProtoOAGetAccountListByAccessTokenRes) contiene el campo repetido ctidTraderAccountId.

9. Después de recibir una respuesta, la aplicación envía el mensaje ProtoOAAccountAuthReq que contiene los campos ctidTraderAccountId y accessToken.

Posteriormente, el usuario debe estar autenticado bajo la cuenta cuyo ctidTraderAccountId coincida con el ctidTraderAccountId proporcionado durante el paso 8.

El diagrama a continuación explica cómo funciona el flujo de autenticación básico desde la perspectiva de su aplicación Open API.

graph TB
  A([Redirigir al usuario a una <br/> URI específica]) ==> B([Recibir el código de <br/> autorización]); 
  B ==> C([Enviar una solicitud <br/> para obtener <br/> un código de acceso]); 
  C ==> D([Enviar el <br/> mensaje <br/> ProOAApplicationAuthReq]); 
  D ==> E([Enviar el <br/> mensaje <br/> ProtoOAAccountAuthReq]);

En las subsecciones siguientes, explicamos los pasos clave del flujo de autenticación en detalle.

Agregar un URI de redirección

Como se mostró anteriormente, su aplicación necesita obtener un código de autorización después de que un usuario es enviado a un determinado URI de redirección. Este URI incluirá el código de autorización como valor del parámetro de consulta code.

Para agregar un nuevo URI de redirección, haga lo siguiente:

1. Abra la página Aplicaciones en el portal de Open API.

2. Seleccione el botón Editar en la fila con la aplicación a la que desea agregar una URL de redirección.

3. En la nueva pantalla que aparece, desplácese hacia abajo hasta la sección URI de redirección.

4. Agregue una URL de redirección en un campo de entrada de texto vacío disponible. Si no se muestran campos disponibles, seleccione el botón Agregar URI de redirección.

5. Seleccione el botón Guardar en la parte inferior de la página para aplicar sus cambios.

Administrar URI de redirección

El primer URI de redirección es para el servicio Playground que le permite probar su aplicación antes de dar acceso a los usuarios regulares. Nunca debe usarse para una aplicación de producción. Puede agregar un número ilimitado de URI de redirección si es necesario.

Obtener el código de autorización

Para recibir un código de autorización para un cTID específico, su aplicación deberá enviar un usuario al siguiente URI.

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

Nota

En esta etapa, el usuario deberá permitir que su aplicación o servicio acceda a sus cuentas de operaciones. Como resultado, es imperativo que proporcione al usuario una comprensión completa de lo que requerirá el uso de su aplicación o servicio en cuanto a permisos, almacenamiento de datos y procesamiento de datos.

Este URI tiene los siguientes parámetros de consulta.

Parámetro ¿Obligatorio? Definición
client_id El identificador único de su aplicación Open API.
redirect_uri Un URI de redirección válido especificado en la configuración de su aplicación.
scope El alcance de los permisos que desea otorgar a su aplicación. Se aceptan los siguientes valores:
accounts. Se otorga acceso de solo lectura. Su aplicación podrá acceder a la información y las estadísticas de la cuenta; será imposible realizar operaciones.
trading. Se otorga acceso completo a la información y las estadísticas de la cuenta, así como a todas las operaciones permitidas.
product No Si este parámetro se especifica y se establece en web, la pantalla de autorización carece de encabezado y pie de página, lo que la hace verse mejor en dispositivos móviles. Si bien el parámetro es opcional, recomendamos establecerlo en web.

Para ver su client_id, vaya a la página Aplicaciones y seleccione el botón Ver en la columna Credenciales.

Después de que un usuario es enviado al URI anterior (y siempre que ambos parámetros sean válidos), debería ver una pantalla de inicio de sesión/registro que le solicita autorizar bajo su cTID. Después de eso, se le mostrará al usuario un cuadro de diálogo donde podrá permitir que la aplicación obtenga acceso a una o más cuentas vinculadas a su cTID.

Cuando el usuario seleccione el botón Permitir acceso, será redirigido al redirect_uri que especificó originalmente. Como se muestra en el ejemplo a continuación, el código de autorización se agregará a este URI como un parámetro de consulta.

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

En este punto, su aplicación necesitaría acceder y almacenar el valor del parámetro code. Debe intercambiarse rápidamente con un token de acceso antes de que caduque el código de autorización.

Cuentas adicionales

Si un usuario crea cuentas adicionales después de completar las acciones descritas anteriormente, estas cuentas no se autorizarán dentro de la aplicación. En su lugar, el usuario deberá ser redirigido nuevamente a la URL proporcionada anteriormente para que pueda dar acceso a la aplicación a cualquier cuenta adicional que haya creado desde el último inicio de sesión.

Autenticación a través de Google

Si la URI anterior se abre a través de WebView y el usuario elige Google para iniciar sesión, Google mostrará una página de Acceso bloqueado, impidiendo que el usuario continúe.

Para evitar esto, asegúrese de que la firma user-agent del dispositivo que abre la página se vea de la siguiente manera.

'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'

Obtener un token de acceso

Para obtener un token de acceso, realice la siguiente llamada a la API REST.

URL relativa

La URL de la solicitud es relativa a https://openapi.ctrader.com.

Método URL
GET apps/token

Esta solicitud incluye los siguientes parámetros de consulta.

Parámetro ¿Obligatorio? Definición
grant_type El tipo de token enviado a este endpoint. Se aceptan los siguientes valores.
authorization_code. Se envía un código de autorización al endpoint para intercambiarlo por un token de acceso.
refresh_token. Se envía un token de actualización al endpoint para actualizar un token de acceso existente.
code No El token enviado al endpoint. Este parámetro es obligatorio si grant_type=authorization_code.
redirect_uri No Un URI de redirección válido especificado en la configuración de su aplicación. Este parámetro es obligatorio si grant_type=authorization_code.
client_id El identificador único de su aplicación Open API.
client_secret La clave secreta asignada a su aplicación Open API.

El ejemplo de solicitud se puede encontrar a continuación.

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'

Para ver su client_secret, regrese a la página Aplicaciones y seleccione el botón Ver en la columna Credenciales.

Tras una solicitud exitosa, debería recibir una respuesta con las siguientes claves.

Clave Tipo de valor Definición
"accessToken" string El token de acceso que su aplicación utilizará para autenticar los mensajes enviados a cTrader Open API.
"tokenType" string El tipo de token de acceso (bearer"" debe ser el valor de esta clave ya que se utiliza el estándar REST para realizar la solicitud)."
"expiresIn" integer El número de segundos que deben pasar antes de que expire el token de acceso (por defecto, el valor de esta clave es igual a 2628000).
"refreshToken" string El token de actualización que debe utilizarse para renovar el token de acceso una vez que expire. El token de actualización no tiene tiempo de expiración por sí mismo.
"errorCode" string/null El código de error que describe por qué una solicitud no tuvo éxito. Para una solicitud exitosa, el valor de esta clave debe ser null.
"description" string/null La descripción de un error que ha ocurrido durante una solicitud sin éxito. Para una solicitud exitosa, el valor de esta clave debe ser null.

Para ver un ejemplo de una respuesta exitosa, consulte el fragmento a continuación.

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

Enviar los mensajes ProtoBuf requeridos

Después de recibir un código de acceso válido, su aplicación deberá enviar los mensajes ProtoOAApplicationAuthReq, ProtoOAGetAccountListByAccessTokenReq y ProtoOAAccountAuthReq. Esto se puede hacer de la siguiente manera.

 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)

Actualizar el token de acceso

Después de que un token de acceso caduque, deberá renovarlo usando el refreshToken que recibió anteriormente. Puede realizar esta acción mediante dos métodos diferentes.

Enviar una solicitud HTTP

Para obtener un nuevo token de acceso (y, posteriormente, un nuevo token de actualización), puede realizar la misma solicitud HTTP mencionada anteriormente. Como se muestra en el ejemplo a continuación, deberá establecer el parámetro de consulta grant_type en 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'

Recibirá una respuesta que contiene los nuevos valores de las claves accessToken y refreshToken. Puede usar estos nuevos valores de forma segura mientras que los valores antiguos de las mismas claves se invalidan automáticamente.

Enviar un mensaje Protobuf

Alternativamente, puede enviar el ProtoOARefreshTokenReq y recibir el mensaje ProtoOARefreshTokenRes que contiene nuevos tokens válidos.

 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")

Usar el Playground

El Playground proporciona un medio rápido para obtener un token de acceso para su propio cTID, lo que le permite desarrollar y probar su aplicación de forma rápida y sencilla antes de distribuirla entre su público objetivo.

Para acceder al Playground, vaya a la página Aplicaciones y seleccione el botón Playground. En la ventana que aparece, seleccione el alcance de la aplicación y haga clic en el botón Obtener token.

Después, debería ver la siguiente página.

Puede usar el token de acceso y el token de actualización para enviar mensajes a la API mientras está autenticado con su propio cTID.