Alexa Account Linking: 5 Steps to Seamlessly Link Your Alexa Skill to User Systems That Require Authentication

Sebastien Stormacq Aug 03, 2016
Share:
Tutorial
Blog_Header_Post_Img

Editor's Note: This post was updated in January 2019. 

Some skills require the ability to connect the identity of an Alexa end user with a user in another system, such as Twitter, Facebook, Amazon, and many others. For example, suppose you own a web-based service “Car-Fu” that lets users order taxis. It would be very convenient for people to access Car-Fu by voice (“Alexa, ask Car-Fu to order a taxi”).

To accomplish that, you’d use a process called account linking, which provides a secure way for Alexa skills to connect with third-party systems requiring authentication.

Skills that use the Smart Home Skill API must use account linking (with the authorization code grant flow) to connect the Alexa user with their device cloud account. Custom skills can use account linking if desired. However, if your custom skill merely needs to keep track of a user to save attributes between sessions, you do not need to use account linking.

There are many ways you can use account linking to enhance your Alexa skills. For example:

  • You can map this user profile to an existing user in your user database, using the email address as key. This would allow you to create a contextual skill that behaves according to your user’s preferences and history.
  • You can decide what authorizations this user will have in your system.
  • You can use services such as Amazon Cognito Identity Pools to acquire an AWS Access Key and Secret Key to interact with AWS Services such as Amazon DynamoDB.

The Basics of Account Linking with the Login with Amazon (LWA) Service

Account linking leverages OAuth 2.0; an open protocol that provides a simple, standards-based method for web, mobile and desktop applications to request user authorization from remote servers.

As a skill developer, you could set up and configure your own OAuth server and identity management system. At some large companies, an OAuth server is probably already available and Identity Management procedures already in place. However, at smaller companies, this would require you to build, operate, and maintain your own complex system to manage user identities, passwords, and profiles in a secure and scalable way.

Many organizations rely instead on well-known identity providers, available on the internet. These are sites where nearly everyone has an account, such as Facebook, Google, Twitter, and Amazon. The service that acts as a public-facing identity provider for Amazon is Login with Amazon.

When using OAuth, you delegate user authentication to a third-party Identity Provider (IDP). As illustrated below, the user is redirected to the IDP web site. User authentication happens according to the IDP’s policies (username and password, one-time password, biometric, etc.), and upon successful authentication, the IDP generates an implicit grant (aka bearer token) or an authorization code grant.

The bearer token is the token you'll use for accessing information and services. On the other hand, an authorization code can only be used to request a bearer token. This usually happens on the backend, between your application server and the IDP service. While an implicit grant is often faster and simpler for developers to request, an authorization code grant is generally considered more secure and some IDPs may require it for sensitive information or services. Also, a code grant allows for automatic refreshing of the bearer token after a given expiry, which will be set according to the IDP’s policy. When using an implicit grant, the user has to manually re-authenticate themselves when attempting to use the service, which, depending on the lifespan of the bearer token, can cause friction for account linking in applications.

After authentication is complete and a valid token is received, your application is responsible for managing authorization based on the customer's profile.

oauth data flow
Figure 1: OAuth data flow

Account Linking Step by Step

Follow these steps to configure your Alexa skills with account linking and Login with Amazon.

If you haven’t created a skill yet, please first use the Alexa Skills Kit to build something relatively simple, such as a trivia skill. You can get a prototype up and running in just a few hours and come back here once it’s published.

Step 1: Create a Login with Amazon (LWA) Security Profile

First, you need to create a LWA profile for your Alexa skill. Here’s how.

  • Connect to https://developer.amazon.com and authenticate with your Amazon credentials
  • Click on “Login with Amazon” then “Security Profiles”
  • Click on “Create a New Security Profile”

Figure 2: Access Login With Amazon
Figure 2: Access Login With Amazon
Figure 3: Create a Security Profile
Figure 3: Create a Security Profile

