AVS Device SDK Authorization

The Alexa Voice Service (AVS) Device SDK uses Login with Amazon (LWA) to authorize your client's requests with one of the following protocols:

To authenticate the SDK with LWA, your device sends an access token to AVS with every request. The SDK abstracts the token retrieval process by using the AuthDelegateInterface. This abstraction enables the SDK to work with any of the existing methods to acquire access tokens. It also allows you to specialize your implementation of AuthDelegateInterface without changing the code that relies on the AuthDelegateInterface.

How AuthDelegateInterface works

You inject an instance of AuthDelegateInterface into your product to abstract the LWA token retrieval process. How you implement this abstraction depends on the authorization method you're using.

If you've based your product on the sample app

The sample app uses code-based linking authorization. When the sample app initializes, it creates an instance of AuthDelegateInterface called CBLAUthDelegate and passes it to these methods:

To set up your product up with code-based linking, inject your implementation of AuthDelegateInterface into the same places as the sample app

If you haven't based your product on the sample app

If your product isn't based on the sample app, you're using the Companion App, companion site or the on-product authorization method. You must create a custom instance of AuthDelegateInterface that communicates with the Alexa Communications Library (ACL).

To do this, pass your instance of AuthDelegateInterface into the MessageRouter constructor call.

Next, pass your MessageRouter instance into AVSConnectionManager::create(). AVSConnectionManager manages your persistent connection with AVS.

Required methods

AuthDelegateInterface contains abstract methods that you must use in your implementation.

Get an LWA authorization token

getAuthToken()

Every time you make a call to AVS, you must check if you have a valid token.

getAuthToken() returns the current access token.

  • Returns an empty string if it's your first time requesting a token or an access token expires.
  • Call getAuthToken() immediately before sending any messages to AVS. The ACL handles token refresh automatically.
  • Proper implementations of getAuthToken() preemptively refresh access tokens before they expire, meaning you can send requests to AVS without waiting for a refresh.

Example

virtual std::string getAuthToken() = 0;

Track state changes

addAuthObserver() and removeAuthObserver()

It's important to track any changes to the AuthDelegateInterface state. Tracking prevents requests from failing due to an expired authorization token. Tracking also informs your client when the authorization process restores.

To track the AuthDelegateInterface state, use the following abstract methods: addAuthObserver() and removeAuthObserver().

When the authorization state changes, addAuthObserver() and removeAuthObserver() manage instances of AuthObserverInterface that receive notifications.

Example

virtual void addAuthObserver(std::shared_ptr<avsCommon::sdkInterfaces::AuthObserverInterface> observer) = 0;
virtual void removeAuthObserver(std::shared_ptr<avsCommon::sdkInterfaces::AuthObserverInterface> observer) = 0;

onAuthStateChange()

You report state changes to the observers with onAuthStateChange(). This method takes two parameters, the state and an error code. You can also receive callbacks when the state changes by calling setAuthObserver().

Parameter Description
State The new State of the authorization delegate.
Error code Error code that provides details about how the state.

Handle customer data

CustomerDataHandler()

Your implementation of AuthDelegateInterface must retain the current access token and refresh it before it expires. To refresh the token transfer device properties that might hold customer-specific data. You must wipe the customer data before refreshing the token.

To wipe customer data, implement an instance of the CustomerDataHandler interface and its abstract method clearData(). You must call cleardata() for each instance of CustomerDataHandler. You should wipe the data when the user resets the product or if the primary user associated with the product changes.

Example

virtual void clearData() = 0;

One way to incorporate CustomerDataHandler into your implementation is to use multiple inheritance and derive your implementation from both AuthDelegateInterface and CustomerDataHandler.

Example

class MyAuthDelegate
        : public avsCommon::sdkInterfaces::AuthDelegateInterface
        , public registrationManager::CustomerDataHandler {
    ...
};

SDK authorization flows

Companion app

Companion app authorization is useful for devices headless devices, such as a smart speaker. It provides an interface for users to generate Authorization Codes and register device with AVS

The AVS Device SDK doesn't provide a companion app – you must create one for your product.

Companion app data flow companion app data flow

