Back

How to Easily Create Custom Skills for Alexa

Chris PowerSaturday, January 14, 2017
Pokemon smiling with hearts

After another influx of Alexa powered devices made their way into consumer homes, many companies hope to create custom skills. We’ve had the opportunity to help integrate custom business logic that will keep our clients top of mind, and you can too.

The Amazon documentation is very straightforward, so we made a tutorial to help create custom skills that involve linking your user’s Amazon account with their profile on your application.

Throughout this article, you will learn the process of creating a custom skill, linking it with a user in a Rails application (using Devise and Doorkeeper), and querying data on the user’s behalf.

If that sounds like fun, let’s get started!

Meet our application: PokeHOT or PokeNOT

A group of pokemons with the title of PokeHOT and PokeNOT

I have had the pleasure of working with the premiere Pokemon hotness rating application on the Internet today. It’s very disruptive. Thankfully, this author was kind enough to let me use their application as an example of writing custom Alexa skills. This is a basic application that allows a user to sign in, vote on the hottest Pokemon, and see the results.

For our Alexa skill, we will enable a user to:

  1. link their account
  2. check which Pokemon is currently the hottest
  3. ask for the last vote they cast on a Pokemon

All by using their voice!

Step one: Get an Amazon Developer Account and create a Custom Skill in Alexa

Sign up for a developer account on Amazon, click on the Alexa Tab, then Alexa Skills Kit. Once in the Alexa skills dashboard, click on the “Add a new Skill” button.

Let’s go through the new skill sections one-by-one.

Skill Information: This is where you put basic info like your skill name, invocation name, etc. All we do here is put “Pokemon Hot or Not” for skill name, and “Pokemon hot” for the invocation name.

Note: the invocation name is what users say to ask questions through your skill.

Form inputs to insert skill information

Interaction Model: Place your “Intent Schema” and your “Sample Utterances” here. In short, your Intent Schema is the list of intents you want for your skill. An “Intent” is basically a question. We are going to keep this part simple with only a couple intents. For more information on intents, see this section of the Alexa documentation. We will also add some sample utterances on this page. An utterance is an example of how your user can ask a question. You will generally want a lot of sample utterances in your skill.

Interaction Model UI to configure

Let’s leave the rest of the skill configuration blank for now. We’ll come back to the configuration after we’ve set up our application to talk to Amazon. For now, take a break, grab a coffee, and rest up. You’ve done a lot.

Step Duex: Setting up your application to talk with Alexa

Let’s set up our application to handle Alexa’s requests. For this section, we’re going to assume you have a Rails API available.

Create a new controller for requests from Alexa

Alexa will hit our server with POST requests. These requests will contain data, like an access token, Intent name, etc. In order to get these requests, let’s create a new controller. I like to namespace mine, so I opt for api/alexa/handler_controller.rb

In this controller, you’ll note that I return an odd piece of JSON. A lot of this is boilerplate you need for Amazon. The most important part is the “outputSpeech” section. Here is the documentation to learn more about responses and requests from Amazon. For now, we’ll stub out a simple response “hello from Pokemon Hot!”

#app/controllers/api/alexa/handlers_controller.rb class Api::Alexa::HandlersController < ActionController::Base def create message = "hello from Pokemon Hot!" session_attributes = {"previous_session": "something"} session_end = true render json: { "response": { "outputSpeech": { "type": "PlainText", "text": message, }, "shouldEndSession": session_end }, "sessionAttributes": session_attributes } end end

and update your routes file

#config/routes.rb namespace :api do namespace :Alexa do resource :handler, only: [:create] end end

Once you’re finished make sure to restart your Rails server.

Install ngrok for SSL locally
ngrok will host a local version of our ap, and allow Amazon servers to speak to it. Amazon requires our server to have SSL. We don’t want to host a heroku SSL instance simply for testing, so ngrok will work perfectly.

brew update brew cask install ngrok

After installing ngrok, set it to run on whatever port you’re running your Rails server on. In our case, it’s good ol’ port 3000.

ngrok http 3000

After running this command, you should see something like this:

ngrok example in the CLI

Do you see that https link above? That is what we’ll tell Alexa to communicate with.

Get Alexa to talk to us
Now that we have:

  1. ngrok tunneling our application to https
  2. we have our controller and route

Let’s point Alexa at our application. Go to the Alexa skill you created earlier, click on “configuration” tab, and paste in the https link from ngrok, including the route we created:

Adding endpoints to a form

Now let’s test!
Go to the “Test” tab in your Alexa skill, and type in an utterance. If you did everything correctly, you should see output similar to below:

The response object from a specific endpoint

Great Job! You see we got a response back from our API. You can even hear Alexa say it out loud by clicking the “Listen” button. This is another great opportunity to take a break. We’ll finish this up when you get back!

Step Three: Authenticate users with DoorKeeper and Query on their behalf

This is where things get very interesting. We have the building blocks in place currently, and now it’s time to finalize everything. We are going to focus on a few major things from here on out:

  1. Install Doorkeeper to become an Oauth2 provider
  2. create application in Doorkeeper for Amazon to connect with
  3. configure Doorkeeper to play nicely with Amazon and how Amazon handles tokens
  4. flesh out actual responses for our api

Install and configure Doorkeeper
Doorkeeper is a great gem that allows you to introduce OAuth 2 provider functionality to your Rails application. Let’s install and configure Doorkeeper.

#gemfile.rb gem 'doorkeeper'

Then generate migrations and boilerplate Doorkeeper stuff:

bundle Rails generate doorkeeper:install Rails generate doorkeeper:migration rake db:migrate