Fill in all three required fields to create your security profile and click “Save.” For the purpose of this article, I am using Amazon’s privacy policy URL. Make sure to replace the link with a link to your own Data Privacy policy. The end result should look like this:

Figure 4: Create Security Profile
Figure 4: Create Security Profile

Before you complete this step, be sure to copy your Client ID and Client Secret from the Web Settings tab (see Figure 4) to a text editor so they're easily available. You’ll need these values later in the process.

Figure 5: Collect Client ID and Client Secret
Figure 5: Collect Client ID and Client Secret

Step 2: Configure Account Linking in the Alexa Developer Console

Now that you’ve configured Login with Amazon, you can configure Account Linking for your Alexa skill. (Remember, you need to have a skill already created to do this). In the Alexa developer console, choose the skill you want to edit (or create a new skill).

Under the “Build” tab for your skill, click “Account Linking” on the left side. To enable account linking, turn on the “Do you allow users to create an account or link to an existing account with you?” toggle.

Choose “Allow users to enable skill without account linking” if you want to allow users to start to use the skill without Account Linking and let them link their account later during the skill usage (see Optional Account Linking for the details).

Figure 6: Account Linking Details
Figure 6: Account Linking Details

Then, enter the following:

Figure 7: Account Linking Details
Figure 7: Account Linking Details

The values you need to enter into these fields are detailed in the table below.

Key

Value

Authorization Grant Type

Auth Code Grant

Authorization URI

https://www.amazon.com/ap/oa

This is the URL where Alexa Service will send the customers for authentication.  This URL will show customers the Login With Amazon login page.

Access Token URI

https://api.amazon.com/auth/o2/token

This is the URI the Alexa Service needs to use to exchange an authorization code for a token and to refresh expired tokens.  This is the same value for all Login with Amazon applications.

Client ID

The Client ID received from Login with Amazon during Step 1 above.  This has a format such as amzn1-application-oa2-client-xxx

Client Secret

The client secret received from Login With Amazon during Step 1 above.

Scope

Login with Amazon supports several scopes, for this example, let’s use “profile”.  This will allow your code to retrieve a unique Amazon userid, email address, and full name for the user.

The last step is to configure Login with Amazon to accept our redirection URLs.  The redirection URLs are given on the Alexa Developer Console, 1 per geographic area, under “Redirect URL”. These are the URLs starting by https://pitangui.amazon.com/… (North America) or https://layla.amazon.com/... (EU and India) https://alexa.amazon.co.jp... (Far East)

Copy this value to that text editor I suggested earlier and go back to the Login with Amazon console.

Next to the Security Profile you created in Step 1, click the button with the gear icon and select “Web Settings” from the menu.

Figure 8: Login with Amazon – Redirection URL
Figure 8: Login with Amazon – Redirection URL

Click the "Edit" button in the lower right, then enter the Redirect URL, as it appears on the ASK Developer Console.

Figure 9: Login with Amazon - Redirect URL
Figure 9: Login with Amazon - Redirect URL

Now you are ready to write some code.

Step 3: Write Your Custom Skill Code

For the purpose of this blog post, I chose to write the Alexa custom skill code in NodeJS and deploy it on AWS Lambda.

You can learn more about writing code for custom skills here.

When your skill is called the first time, you will receive a JSON document like this:

Copied to clipboard
{
  "session": {
    "sessionId": "SessionId.7c77f955-ae5e-46f1-a9ca-3fb354b1ce77",
    "application": {
      "applicationId": "amzn1.echo-sdk-ams.app.fb2fc3e7-55e7-4f05-851e-7ad308a6b499"
    },
    "user": {
      "userId": "amzn1.ask.account.AFP3ZWPOS2BGJR7OWJZ3DHPKMOMNWY4AY66FUR7ILBWANIHQN73QHMAHCTVTAHFPUV3WAFNGKBYW5LFUE2WV4CCGEISSPHBHCW5SCYJDL3DLWRRRBB4CQIP3X3PV65V2AYMMXSNFPKHPZJFVAH5AHKHDLAER67H3AHL4XBUU76XEH5BGDZZNGV5T6HHAGN6KGZI777J3VA7WGPA"
    },
    "new": true
  },
  "request": {
    "type": "IntentRequest",
    "requestId": "EdwRequestId.b595d667-caa3-4818-8d4a-c7a31e8adddc",
    "timestamp": "2016-05-27T15:36:26Z",
    "intent": {
      "name": "SayHello",
      "slots": {}
    },
    "locale": "en-US"
  },
  "version": "1.0"
}