To integrate AuthDelegateInterface with a companion app to retrieve access tokens

  1. Check for a valid Refresh Token token. If you already have a valid refresh token, skip to step 7.
  2. Load the Product ID and Device Serial Number parameters.
  3. Generate a Code Verifier and Code Challenge pair. Retain for use in later steps.
  4. Connect your product to the Companion App using a supported protocol, such as Bluetooth or Wi-Fi. Implement this functionality in the manner that best fits your product.
    • After connecting, get the Product ID, Device Serial Number, and Code Challenge.
  5. Using the Companion App, send the Authorization Code, Client ID, and Redirect URI to your product. Implement this functionality in the manner that best fits your product. Retain these values for use in later steps.
  6. Get an Access token and Refresh Token. Send a POST request to the LWA.
  7. The Access Token and Refresh Token can expire. To refresh them, send a refresh token POST request to the LWA.

Get token

Gets an Access Token and Refresh Token from the LWA server.

Sample request

POST: https://api.amazon.com/auth/O2/token
Parameter Description
grant_type authorization_code
code The authorization code received from the companion app
redirect_uri The Redirect URI received from the companion app
client_id The Client ID received from the companion app
code_verifier The Code Verifier initially generated by the product

Sample response

If this request times out or fails due to a server error, retry after a delay until it succeeds or the product shuts down.

HTTP/1.1 200 OK
Content-Type: application/json;charset UTF-8
 {
    "access_token":"...",
    "refresh_token":"Atzr|IQEBLzAtAhRPpMJxdwVz2Nn6f2y-tpJX2DeX..."
    "token_type":"bearer",
    "expires_in":3600,
    "code_verifier: "..."
 }
Parameter Description
access_token The access token
refresh_token The refresh token
token_type bearer
expires_in The number of seconds for which the access token is still valid

Refresh token

Refreshes an Access Token and Refresh Token from the LWA server.

Sample request

POST: https://api.amazon.com/auth/O2/token
Parameter Description
grant_type refresh_token
refresh_token The refresh token
client_id The Client ID received from the companion app.

Sample response

HTTP/1.1 200 OK
Content-Type: application/json;charset UTF-8
 {
    "access_token":"...",
    "refresh_token":"Atzr|IQEBLzAtAhRPpMJxdwVz2Nn6f2y-tpJX2DeX..."
    "token_type":"bearer",
    "expires_in":3600,
 }
Parameter Description
access_token The access token
refresh_token The refresh token
token_type bearer
expires_in The number of seconds for which the access token is still valid

Companion site

Companion site authorization is for product manufacturers want to authorize users with a webpage. The AVS Device SDK doesn't provide a companion site – you must create one for your product.

To retrieve LWA access tokens for your companion site, your implementation of AuthDelegateInterface must perform the following steps.

Companion site data flow Companion site data flow

To retrieve LWA access tokens

  1. Check if a valid Session ID exists. If you have one, skip to step 5.
  2. Load the Product ID and Device Serial Number.
  3. Register your product with the companion site. To register, send the Product ID and Device Serial Number from your product to the Companion Site. The Companion Site needs to respond with a valid Registration Code and a Session ID.
  4. Wait until you receive the signal that the consent request has completed.
  5. Request the Access Token. To do this, send a valid Session ID from your product to the Companion Site. After this process completes, the Companion Site responds with the Access Token.

Code based linking (CBL)

The AVS Device SDK sample app provides an example implementation of the Code Based Linking with the class CBLAUthDelegate.

You can use the provided CBLAUthDelegate implementation exactly as provided in your product. If you want to create your own implementation of Code Based Linking, you must create the implementation yourself.

Companion app data flow CBL data flow

To create a custom CBLAUthDelegate

  1. Load the Client ID, Product ID and Device Serial Number parameters.
  2. Check for a valid Refresh Token. If you have one, skip to step 5.
  3. Send a Device Authorization Request to LWA. For more details, see Device Authorization Request.
  4. Prompt the user to visit your Verification URI and enter the User Code. For more details, see Direct the user to log in for details.
  5. At the same time that the user is entering User Code, poll LWA to acquire an initial access token by sending Device Token Requests to LWA. For more details, see Device Token Request.

On product

To create your own implementation of the On Product authorization, you must provide an implementation of AuthDelegateInterface that uses the Android or iOS LWA Library operations described in the On Product documentation.