Aller au contenu

Authentification de l'application et du compte

Le processus d'authentification de l'Open API de cTrader est basé sur la norme OAuth 2.0.

Ce cadre permet aux applications tierces d'obtenir un accès limité à un service, soit au nom du propriétaire de la ressource, en orchestrant une interaction d'approbation entre le propriétaire de la ressource et le service, soit en permettant à une application tierce d'obtenir un accès en son propre nom.

Flux d'authentification

Conformément à la norme OAuth 2.0, l'authentification du compte nécessite à la fois un code d'autorisation et un jeton d'accès.

Définir les jetons

Un code d'autorisation est un jeton à court terme qui est émis pour un cTID individuel. Sa période d'expiration est d'une minute. Un jeton d'accès est un jeton à long terme qui permet à une application d'envoyer et de recevoir des messages vers et depuis le backend de cTrader. Après l'avoir reçu, un code d'autorisation doit être rapidement échangé contre un jeton d'accès ; par la suite, tous les messages envoyés au backend de cTrader doivent être signés avec le jeton d'accès reçu pour authentifier votre application. La période d'expiration d'un jeton d'accès est de 2 628 000 secondes (environ 30 jours). Après son expiration, un nouveau jeton d'accès peut être généré à l'aide d'un jeton de rafraîchissement. Le jeton de rafraîchissement n'a pas de période d'expiration.

Généralement, le processus pour qu'un nouvel utilisateur commence à utiliser votre application pour la première fois se déroule comme suit :

1. Un utilisateur avec un certain cTID accède à votre application où qu'elle soit déployée ; l'utilisateur interagit avec un bouton d'action ou équivalent.

2. L'application utilise un navigateur intégré (ou tout autre moyen approprié) pour rediriger l'utilisateur vers une URI spécifique où il donnera à l'application les autorisations nécessaires.

Gagner la confiance

Avant de rediriger l'utilisateur vers cette URI, assurez-vous que l'utilisateur fait confiance à votre application et qu'il est conscient du fait qu'il devra fournir des autorisations supplémentaires.

3. L'utilisateur est transféré vers une URL de redirection prédéfinie. Cette URL contient le jeton d'accès comme valeur du paramètre de requête code.

4. L'utilisateur est renvoyé vers l'application soit de son propre gré, soit automatiquement. L'application est informée de la valeur du paramètre code.

5. L'application envoie une demande d'échange du code d'autorisation contre un jeton d'accès à un point de terminaison spécifique.

6. L'application reçoit une réponse contenant le jeton d'accès comme valeur de la clé accessToken.

7. L'application envoie le message ProtoOAApplicationAuthReq contenant les champs clientId et clientSecret.

8. L'application envoie le message ProtoOAGetAccountListByAccessTokenReq contenant le champ accessToken. La réponse (ProtoOAGetAccountListByAccessTokenRes) contient le champ répété ctidTraderAccountId.

9. Après avoir reçu une réponse, l'application envoie le message ProtoOAAccountAuthReq contenant les champs ctidTraderAccountId et accessToken.

Par la suite, l'utilisateur devrait être authentifié sous le compte dont le ctidTraderAccountId correspond au ctidTraderAccountId fourni à l'étape 8.

Le diagramme ci-dessous explique comment fonctionne le flux d'authentification de base du point de vue de votre application Open API.