Notice that the “user” section contains a userId properties, but no OAuth access token is available yet as we did not authenticate our user yet.

Whenever users invoke intents in your skill that rely on information obtained from account linking, your skill code should return a “LinkAccount” card to be displayed in the Alexa app or the Alexa web site.  In this example, the card will contain a link allowing the user to authenticate on Login with Amazon. In addition to the card, it is a recommended practice to return a voice prompt inviting the user to authenticate in the app.

Below is an example of what this might look like using the ASK SDK for Node.js V2:

Copied to clipboard
const HelloWorldIntentHandler = {
  canHandle(handlerInput) {
    return handlerInput.requestEnvelope.request.type === 'IntentRequest'
      && handlerInput.requestEnvelope.request.intent.name === 'HelloWorldIntent';
  },
  async handle(handlerInput) {
    const { accessToken } = handlerInput.requestEnvelope.context.System.user;
    let speechText = '';
    
    if (!accessToken) {
      speechText = 'You must authenticate with your Amazon Account to use this skill. I sent instructions for how to do this in your Alexa App';
      return handlerInput.responseBuilder
        .speak(speechText)
        .withLinkAccountCard()
        .getResponse();
    } else {
      speechText = 'Hello World!';
      return handlerInput.responseBuilder
        .speak(speechText)
        .getResponse();
    }
  }
}

And the corresponding JSON output looks like this:

Copied to clipboard
{
  "version": "1.0",
  "response": {
    "outputSpeech": {
      "type": "PlainText",
      "text": "You must authenticate with your Amazon Account to use this skill. I sent instructions for how to do this in your Alexa App"
    },
    "card": {
      "type": "LinkAccount"
    },
    "shouldEndSession": true
  },
  "sessionAttributes": {}
}

Step 4: Test Account Linking on Your Skill

When you invoke your skill from a device, you will receive a card in the Alexa app asking you to link your account.

Figure 10: Account Linking Card
Figure 10: Account Linking Card

Click on the “Link Account” link, and the Login with Amazon page will display.

Figure 11: Login with Amazon Credentials
Figure 11: Login with Amazon Credentials

Authenticate using your regular Amazon login (the same login used when shopping on Amazon.com).

The very first time, Amazon will ask you if you authorize the Alexa skill to retrieve some data from your user profile.

Figure 12: Login with Amazon - Authorization Screen
Figure 12: Login with Amazon - Authorization Screen

Click ‘Okay’ and a confirmation message appears.

Figure 13: Success - Account Linking Complete
Figure 13: Success - Account Linking Complete

Step 5: Test the Skill Again

Invoke the skill again. Now, because your account is linked, an Amazon OAuth Token is included in the input JSON document.

