# Alexa Rust Webservice Verifier [![Crates.io](https://img.shields.io/crates/v/alexa-verifier)](https://crates.io/crates/alexa-verifier) [![](https://docs.rs/alexa-verifier/badge.svg)](https://docs.rs/alexa-verifier) Verify that incoming requests are from Alexa for custom, webservice skills. - Confirmed working with the Alexa [certification functional test](https://developer.amazon.com/docs/devconsole/test-and-submit-your-skill.html). - Built using the [Developer Documentation](https://developer.amazon.com/docs/custom-skills/host-a-custom-skill-as-a-web-service.html#manually-verify-request-sent-by-alexa) and [Python Alexa SDK](https://github.com/alexa/alexa-skills-kit-sdk-for-python/tree/master/ask-sdk-webservice-support) as reference. ## Features Both sync and async clients are provided by default. These are behind feature flags `sync` or `async`, respectively. - `sync` provides `RequestVerifier` client - `async` provides `RequestVerifierAsync` client ## Using Example using [Rouille](https://github.com/tomaka/rouille) server and [alexa_sdk](https://github.com/tarkah/alexa_rust) for request deserialization ```rust use crate::skill::process_request; // Entry point to custom skill use alexa_verifier::RequestVerifier; // Struct provided by this crate use log::{debug, error, info}; use rouille::{router, Request, Response}; use std::io::Read; fn note_routes(request: &Request, verifier: &RequestVerifier) -> Response { router!(request, (POST) (/) => { info!("Request received..."); // Get request body data let mut body = request.data().unwrap(); let mut body_bytes: Vec = vec![]; body.read_to_end(&mut body_bytes).unwrap(); // Get needed headers, default to blank (will cause verification to fail) let signature_cert_chain_url = request.header("SignatureCertChainUrl").unwrap_or(""); let signature = request.header("Signature").unwrap_or(""); // Deserialize using alexa_sdk::Request let _request = serde_json::from_slice::(&body_bytes); if let Err(e) = _request { error!("Could not deserialize request"); error!("{:?}", e); let response = Response::empty_400(); info!("Sending back response..."); debug!("{:?}", response); return response; } let request = _request.unwrap(); debug!("{:?}", request); // alexa-verifier used here, return 400 if verification fails if verifier .verify( signature_cert_chain_url, signature, &body_bytes, request.body.timestamp.as_str(), None ).is_err() { error!("Could not validate request came from Alexa"); let response = Response::empty_400(); info!("Sending back response..."); debug!("{:?}", response); return response; }; debug!("Request is validated..."); // Entry point custom to skill, returning alexa_sdk::Response let response = Response::json(&process_request(request)); info!("Sending back response..."); debug!("{:?}", response); response }, _ => Response::empty_404() ) } pub fn run() -> std::io::Result<()> { info!("Starting server on 0.0.0.0:8086"); let verifier = RequestVerifier::new(); rouille::start_server("0.0.0.0:8086", move |request| { note_routes(&request, &verifier) }); } ``` License: MIT