Validating Requests and Responses

All requests made by Plivo to your server URLs contain X-Plivo-Signature-V2, X-Plivo-Signature-Ma-V2, and X-Plivo-Signature-V2-Nonce HTTP headers. To validate a request and to verify that the request to your server originated from Plivo, you must generate a signature at your end and check that it matches with the X-Plivo-Signature-V2 or X-Plivo-Signature-Ma-V2 parameter in the HTTP header.

You can use either X-Plivo-Signature-V2 or X-Plivo-Signature-Ma-V2 to validate a signature.

  • X-Plivo-Signature-V2 is generated using the Auth Token of the associated account or subaccount. To validate using the X-Plivo-Signature-V2 request header, you must generate a signature at your end using the same account or subaccount.
  • X-Plivo-Signature-Ma-V2 is always generated using the Auth Token of the main account. To validate using the X-Plivo-Signature-Ma-V2 request header, you must generate the signature using the main account.

Generating and validating the signature

You can generate the signature by calculating the keyed hash message authentication code (HMAC) with these parameters:

  • Key — Your Plivo Auth Token
  • Message — Base URI appended with X-Plivo-Signature-V2-Nonce. For example, if the base URI is https://<yourdomain>.com/answer/ and X-Plivo-Signature-V2-Nonce is 05429567804466091622, the message will be https://<yourdomain>.com/answer/05429567804466091622.
  • Hashing Function — SHA256

Validating signatures using the latest server SDKs

To validate and verify that the request to your server has originated from Plivo, you must compare the generated signature with X-Plivo-Signature-V2 parameter in the HTTP header and check whether they’re identical. You’ll need your Auth Token, X-Plivo-Signature-V2-Nonce, and the original URL of the server to which callback was sent.

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from flask import Flask, request, make_response, url_for
import plivo

app = Flask(__name__)

@app.route('/receive_sms/', methods =['GET','POST'])
def signature():
    signature = request.headers.get('X-Plivo-Signature-V2')
    nonce = request.headers.get('X-Plivo-Signature-V2-Nonce')
    uri = url_for('signature', _external=True)
    auth_token = "<auth_token>"
    
    output = plivo.utils.validate_signature(uri,nonce,signature,auth_token)
    print(output)

    from_number = request.values.get('From') # Sender's phone numer
    to_number = request.values.get('To') # Receiver's phone number - Plivo number
    text = request.values.get('Text') # The text which was received

    print('Message received - From: %s, To: %s, Text: %s' %(from_number, to_number, text))
    return "Text received"

if __name__ == "__main__":
    app.run(host='0.0.0.0', debug=True)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
require 'sinatra'
require 'rubygems'
require 'plivo'
include Plivo
require 'uri'

get '/receive_sms/' do
    auth_token = "<auth_token>"
    signature = request.env["HTTP_X_PLIVO_SIGNATURE_V2"]
    nonce = request.env["HTTP_X_PLIVO_SIGNATURE_V2_NONCE"]
    url = request.url
    uri = (url.split("?"))[0]
    
    output = Plivo::Utils.valid_signature?(uri,nonce,signature,auth_token)
    puts output

    from_number = params[:From]# The phone number of the person who sent the SMS
    to_number = params[:To]# Your Plivo number that will receive the SMS
    text = params[:Text]# The text which was received on your Plivo number

    puts "Message received from #{from_number} : #{ text }"
end
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
var plivo = require('plivo');
var express = require('express');
var app = express();

app.set('port', (process.env.PORT || 5000));
app.use(express.static(__dirname + '/public'));
app.use(express.urlencoded({ extended: true }))

app.all('/receive_sms/', function(req, res) {
    
    var auth_token = ('<auth_token>');
    var signature = req.get('X-Plivo-Signature-V2');
    var nonce = req.get('X-Plivo-Signature-V2-Nonce');
    var fullUrl = req.protocol + '://' + req.get('host') + req.originalUrl;

    var from_number = req.body.From;// Sender's phone number
    var to_number = req.body.To;// Receiver's phone number - Plivo number
    var text = req.body.Text;// The text which was received

    var output = plivo.validateSignature(fullUrl, nonce, signature, auth_token)
    console.log(output);
    
    console.log ('From : ' + from_number + ' To : ' + to_number + ' Text : ' + text);

});

