Sample code for 30+ languages & platforms
Java Requires Chilkat v11.0.0+

Verify Signature of Alexa Custom Skill Request

See more HTTP Misc Examples

This example verifies the signature of an Alexa Custom Skill Request.

Chilkat Java Downloads

Chilkat2 Java
import com.chilkatsoft.chilkat2.Cert;
import com.chilkatsoft.chilkat2.ChilkatException;
import com.chilkatsoft.chilkat2.Http;
import com.chilkatsoft.chilkat2.Pem;
import com.chilkatsoft.chilkat2.PublicKey;
import com.chilkatsoft.chilkat2.Rsa;
import com.chilkatsoft.chilkat2.StringBuilder;

public class ChilkatExample {

    public static void main(String[] args) {
        // This example assumes you have a web service that will receive requests from Alexa.
        // A sample request sent by Alexa will look like the following:

        // Connection: Keep-Alive
        // Content-Length: 2583
        // Content-Type: application/json; charset=utf-8
        // Accept: application/json
        // Accept-Charset: utf-8
        // Host: your.web.server.com
        // User-Agent: Apache-HttpClient/4.5.x (Java/1.8.0_172)
        // Signature: dSUmPwxc9...aKAf8mpEXg==
        // SignatureCertChainUrl: https://s3.amazonaws.com/echo.api/echo-api-cert-6-ats.pem
        //
        // {"version":"1.0","session":{"new":true,"sessionId":"amzn1.echo-api.session.433 ... }}

        // First, assume we've written code to get the 3 pieces of data we need:
        String signature = "dSUmPwxc9...aKAf8mpEXg==";
        String certChainUrl = "https://s3.amazonaws.com/echo.api/echo-api-cert-6-ats.pem";
        String jsonBody = "{\"version\":\"1.0\",\"session\":{\"new\":true,\"sessionId\":\"amzn1.echo-api.session.433 ... }}";

        // To validate the signature, we do the following:

        // First, download the PEM-encoded X.509 certificate chain that Alexa used to sign the message
        Http http = new Http();
        StringBuilder sbPem = new StringBuilder();
        try {
            http.quickGetSb(certChainUrl, sbPem);
        } catch (ChilkatException e) {
            System.out.println(e.getLastErrorText());
            return;
        }

        Pem pem = new Pem();
        try {
            pem.loadPem(sbPem.getAsString(), "passwordNotUsed");
        } catch (ChilkatException e) {
            System.out.println(e.getLastErrorText());
            return;
        }

        // The 1st certificate should be the signing certificate.
ERROR: Method not in Chilkat2 Java: Pem.GetCert
        Cert cert = pem.ERROR();
        if (!pem.getLastMethodSuccess()) {
            System.out.println(pem.getLastErrorText());
            return;
        }

        // Get the public key from the cert.
        PublicKey pubKey = new PublicKey();
        cert.getPublicKey(pubKey);

        cert.close();

        // Use the public key extracted from the signing certificate to decrypt the encrypted signature to produce the asserted hash value.
        Rsa rsa = new Rsa();
        try {
            rsa.usePublicKey(pubKey);
        } catch (ChilkatException e) {
            System.out.println(cert.getLastErrorText());
            return;
        }

        // RSA "decrypt" the signature.
        // (Amazon's documentation is confusing, because we're simply verifiying the signature against the SHA-1 hash
        // of the request body.  This happens in a single call to VerifyStringENC...)
        rsa.setEncodingMode("base64");
        try {
            rsa.verifyStringENC(jsonBody, "sha1", signature);
            System.out.println("The signature is verified against the JSON body of the request. Yay!");
        } catch (ChilkatException e) {
            System.out.println("Sorry, not verified.  Crud!");
        }
    }
}