Then make sure Doorkeeper added routes to your app:

#config/routes.rb Rails.application.routes.draw do use_doorkeeper # your routes end

Configure Doorkeeper to use the current_user in resource_owner_authenticator. Since we use Devise, this is handled easily:

#config/initializers/doorkeeper.rb resource_owner_authenticator do # Put your resource owner authentication logic here. # Example implementation: current_user || warden.authenticate!(:scope => :user) end

For our purpose, we’re going to use “implicit grant” for OAuth. Configure that in Doorkeeper config again:

#config/initializers/doorkeeper.rb # implicit and password grant flows have risks that you should understand # before enabling: # http://tools.ietf.org/html/rfc6819#section-4.4.2 # http://tools.ietf.org/html/rfc6819#section-4.4.3 grant_flows %w(implicit)

Create an OAuth application in Doorkeeper to handle the Amazon requests

This is pretty straightforward, you need an application for Amazon to connect to. You set this up in both Doorkeeper and Amazon. First, go to your local Doorkeeper applications instance. (Mine is running at http://localhost:3000/oauth/applications.) Click "New Application". You can name this application whatever you want.

For the “redirect URIs”, go to your Amazon developer account, click on “Configuration” in your custom skill, then click “Yes” for account linking.

A highlight of grabbing the redirect URL

  • In the “Authorization URL” field, put in your ngrok URL for OAuth. It is /oauth/authorize in standard Doorkeeper installs.
  • Copy the two redirect urls (highlighted above). Doorkeeper will redirect to one of these after linking a user account

Next, go back to Doorkeeper and finish your new application

Creating a new application UI

One thing to note: Doorkeeper does not allow query params in Redirect URI’s see Github issue here. Make sure to remove the trailing ?vendor=XXXXXXX from your redirect_uris from Amazon when pasting into Doorkeeper.

After hitting “Submit” you should have an application for Amazon to connect to!

Application created successfull UI

Now copy and paste your application ID to Amazon’s Client Id field under "Account Linking" and hit save!

Let’s test this out

Restart your server and “Authorize” the app with Amazon.

If you don’t already have an Alexa account, create one with the same email as your developer account. Then, go to alexa.amazon.com, click on ‘home’ and click ‘Your skills’ at the top right. You should see your custom skill listed there. Click on it and authorize:

Amazon Alexa showing the app now exists

Awesome! We’re almost there!

Protect controller with Doorkeeper

It’s time to finally handle the intents and grab information from an actual linked user! Let’s configure our alexa/handler controller to 'handle' the requests and respond with actual data.

First things first, let’s protect the controller with Doorkeeper. We’re going to add a few methods that I will explain shortly.

#controllers/api/alexa/handlers_controller.rb prepend_before_action :set_access_token_in_params before_action :doorkeeper_authorize! def current_doorkeeper_user @current_doorkeeper_user ||= User.find(doorkeeper_token.resource_owner_id) end def set_access_token_in_params request.parameters[:access_token] = token_from_params end def token_from_params params["session"]["user"]["accessToken"] rescue nil end
  • dookeeper_authorize! is what Doorkeeper uses to protect actions from unauthorized users
  • set_access_token_in_params takes a bit of explanation. When Amazon sends a request to your API, it includes the accessToken for the user in a nested JSON object. Doorkeeper doesn't know where to look for this access token, so we prepend our before_action with a method that moves access_token into the params where Doorkeeper expects it.
  • current_doorkeeper_user is just our convenience method for grabbing a user from the passed over access_token.

Actually get user data for responses
We are just about done! Now let’s grab information from the actual database and return it to the user depending on what they asked our app for. If you remember, we have two intents to handle “HottestPokemon” and “LastPokemonVote”.

  • For “HottestPokemon”, we’ll grab the Pokemon with the most vote and return the name
  • For “LastPokemonVote”, we’ll get the most recent vote from the user, and return the name of the Pokemon they voted for.

The final code should look like this

class Api::Alexa::HandlersController < ActionController::Base prepend_before_action :set_access_token_in_params before_action :doorkeeper_authorize! def create user = current_doorkeeper_user intent_name = params["request"]["intent"]["name"] case intent_name when "HottestPokemon" Pokemon = Pokemon.order(vote_count: :desc).first message = "The hottest Pokemon is #{Pokemon.name}!" render response_with_message(message) when "LastPokemonVote" Pokemon = user.votes.order(created_at: :desc).first.Pokemon message = "Your last vote was for #{Pokemon.name}" render response_with_message(message) else #error somehow render response_with_message("Error. We couldn't find your request") end end def current_doorkeeper_user @current_doorkeeper_user ||= User.find(doorkeeper_token.resource_owner_id) end private def response_with_message(message) { json: { "response": { "outputSpeech": { "type": "PlainText", "text": message, }, "shouldEndSession": true }, "sessionAttributes": {} } } end def set_doorkeeper_token request.parameters[:access_token] = token_from_params end def token_from_params params["session"]["user"]["accessToken"] rescue nil end end

For simplicity, we use a case-statement based on the params["request"]["intent"]["name"] passed along from Alexa. From there, we find data from our database, and return the message to our user.

If you’d like to see the demo app used in this post, check it out here

Your Turn

This tutorial scratches the surface of what is possible with an open platform like Alexa. Although this demo showcases simple responses, you can build complex interactions that span multiple skills. Contact us if you have an idea for a custom skill you would like to integrate for your business.

Share this post

twitterfacebooklinkedin

Related Posts:

Interested in working with us?

Give us some details about your project, and our team will be in touch with how we can help.

Get in Touch