Dismiss Notice

Register now to be one of the first members of this SharePoint Community! Click here it just takes seconds!

Dismiss Notice
Welcome Guest from Country Flag

Build Your Skype Bot with OAuth and REST

Discussion in 'Official Microsoft News' started by Tsuyoshi Matsuzaki, Jul 12, 2016.

Thread Status:
Not open for further replies.
  1. Tsuyoshi Matsuzaki

    Tsuyoshi Matsuzaki Guest

    Blog Posts:
    0
    If you are .NET (C#, etc) or Node.js programer, you can use SDK for building your Skype Bot. If not, you must handle the HTTP and OAuth using your programming language (like PHP, Ruby, etc).
    In this blog post I explain the HTTP flow (incl. AuthN) of Skype Bot without SDK. Using this flow, you can develop Skype Bot with any programming language.

    Beforehand, you must register your bot, and please see the tutorial document. (In this blog post we assume that the registration is done.)

    Basic flow


    The following picture illustrates the calling flow in the Skype Bot Platform.
    The Skype Bot Platform provides basic bot functionalities (Bot Directory, etc) fronting on end-users. Your code is called through the Skype Bot Platform in the backend.

    [​IMG]

    If you are using Microsoft Bot Framework with Skype, as a result the Bot Framework connects to the above platform. (See the previous post “HTTP Flow of Microsoft Bot Framework“.)

    Authentication (outgoing – your code to skype)


    Before starting messaging, you must get secure token. The message from your bot is protected Azure AD v2 endpoint, otherwise the malicious code might call the Skype Bot Platform instead of your bot.
    In this section, I explain how to accomplish this flow.

    [​IMG]

    Skype Bot uses the app-only access token in Azure AD v2 endpoint. To get this kind of access token, you just send the HTTP request as following.
    (Beforehand, you must retrieve the following client_id and client_secret from the app registration portal. These are the bot’s client id and secret.)

    POST https://login.microsoftonline.com/common/oauth2/v2.0/token
    Content-Type: application/x-www-form-urlencoded

    grant_type=client_credentials&client_id=761b6e57-2dc1-4de9-b5d1-9599a9902117&client_secret=3ayhQ55FqU...&scope=https%3A%2F%2Fgraph.microsoft.com%2F.default

    You can receive the following HTTP response.

    HTTP/1.1 200 OK
    Content-Type: application/json; charset=utf-8

    {
    "token_type": "Bearer",
    "expires_in": 3600,
    "ext_expires_in": 3600,
    "access_token": "eyJ0eXAiOi..."
    }

    Please hold the above access token in your bot application. (Notice : This expires in 1 hour.)
    You must always set this access token as Authorization header for your outgoing messages, and the Skype Bot Platform verifies this token for checking if the valid code is sending.

    POST https://apis.skype.com/v2/conversations/8:live:tsuyoshi.matsuzaki/activities/
    Authorization: Bearer eyJ0eXAiOi...
    Content-Type: application/json

    {"message":{"content":"How are you ?"}}
    Authentication (incoming – skype to your code)


    The message from Skype Bot Platform is also protected by Authorization header. (see the following header in bold fonts) In this case, you must verify the message for secure communications. (If not, your code might be called by the malicious code.)

    [​IMG]

    POST https://example.com/yourbot
    Authorization: Bearer eyJ0eXAiOi...
    Content-Type: application/json; charset=utf-8

    [
    {
    "action": "add",
    "activity": "contactRelationUpdate",
    "from": "8:live:tsuyoshi.matsuzaki",
    "fromDisplayName": "Tsuyoshi Matsuzaki",
    "to": "28:761b6e57-2dc1-4de9-b5d1-9599a9902117",
    "time": "2016-07-11T06:30:09.512Z"
    }
    ]

    In this case, the Azure AD is not used. The key in Skype Bot Platform is used for this communication.
    The OpenID / OAuth configuration information of Bot Platform is hosted at https://api.aps.skype.com/v1/.well-known/openidconfiguration. It returns as following. (Notice : This might change in the future, so don’t copy this json in your production code.)

    {
    "issuer": "https://api.botframework.com",
    "authorization_endpoint": "https://anonymous.invalid.com",
    "jwks_uri": "https://api.aps.skype.com/v1/keys",
    "id_token_signing_alg_values_supported": [
    "RSA256"
    ],
    "token_endpoint_auth_methods_supported": [
    "private_key_jwt"
    ]
    }

    The public key (X.509 certificate) is stored in the previous “jwks_uri” value, and you can verify “Authorization” header (access token) using this key.

    As I explained in the previous post “How to verify the OAuth token with the v2.0 endpoint“, this verification is accomplished by the simple steps.
    The next is the PHP sample code for this verification.

    <?php
    // Authorization header value
    $token = "eyJ0eXAiOi...";
    // 0:Invalid, 1:Valid
    $token_valid = 0;

    // 1 separate token by dot (.)
    $token_arr = explode('.', $token);
    $headers_enc = $token_arr[0];
    $claims_enc = $token_arr[1];
    $sig_enc = $token_arr[2];

    // 2 base 64 url decoding
    $headers_arr = json_decode(base64_url_decode($headers_enc), TRUE);
    $claims_arr = json_decode(base64_url_decode($claims_enc), TRUE);
    $sig = base64_url_decode($sig_enc);

    // 3 get key list
    $keylist = file_get_contents('https://api.aps.skype.com/v1/keys');
    $keylist_arr = json_decode($keylist, TRUE);
    foreach($keylist_arr['keys'] as $key => $value) {

    // 4 select one key (which matches)
    if($value['kid'] == $headers_arr['kid']) {

    // 5 get public key from key info
    $cert_txt = '-----BEGIN CERTIFICATE-----' . "n" . chunk_split($value['x5c'][0], 64) . '-----END CERTIFICATE-----';
    $cert_obj = openssl_x509_read($cert_txt);
    $pkey_obj = openssl_pkey_get_public($cert_obj);
    $pkey_arr = openssl_pkey_get_details($pkey_obj);
    $pkey_txt = $pkey_arr['key'];

    // 6 verify signature
    $token_valid = openssl_verify($headers_enc . '.' . $claims_enc, $sig, $pkey_txt, OPENSSL_ALGO_SHA256);
    }
    }

    // 7 show result
    if($token_valid == 1)
    echo 'Token is Valid';
    else
    echo 'Token is Invalid';

    // Helper functions
    function base64_url_decode($arg) {
    $res = $arg;
    $res = str_replace('-', '+', $res);
    $res = str_replace('_', '/', $res);
    switch (strlen($res) % 4) {
    case 0:
    break;
    case 2:
    $res .= "==";
    break;
    case 3:
    $res .= "=";
    break;
    default:
    break;
    }
    $res = base64_decode($res);
    return $res;
    }
    ?>
    HTTP flow – Adding your bot


    The authentication flow is all done ! From now, you just communicate using HTTP (REST-styled messaging) with the Skype Bot Platform.

    First, if your bot is added (subscribed) by a Skype user (customer), the following HTTP webhook arrives to your bot.
    As I explained in the above, you must check the Authorization header value and proceed your actions.

    POST https://example.com/yourbot
    Authorization: Bearer eyJ0eXAiOi...
    Content-Type: application/json; charset=utf-8

    [
    {
    "action": "add",
    "activity": "contactRelationUpdate",
    "from": "8:live:tsuyoshi.matsuzaki",
    "fromDisplayName": "Tsuyoshi Matsuzaki",
    "to": "28:761b6e57-2dc1-4de9-b5d1-9599a9902117",
    "time": "2016-07-11T06:30:09.512Z"
    }
    ]

    The “action” attribute means what kind of bot action is published. In this case, this means that the user added your bot.
    The “from” is the Skype user id, and the “to” is your bot id. Your bot must store this “from” id in your database, because your bot can communicate with your bot’s users (the bot’s subscribers) using this id.

    Notice : The number of “8” means the skype user, and “28” means the skype bot.​

    If your bot accept this request, you just response HTTP status 201.

    HTTP/1.1 201 Created

    When your bot is removed from the contact list, the following HTTP request (webhook) is received. (In this case you just also response the HTTP status 201.)

    POST https://example.com/yourbot
    Authorization: Bearer eyJ0eXAiOi...
    Content-Type: application/json; charset=utf-8

    [
    {
    "action": "remove",
    "activity": "contactRelationUpdate",
    "from": "8:live:tsuyoshi.matsuzaki",
    "fromDisplayName": "Tsuyoshi Matsuzaki",
    "to": "28:761b6e57-2dc1-4de9-b5d1-9599a9902117",
    "time": "2016-07-12T09:52:36.574Z"
    }
    ]
    HTTP flow – Incoming message


    [​IMG]

    If the Skype user sends the message “Good morning !” to your bot, the following HTTP webhook arrives.

    POST https://example.com/yourbot
    Authorization: Bearer eyJ0eXAiOi...
    Content-Type: application/json; charset=utf-8

    [
    {
    "id": "0",
    "content": "Good morning !",
    "activity": "message",
    "from": "8:live:tsuyoshi.matsuzaki",
    "fromDisplayName": "Tsuyoshi Matsuzaki",
    "to": "28:761b6e57-2dc1-4de9-b5d1-9599a9902117",
    "time": "2016-07-12T06:26:08.231Z"
    }
    ]

    This incoming message is very similar to the privious one, then I think there’s no need to explain about details. But there’s some notation for this incoming messages.

    The “id” is called “activity id”. Sometimes this id is refered by other communication.
    For example, when this incoming message is for attachment (images, etc), you can ask for the binary data (which is encoded by base64) using this id.
    When not refered, this id is “0”.

    As you notice, the message body uses the json array. When there are multiple messages, these can be included in one request using the json array.

    If your bot accept this request, you just response HTTP status 201.

    HTTP/1.1 201 Created
    HTTP flow – Outgoing message


    [​IMG]

    On the other hand, when your code send the outgoing message (which is the message from your bot to the Skype user), you send the following HTTP request to the Skype Bot Platform.
    Each HTTP request is one-way (not request-reply), and it can be bidirectional (incoming and outgoing). Your code can also call the Skype user using one-way messaging like timer bot or some notification bot. (There’s no need to use request-reply style messaging.)

    POST https://apis.skype.com/v2/conversations/8:live:tsuyoshi.matsuzaki/activities/
    Authorization: Bearer eyJ0eXAiOi...
    Content-Type: application/json

    {"message":{"content":"Good morning !"}}

    The “8:live:tsuyoshi.matsuzaki” in the uri fragment is the conversation id. When your bot is sending the message to one Skype user, this id can be Skype Id itself. When group conversation, conversation thread id will be used.

    If the Skype Bot Platform accepts this incoming message, HTTP status 201 is returned. (As I explained, the Authorization header is checked by the platform.)

    HTTP/1.1 201 Created

    You can also use emoji, attachment, and so on. Next is the emoji example.

    POST https://apis.skype.com/v2/conversations/8:live:tsuyoshi.matsuzaki/activities/
    Authorization: Bearer eyJ0eXAiOi...
    Content-Type: application/json

    {"message":{"content":"<ss type ="wink">;)</ss>"}}

    [​IMG]



    In this blog post I’ve just explained the basic concepts and steps building Skype Bot, but Skype Bot can handle more advanced scenarios like the attachment, group chat, and audio/video calling, etc. (The audio is the limited preview, and the video will be in the future release.)

    Don’t worry about the supported programming language in SDK, and please try !

    Continue reading...
     
Thread Status:
Not open for further replies.

Share This Page

LiveZilla Live Chat Software