3

The Microsoft webhook subscription is sending weird body data and no text in the validationToken parameter. Is there anyone on the Microsoft Graph team that could help?

This is what I'm sending (I changed the actual domain name in the notificationUrl for privacy).

{
    "changeType": "created",
    "notificationUrl": "https://myapp.com/version-test/api/1.1/wf/msgraphvalidation",
    "resource": "me/mailFolders/inbox/messages",
    "expirationDateTime": "2018-08-27T18:23:45.9356913Z"
 }

This is what's being returned in the body after sending a POST to "https://graph.microsoft.com/v1.0/subscriptions" or "https://graph.microsoft.com/beta/subscriptions" with the above info.

Request data
{
    "bold": "\u001b[1m\u001b[22m",
    "underline": "\u001b[4m\u001b[24m",
    "strikethrough": "\u001b[9m\u001b[29m",
    "italic": "\u001b[3m\u001b[23m",
    "inverse": "\u001b[7m\u001b[27m",
    "grey": "\u001b[90m\u001b[39m",
    "black": "\u001b[30m\u001b[39m",
    "yellow": "\u001b[33m\u001b[39m",
    "red": "\u001b[31m\u001b[39m",
    "green": "\u001b[32m\u001b[39m",
    "blue": "\u001b[34m\u001b[39m",
    "white": "\u001b[37m\u001b[39m",
    "cyan": "\u001b[36m\u001b[39m",
    "magenta": "\u001b[35m\u001b[39m",
    "greyBG": "\u001b[49;5;8m\u001b[49m",
    "blackBG": "\u001b[40m\u001b[49m",
    "yellowBG": "\u001b[43m\u001b[49m",
    "redBG": "\u001b[41m\u001b[49m",
    "greenBG": "\u001b[42m\u001b[49m",
    "blueBG": "\u001b[44m\u001b[49m",
    "whiteBG": "\u001b[47m\u001b[49m",
    "cyanBG": "\u001b[46m\u001b[49m",
    "magentaBG": "\u001b[45m\u001b[49m",
    "rainbow": "",
    "zebra": "",
    "stripColors": "",
    "zalgo": ""
}

Here's the full error:

{ 
"error": { 
    "code": "InvalidRequest", 
    "message": "Subscription validation request failed. Response must exactly match validationToken query parameter.",
    "innerError": { 
        "request-id": "08008b1b-4eda-4a09-a0d5-45ffcce1a8d6", 
        "date": "2018-08-26T02:43:08" 
    }
}
}
Robert
  • 7,394
  • 40
  • 45
  • 64
kfawcett
  • 73
  • 1
  • 4
  • 10

6 Answers6

10

Microsoft Graph validates the notification endpoint provided in the notificationUrl property of the subscription request before creating the subscription. Refer to the following links:

https://developer.microsoft.com/en-us/graph/docs/concepts/webhooks

Microsoft Graph WebHook: Subscription validationtoken blank?

You can validate the notification url like this:

if (Request.QueryString["validationToken"] != null)
            {
                var token = Request.QueryString["validationToken"];
                return Content(token, "text/plain");
            }

https://github.com/microsoftgraph/aspnet-webhooks-rest-sample/blob/master/GraphWebhooks/Controllers/NotificationController.cs

jarrad_obrien
  • 391
  • 1
  • 4
  • 15