app.listen(app.get('port'), function() {
    console.log('Node app is running on port', app.get('port'));
});
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?php
    require 'vendor/autoload.php';
    use Plivo\Util\signatureValidation;

    $auth_token = "<auth_token>";
    $signature = $_SERVER["HTTP_X_PLIVO_SIGNATURE_V2"];
    $nonce = $_SERVER["HTTP_X_PLIVO_SIGNATURE_V2_NONCE"];
    
    $url = 'http' . (isset($_SERVER['HTTPS']) ? 's' : '') . '://' . "{$_SERVER['HTTP_HOST']}{$_SERVER['REQUEST_URI']}";
    $uri = explode('?',$url);   
    $uri1 = $uri[0];    

    $SVUtil = new signatureValidation();
    $output = $SVUtil->validateSignature($uri1,$nonce,$signature,$auth_token);
    var_export($output);
    
    $from_number = $_REQUEST["From"];// Sender's phone numer
    $to_number = $_REQUEST["To"];// Receiver's phone number - Plivo number
    $text = $_REQUEST["Text"];// The SMS text message which was received
    
    echo("Message received from $from_number : $text");
?>
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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
import java.io.IOException;
import java.net.URLDecoder;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import com.plivo.api.util.Utils;
import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;

import com.plivo.api.util.*;
import com.plivo.api.exceptions.*;

public class validateSignature extends HttpServlet {
    private static final long serialVersionUID = 1L;
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        String auth_token = "<auth_token>";
        String signature = req.getHeader("X-Plivo-Signature-V2");
        String nonce = req.getHeader("X-Plivo-Signature-V2-Nonce");
        String url = req.getRequestURL().toString();

        try {
            Boolean isValid = Utils.validateSignature(url, nonce, signature, auth_token);
            System.out.println("Valid : " + isValid);
        } catch (Exception  e) {
            e.printStackTrace();
        }

        String from_number = req.getParameter("From");
        String to_number = req.getParameter("To");
        String text = req.getParameter("Text");
        System.out.println("From : " + from_number + " To : " + to_number + " Text : " + text);
    }

    public static void main(String[] args) throws Exception {
        String port = System.getenv("PORT");
        if(port==null)
            port ="8080";
        Server server = new Server(Integer.valueOf(port));
        ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
        context.setContextPath("/");
        server.setHandler(context);
        context.addServlet(new ServletHolder(new validateSignature()),"/receive_sms");
        server.start();
        server.join();
    }
}
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
package main

import (
	"fmt"
	"net/http"

	"github.com/plivo/plivo-go/v7"
)

func handler(w http.ResponseWriter, r *http.Request) {

	originalurl := "https://" + r.Host + r.URL.Path
	authToken := "<auth_token>"
	signature := r.Header.Get("X-Plivo-Signature-V2")
	nonce := r.Header.Get("X-Plivo-Signature-V2-Nonce")
	fromnumber := r.FormValue("From")
	tonumber := r.FormValue("To")
	text := r.FormValue("Text")

	response := plivo.ValidateSignatureV2(
		originalurl,
		nonce,
		signature,
		authToken,
	)
	fmt.Printf("Response: %#v\n", response)

	print("Message Received - ", fromnumber, " ", tonumber, " ", text)
}

func main() {
	http.HandleFunc("/receive_sms/", handler)
	http.ListenAndServe(":8080", nil)
}
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
using System;
using System.Collections.Generic;
using System.Diagnostics;
using RestSharp;
using Plivo.Utilities;
using Nancy;

namespace validateSignature
{
    public class Program : NancyModule
    {
        public Program()
        {
            Get["/receive_sms/"] = x =>
            {
                IEnumerable<string> signature = Request.Headers["X-Plivo-Signature-V2"];
                String[] sign = (String[])signature;
                String actualsignature = sign[0];

                IEnumerable<string> nonce = Request.Headers["X-Plivo-Signature-V2-Nonce"];
                String[] key = (String[])nonce;
                String actualnonce = key[0];

                String auth_token = "<auth_token>";
                String url = Request.Url.SiteBase + Request.Url.Path;

                bool valid = Plivo.Utilities.XPlivoSignatureV2.VerifySignature(url, actualnonce, actualsignature, auth_token);
                Debug.WriteLine("Valid : " + valid);
                
                String from_number = Request.Query["From"];
                String to_number = Request.Query["To"];
                String text = Request.Query["Text"];

                Debug.WriteLine("From : {0}, To : {1}, Text : {2}", from_number, to_number, text);
                Console.ReadLine(); 
                return "OK";
            };
        }
    }
}