graph TB
  A([Rediriger l'utilisateur <br/> vers une URI spécifique]) ==> B([Recevoir le code <br/> d'autorisation]);
  B ==> C([Envoyer une demande <br/> pour obtenir <br/> un code d'accès]);
  C ==> D([Envoyer le <br/> message <br/> ProOAApplicationAuthReq]);
  D ==> E([Envoyer le <br/> message <br/> ProtoOAAccountAuthReq]);

Dans les sous-sections ci-dessous, nous expliquons en détail les étapes clés du flux d'authentification.

Ajouter une URI de redirection

Comme montré précédemment, votre application doit obtenir un code d'autorisation après qu'un utilisateur est envoyé vers une certaine URI de redirection. Cette URI inclura le code d'autorisation comme valeur du paramètre de requête code.

Pour ajouter une nouvelle URI de redirection, procédez comme suit :

1. Ouvrez la page Applications dans le portail Open API.

2. Sélectionnez le bouton Modifier dans la ligne de l'application à laquelle vous souhaitez ajouter une URL de redirection.

3. Dans l'écran nouvellement apparu, faites défiler jusqu'à la section URI de redirection.

4. Ajoutez une URL de redirection dans un champ de saisie vide disponible. Si aucun champ disponible n'est affiché, sélectionnez le bouton Ajouter une URI de redirection.

5. Sélectionnez le bouton Enregistrer en bas de la page pour appliquer vos modifications.

Gérer les URI de redirection

Le tout premier URI de redirection est destiné au service Playground qui vous permet de tester votre application avant de donner accès aux utilisateurs réguliers. Elle ne doit jamais être utilisée pour une application en production. Vous pouvez ajouter un nombre illimité d'URI de redirection si nécessaire.

Obtenir le code d'autorisation

Pour recevoir un code d'autorisation pour un cTID spécifique, votre application devra envoyer un utilisateur vers l'URI suivante.

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

Remarque

À ce stade, l'utilisateur devra autoriser votre application ou service à accéder à ses comptes de trading. Par conséquent, il est impératif que vous fournissiez à l'utilisateur une compréhension complète de ce que l'utilisation de votre application ou service nécessitera en termes d'autorisations, de stockage et de traitement des données.

Cette URI a les paramètres de requête suivants.

Paramètre Obligatoire ? Définition
client_id Oui L'identifiant unique de votre application Open API.
redirect_uri Oui Une URI de redirection valide spécifiée dans les paramètres de votre application.
scope Oui La portée des autorisations que vous souhaitez accorder à votre application. Les valeurs suivantes sont acceptées :
accounts. Un accès en lecture seule est accordé. Votre application pourra accéder aux informations et statistiques du compte ; l'exécution d'opérations de trading sera impossible.
trading. Un accès complet est accordé aux informations et statistiques du compte ainsi qu'à toutes les opérations de trading autorisées.
product Non Si ce paramètre est spécifié et défini sur web, l'écran d'autorisation n'a pas d'en-tête ni de pied de page, ce qui le rend plus esthétique sur les appareils mobiles. Bien que le paramètre soit facultatif, nous recommandons de le définir sur web.

Pour voir votre client_id, allez sur la page Applications et sélectionnez le bouton Voir dans la colonne Identifiants.

Après qu'un utilisateur est envoyé vers l'URI ci-dessus (et tant que les deux paramètres sont valides), il devrait voir un écran de connexion/inscription l'invitant à s'authentifier avec son cTID. Ensuite, un utilisateur verra une boîte de dialogue où il pourra autoriser l'application à accéder à un ou plusieurs comptes liés à son cTID.

Lorsque l'utilisateur sélectionne le bouton Autoriser l'accès, il sera redirigé vers l'redirect_uri que vous aviez spécifiée à l'origine. Comme montré dans l'exemple ci-dessous, le code d'autorisation sera ajouté à cette URI en tant que paramètre de requête.

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

À ce stade, votre application devrait accéder et stocker la valeur du paramètre code. Il doit être rapidement échangé contre un jeton d'accès avant que le code d'autorisation n'expire.

Comptes supplémentaires

Si un utilisateur crée des comptes supplémentaires après avoir effectué les actions décrites ci-dessus, ces comptes ne seront pas autorisés dans l'application. À la place, l'utilisateur devra être redirigé vers l'URL fournie ci-dessus afin de pouvoir donner à l'application l'accès à tous les comptes supplémentaires qu'il a créés depuis sa dernière connexion.

Authentification via Google

Si l'URI ci-dessus est ouverte via WebView et que l'utilisateur choisit Google pour se connecter, Google affichera une page Accès bloqué, empêchant l'utilisateur de poursuivre.

Pour éviter cela, assurez-vous que la signature user-agent de l'appareil ouvrant la page ressemble à ce qui suit.

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

Obtenir un jeton d'accès

Pour obtenir un jeton d'accès, effectuez l'appel API REST suivant.

URL relative

L'URL de la requête est relative à https://openapi.ctrader.com.

Méthode URL
GET apps/token

Cette requête inclut les paramètres de requête suivants.

Paramètre Obligatoire ? Définition
grant_type Oui Le type de jeton envoyé à ce point de terminaison. Les valeurs suivantes sont acceptées.
authorization_code. Un code d'autorisation est envoyé au point de terminaison pour l'échanger contre un jeton d'accès.
refresh_token. Un jeton de rafraîchissement est envoyé au point de terminaison pour rafraîchir un jeton d'accès existant.
code Non Le jeton envoyé au point de terminaison. Ce paramètre est obligatoire si grant_type=authorization_code.
redirect_uri Non Une URI de redirection valide spécifiée dans les paramètres de votre application. Ce paramètre est obligatoire si grant_type=authorization_code.
client_id Oui L'identifiant unique de votre application Open API.
client_secret Oui La clé secrète attribuée à votre application Open API.

L'exemple de requête peut être trouvé ci-dessous.

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'

Pour voir votre client_secret, retournez à la page Applications et sélectionnez le bouton Voir dans la colonne Identifiants.

Après une requête réussie, vous devriez recevoir une réponse avec les clés suivantes.

Clé Type de valeur Définition
"accessToken" string Le jeton d'accès que votre application utilisera pour authentifier les messages envoyés à l'Open API de cTrader.
"tokenType" string Le type du jeton d'accès ("bearer" devrait être la valeur de cette clé car la norme REST est utilisée pour faire la requête).
"expiresIn" integer Le nombre de secondes qui doivent s'écouler avant que le jeton d'accès n'expire (par défaut, la valeur de cette clé est égale à 2628000).
"refreshToken" string Le jeton de rafraîchissement qui doit être utilisé pour renouveler le jeton d'accès une fois qu'il expire. Le jeton de rafraîchissement n'a pas de durée d'expiration en soi.
"errorCode" string/null Le code d'erreur qui décrit pourquoi une requête a échoué. Pour une requête réussie, la valeur de cette clé devrait être null.
"description" string/null La description d'une erreur qui s'est produite lors d'une requête infructueuse. Pour une requête réussie, la valeur de cette clé devrait être null.

Pour un exemple de réponse réussie, voir l'extrait ci-dessous.

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

Envoyer les messages ProtoBuf requis

Après avoir reçu un code d'accès valide, votre application devra envoyer les messages ProtoOAApplicationAuthReq, ProtoOAGetAccountListByAccessTokenReq et ProtoOAAccountAuthReq. Cela peut être fait comme suit.

 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)

Rafraîchir le jeton d'accès

Après l'expiration d'un jeton d'accès, vous devrez le renouveler en utilisant le refreshToken que vous avez reçu précédemment. Vous pouvez effectuer cette action via deux méthodes différentes.

Envoyer une requête HTTP

Pour obtenir un nouveau jeton d'accès (et, par conséquent, un nouveau jeton de rafraîchissement), vous pouvez effectuer la même requête HTTP couverte ci-dessus. Comme montré dans l'exemple ci-dessous, vous devrez définir le paramètre de requête grant_type sur 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'

Vous recevrez une réponse contenant les nouvelles valeurs des clés accessToken et refreshToken. Vous pouvez utiliser en toute sécurité ces nouvelles valeurs tandis que les anciennes valeurs des mêmes clés sont automatiquement invalidées.

Envoyer un message Protobuf

Alternativement, vous pouvez envoyer le message ProtoOARefreshTokenReq et recevoir le message ProtoOARefreshTokenRes contenant de nouveaux jetons valides.

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

Utiliser le Playground

Le Playground fournit un moyen rapide d'obtenir un jeton d'accès pour votre propre cTID, vous permettant de développer et de tester rapidement et facilement votre application avant de la distribuer à son public cible.

Pour accéder au Playground, allez à la page Applications et sélectionnez le bouton Playground. Dans la fenêtre nouvellement apparue, sélectionnez la portée de l'application et cliquez sur le bouton Obtenir le jeton.

Ensuite, vous devriez voir la page suivante.

Vous pouvez utiliser le jeton d'accès et le jeton de rafraîchissement pour envoyer des messages à l'API tout en étant authentifié sous votre propre cTID.