Sample code for 30+ languages & platforms
Lua 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 Lua Downloads

Lua
local chilkat = require("chilkat")

-- 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:
local signature = "dSUmPwxc9...aKAf8mpEXg=="
local certChainUrl = "https://s3.amazonaws.com/echo.api/echo-api-cert-6-ats.pem"
local 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
local http = chilkat.Http.new()
local sbPem = chilkat.StringBuilder.new()
local success = http:quick_get_sb(certChainUrl, sbPem)
if not success then
    print(http.last_error_text)
    return
end

local pem = chilkat.Pem.new()
success = pem:load_pem(sbPem:get_as_string(), "passwordNotUsed")
if not success then
    print(pem.last_error_text)
    return
end

-- The 1st certificate should be the signing certificate.
local cert = ERROR: Method not in Chilkat for Lua: Pem.GetCert
pem:ERROR()
if not pem.last_method_success then
    print(pem.last_error_text)
    return
end

-- Get the public key from the cert.
local pubKey = chilkat.PublicKey.new()
cert:get_public_key(pubKey)

-- Use the public key extracted from the signing certificate to decrypt the encrypted signature to produce the asserted hash value.
local rsa = chilkat.Rsa.new()
success = rsa:use_public_key(pubKey)
if not success then
    print(cert.last_error_text)
    return
end

-- 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.encoding_mode = "base64"
local bVerified = rsa:verify_string_enc(jsonBody, "sha1", signature)
if bVerified then
    print("The signature is verified against the JSON body of the request. Yay!")
else
    print("Sorry, not verified.  Crud!")
end