kfawcett
kfawcett

Reputation: 83

Subscription validation request failed. Response must exactly match validationToken query parameter

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

Upvotes: 4

Views: 10737

Answers (7)

dataviews
dataviews

Reputation: 3100

@afonso's answer above is correct for lambda. However, if you're using a lifecycleNotificationUrl parameter as well, make sure this endpoint also does the validation, otherwise you'll be stuck with your hands in your pockets for a few hours like I was!

Upvotes: 0

afonso Quinaz
afonso Quinaz

Reputation: 21

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
    }

Upvotes: 2

Saad Ahmed
Saad Ahmed

Reputation: 777

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
}

Upvotes: 0

DevÁsith
DevÁsith

Reputation: 1234

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

Upvotes: 10

Rishabh Rawat
Rishabh Rawat

Reputation: 1194

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);
    ?>

Upvotes: 2

Trey
Trey

Reputation: 348

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.

Upvotes: 0

crice1988
crice1988

Reputation: 79

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

Upvotes: 0

Related Questions