Copied to clipboard
{
  "session": {
    "sessionId": "SessionId.7fc6aa11-8a2c-4f3f-a1ea-001569cd0035",
    "application": {
      "applicationId": "amzn1.echo-sdk-ams.app.fb2fc3e7-55e7-4f05-851e-7ad308a6b499"
    },
    "user": {
      "userId": "amzn1.ask.account.AFP3ZWPOS2BGJR7OWJZ3DHPKMOMNWY4AY66FUR7ILBWANIHQN73QHMAHCTVTAHFPUV3WAFNGKBYW5LFUE2WV4CCGEISSPHBHCW5SCYJDL3DLWRRRBB4CQIP3X3PV65V2AYMMXSNFPKHPZJFVAH5AHKHDLAER67H3AHL4XBUU76XEH5BGDZZNGV5T6HHAGN6KGZI777J3VA7WGPA",
      "accessToken": "Atza|IQEBLjAsAhRBk1-yYVTk9HhZEQnTGL9F3RHS5gIUG0rrerkVvpVTF5kIFWBvZIx7QtJCkzsRFRf1ZAIZeRz6FJwdeyQCLPEbqLnEKU-zQF4n9x76Dl24Rt7HiltefBilnDm0c2PZQP_IUBAzcm93CIDxsMYhEmW_Pr0Tm9tIrGzNzVntLgyiUeXmasL1bUOIv_om66ZVwd7urpyiJSoSbA-1NQ7O9AKC2qXMqvFpvFUBSvgCYoTyyAkOePN63FCaq9NJPYbJLuocqcuyGz9mygNqp9_mNRWRRzcoeSTxpUoa8LxW-IvVVFEA1omCfXmcVijEZA6nbi-EzheMG7fu1y0XNGPEy40Csq7H07wrSqksz9IDIUd4tmqiYsJpN4dxfoGddEauC3i4eLCvsg8gbu963CqqUQ3COxgrWKTsqX8AsT8FCFvmfW3IYfhCG6KuPw8qntBgAU-W9pW523lERQKLxzI07UHyMd2R-Fnaw8IWbBYFCbblwIJhf6twjz9z_4h320f4ywczBa3k_LCoE0VpidER7rVgBtfreox-XYqV5jw"
    },
    "new": true
  },
  "request": {
    "type": "IntentRequest",
    "requestId": "EdwRequestId.31777921-9438-44f7-b271-6b9808d5fba9",
    "timestamp": "2016-05-27T16:18:57Z",
    "intent": {
      "name": "SayHello",
      "slots": {}
    },
    "locale": "en-US"
  },
  "version": "1.0"
}

Your code can use this access token to fetch the user profile data from the Amazon Profile service API. Here is an asynchronous function to retrieve the Amazon profile.  This function uses the Axios request library, which you can add by typing “npm install axios” in your project’s root directory. You can then import it at the top of your index.js file.

Copied to clipboard
const axios = require('axios');

And then in your handle function (notice the async and await keywords):

Copied to clipboard
const HelloWorldIntentHandler = {
  canHandle(handlerInput) {
    return handlerInput.requestEnvelope.request.type === 'IntentRequest'
      && handlerInput.requestEnvelope.request.intent.name === 'HelloWorldIntent';
  },
  async handle(handlerInput) {
    const { accessToken } = handlerInput.requestEnvelope.context.System.user;
    let speechText = '';
    
    if (!accessToken) {
      speechText = 'You must authenticate with your Amazon Account to use this skill. I sent instructions in how to do this in your Alexa App';
      return handlerInput.responseBuilder
        .speak(speechText)
        .withLinkAccountCard()
        .getResponse();
    } else {
      const amznProfileUrl = `https://api.amazon.com/user/profile?access_token=${accessToken}`;
      try {
        const response = await axios.get(amznProfileUrl);
        speechText = `Hello, ${response.data.name.split(" ")[0]}!`;
        
      } catch (error) {
        console.error(error);
        speechText = 'Hello!';
      }
      return handlerInput.responseBuilder
          .speak(speechText)
          .getResponse();
    }
  }
}

The code above will return the following JSON output:

Copied to clipboard
{
  "version": "1.0",
  "response": {
    "outputSpeech": {
      "type": "PlainText",
      "text": "Hello, Sebastien"
    },
    "shouldEndSession": true
  },
  "sessionAttributes": {}
}

Keep Us Posted on Your Success

Congratulations, if you coded along to this point, you have successfully implemented Account Linking with the Login with Amazon service.

Tell us how you’re enhancing your Alexa skills using account linking by tweeting us @AlexaDevs. For further info, check out our developer pages on Account Linking and how to use the Login with Amazon service.