DevÁsith
  • 1,072
  • 12
  • 38
  • Hi InfoÁsith, I understand how the webhook is supposed to work, but Microsoft doesn't appear to be sending the correct data to my notificationUrl. Hopefully someone on the Graph team can check based on the request-id I posted (08008b1b-4eda-4a09-a0d5-45ffcce1a8d6). – kfawcett Aug 27 '18 at 13:14
  • I think this may be due to the `Content-Type` that Microsoft is using when sending data to the `notificationUrl`. Can anyone verify if this is being sent as `application/json` or `text/plain`? I understand that we're supposed to send back as `text/plain` and POST to Microsoft as `applicaiton/json`, but there's no mention of how Microsoft is POSTing to us. – kfawcett Aug 27 '18 at 22:39
  • As the comment that kfawcett posted, Microsoft didn't send the correct data to the notificationUrl. I find [https://developer.microsoft.com/en-us/graph/docs/concepts/webhooks#managing-subscriptions](this document) that says 'If the request is invalid, Microsoft Graph sends an error response with code and details.'. Could you show the error response? – Keen Jin Aug 28 '18 at 07:58
  • 1
    Posted in the format https://usernotificationurl?validationtoken=xxxxxx – codeye Sep 14 '18 at 13:18
2

Microsoft Graph API asked about the notificationUrl. Here the JSON when you call subscription API

//POST https://graph.microsoft.com/v1.0/subscriptions    

{
           "changeType": "created,updated,deleted",
           "notificationUrl": "https://your_domain/outlook/ms_ping",
           "resource": "me/messages",
           "expirationDateTime":"2020-07-08T18:23:45.9356913Z",
           "clientState": "secretClientValue",
           "latestSupportedTlsVersion": "v1_2"
 }

Once you call the Microsoft Subscription API then API will send you a validationToken in your notificationUrl. You only need to respond back to this validationToken from your notificationUrl with 200 response code which you sent in your post body in API. So here is the code

//https://your_domain/outlook/ms_ping.php
    <?php
        $token = $_REQUEST['validationToken'];
        header("content-type:application/json");
        http_response_code(200);
        echo ($token);
    ?>
Rishabh Rawat
  • 1,083
  • 9
  • 15
  • The content-type needs to be text/plain, not json https://learn.microsoft.com/en-us/graph/webhooks?tabs=http#notification-endpoint-validation – Invincibear Mar 15 '23 at 23:41
1

The validationToken is on the query string and not in the body of the request.

crice1988
  • 81
  • 1
  • 10
0

It appears your notification endpoint is not responding with the validation token from the query string. The response should be simply the validation token in plain text.

Not sure if this in on purpose, but the notification url for the request you sent does not match the notification url you've mentioned in this post.

Trey
  • 348
  • 5
  • 16
0

Nodejs Example of webhook for creating Microsoft subscription

**// call for subscription creation**
static async createMicrosoftSubscription(access_token) {
    const data = {
        changeType: "created",
        notificationUrl: 'https:www.yourdomain.com/webhook/inbox-updates',
        resource: "/me/mailfolders('inbox')/messages",
        expirationDateTime: moment().add(1, 'month').toISOString(),
    };

    const response = await axios.post(
        `https://graph.microsoft.com/v1.0/subscriptions`, data, {
        headers: {
            'Authorization': `Bearer ${access_token}`
        }
    });

    console.log(response.data);
}


**// webhook function should be like this**
static async webhookMicrosoftInboxUpdates(req, res) {
    
    if (req.query && req.query.validationToken) {
        res.set('Content-Type', 'text/plain');
        res.send(req.query.validationToken);
        return;
    }

    const response = JSON.stringify(req.body, null, 2);
    const data = response.value;

    console.log(data);

    // then further process your data
}
Saad Ahmed
  • 700
  • 1
  • 8
  • 15
0

This is the lambda function solution! You need to get it from the query params :

import json

def lambda_handler(event, context):
    # Check if this is a subscription validation request
    query_params = event.get('queryStringParameters', {})
    validation_token = query_params.get('validationToken')

    if validation_token:
        # Respond with the validation token
        response = {
            'statusCode': 200,
            'body': validation_token
        }
    else:
        # Process the actual change notification (if needed)
        # Your logic to handle the change notification goes here
        response = {
            'statusCode': 200,
            'body': 'Notification received successfully.'
        }

    return {
        'statusCode': response['statusCode'],
        'body': validation_token
    }
toyota Supra
  • 3,181
  • 4
  • 15
  • 19