Your Alexa Dashboards Settings

Authorize from an AVS Product (Android/iOS)

To access the Alexa Voice Service, your Alexa-enabled Android or iOS app needs to obtain a Login with Amazon (LWA) access token, which will be sent up with each request to the Alexa Voice Service. This document explains how to obtain an access token using the LWA SDK.

When to Use This Method

Scenario: You want to add Alexa to your Android or iOS application. You do not have a headless device, like a smart speaker, that requires you to authorize it and associate it with a customer’s account.

Using the Login with Amazon SDK

Please use the tabs below to select your operating system:

Follow the instructions below to use LWA in your Android app.

  • Register a mobile app in the Alexa developer portal and generate an API key for your app. For instructions on how to create an account and register an app see Getting Started with AVS.
  • Navigate to the Login with Amazon Getting Started for Android and complete steps 1, 4, and 5.
  • Then complete the following steps to obtain an LWA access token to use with AVS:
  1. Add LWA to your Android project. See Install the Login with Amazon Library under Create a Login with Amazon Project.

  2. Import the LWA API to your source file. To import the LWA API, add the following import statements to your source file:

    import com.amazon.identity.auth.device.AuthError;
    import com.amazon.identity.auth.device.api.Listener;
    import com.amazon.identity.auth.device.api.authorization.AuthCancellation;
    import com.amazon.identity.auth.device.api.authorization.AuthorizationManager;
    import com.amazon.identity.auth.device.api.authorization.AuthorizeListener;
    import com.amazon.identity.auth.device.api.authorization.AuthorizeRequest;
    import com.amazon.identity.auth.device.api.authorization.AuthorizeResult;
    import com.amazon.identity.auth.device.api.authorization.Scope;
    import com.amazon.identity.auth.device.api.authorization.ScopeFactory;
    import com.amazon.identity.auth.device.api.workflow.RequestContext;
    
  3. Initialize RequestContext.

    You will need to declare a RequestContext member variable and create a new instance of the class. To create the instance, pass in the current application context to the static factory method. The best place to initialize the RequestContext is in the onCreate method of your Activity. For example:

    private RequestContext mRequestContext;
    
    @Override
    protected void onCreate(Bundle savedInstance) {
        super.onCreate(savedInstance);
        mRequestContext = RequestContext.create(this);
    }
    
  4. Create an AuthorizeListenerImpl.

    AuthorizeListenerImpl extends the AuthorizeListener abstract class, and will process the result of the authorize call. It contains three methods: onSuccess, onError, and onCancel. The AuthorizeResult object passed into the onSuccess method will contain the access token.

    private class AuthorizeListenerImpl extends AuthorizeListener {
    
        /* Authorization was completed successfully. */
        @Override
        public void onSuccess(final AuthorizeResult authorizeResult) {
        }
    
        /* There was an error during the attempt to authorize the application. */
        @Override
        public void onError(final AuthError authError) {
        }
    
        /* Authorization was cancelled before it could be completed. */
        @Override
        public void onCancel(final AuthCancellation authCancellation) {
        }
    }
    
  5. Create an instance of AuthorizeListenerImpl and register it.

    Create an instance of your AuthorizeListenerImpl and register it with your RequestContext instance. When the AuthorizeManager.authorize call is made, your RequestContext instance will invoke the appropriate callback method in your AuthorizeListener with the result of the authorize request. The best place to register your AuthorizeListenerImpl instance is in the onCreate method.

    @Override
    protected void onCreate(Bundle savedInstance) {
        super.onCreate(savedInstance);
        mRequestContext = RequestContext.create(this);
        mRequestContext.registerListener(new AuthorizeListenerImpl());
    }
    
  6. Override the onResume method.

    Override the onResume method in your Activity. Call super.onResume() as well as the onResume method on your RequestContext instance. This will notify the RequestContext to invoke your AuthorizeListener when your app is resumed if there is a callback ready from your AuthorizeManager.authorize call.

    @Override
    protected void onResume() {
        super.onResume();
        mRequestContext.onResume();
    }
    
  7. Call AuthorizeManager.authorize.

    In the onClick handler for your Login with Amazon button, call authorize to prompt the user to log in and authorize your application. This method is responsible for authorizing the customer in one of the following ways:

    • Switches to the system browser and lets the customer sign in and consent to the requested information.

    • Switches to web view in a secure context to let the customer sign in and consent to the requested information.


    This secure context for the second point above, is currently made available as the Amazon Shopping app on Android devices. Amazon devices running Fire OS (for example Kindle tablets and Fire TV devices) always use this option even if there is no Amazon Shopping app on the device. Because of this, if the customer is already signed in to the Amazon Shopping app, this API will skip the sign-in page, leading to a Single Sign On (SSO) experience for the customer.

    When your application is authorized, it is authorized for one or more data sets known as scopes. The first parameter is an array of scopes that encompass the user data that you are requesting from LWA. The first time a user logs in to your app, they will be presented with a list of the data you are requesting and asked for approval. LWA when used with AVS currently supports the alexa:all scope.

    The call to authorize is asynchronous, and your AuthorizeListenerImpl instance will be invoked with the result of your call.

    private RequestContext mRequestContext;
    private static final String PRODUCT_ID = "INSERT YOUR PRODUCT ID FROM AMAZON DEVELOPER CONSOLE";
    private static final String PRODUCT_DSN = "INSERT UNIQUE DSN FOR YOUR DEVICE";
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mRequestContext = RequestContext.create(this);
        mRequestContext.registerListener(new AuthorizeListenerImpl());
    
        // Find the button with the login_with_amazon ID
        // and set up a click handler
        mLoginButton = (Button) findViewById(R.id.login_with_amazon);
        mLoginButton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                final JSONObject scopeData = new JSONObject();
                final JSONObject productInstanceAttributes = new JSONObject();
    
                try {
                    productInstanceAttributes.put("deviceSerialNumber", PRODUCT_DSN);
                    scopeData.put("productInstanceAttributes", productInstanceAttributes);
                    scopeData.put("productID", PRODUCT_ID);
    
                    AuthorizationManager.authorize(new AuthorizeRequest.Builder(mRequestContext)
                        .addScope(ScopeFactory.scopeNamed("alexa:all", scopeData))
                        .forGrantType(AuthorizeRequest.GrantType.ACCESS_TOKEN)
    		                .shouldReturnUserData(false)
                        .build());
                } catch (JSONException e) {
                    // handle exception here
                }
            }
        });
    }
    
  8. Create a TokenListener.

    Implement the Listener<AuthorizeResult, AuthError> interface. Your listener will process the result of the getToken call. Listener contains two methods, onSuccess and onError (it does not support onCancel because there is no way to cancel a getToken call). onSuccess receives an AuthorizeResult object with token data, while onError receives an AuthError object with information on the error.

    public class TokenListener implements Listener<AuthorizeResult, AuthError> {
        /* getToken completed successfully. */
        @Override
        public void onSuccess(AuthorizeResult authorizeResult) {
        }
    
        /* There was an error during the attempt to get the token. */
        @Override
        public void onError(AuthError authError) {
        }
    }
    
  9. Implement onSuccess for your AuthorizeListener.

    In onSuccess, call AmazonAuthorizationManager.getToken to retrieve the access token. getToken, like authorize, uses an asynchronous listener interface. For getToken, that interface is Listener<AuthorizeResult, AuthError>, not AuthorizationListener.

    @Override
    public void onSuccess(Bundle response) {
        AuthorizationManager.getToken(this, new Scope[] { ScopeFactory.scopeNamed("alexa:all") }, new TokenListener());
    }
    
  10. Implement onSuccess for your TokenListener.

    onSuccess has two tasks:

    • To retrieve the access token from the Bundle.
    • To set the UI state to logged in, which indicates a user is logged in and provides the means necessary to log out.
    /* getToken completed successfully. */
    @Override
    public void onSuccess(AuthorizeResult authorizeResult) {
        String accessToken = authorizeResult.getAccessToken();
    }
    
  11. In the onStart method of your Activity, call getToken to see if the application is still authorized.

    • getToken retrieves the raw access token that can be used when making requests to AVS.
    • getToken requires the same scopes you requested in your call to authorize.
    private static final Scope ALEXA_ALL_SCOPE = ScopeFactory.scopeNamed("alexa:all");
    
    @Override
    protected void onStart(){
        super.onStart();
        AuthorizationManager.getToken(this, new Scope[] { ALEXA_ALL_SCOPE }, new TokenListener());
    }
    
  12. Now you have an access token that can be used for requests to AVS.

Follow the instructions below to use LWA in your iOS app.

  • Register a mobile app in the Alexa developer portal and generate an API key for your app. For instructions on how to create an account and register an app see Getting Started with AVS.
  • Navigate to Login with Amazon Getting Started for iOS and complete steps 1, 4, and 5.
  • Then complete the following steps to obtain an LWA access token to use with AVS:
  1. Add LWA to your iOS project. See Install the Login with Amazon Library under Create a Login with Amazon Project.

  2. Import the LWA API to your source file.

    To import the LWA API, add the following #import statements to your source file:

    #import <LoginWithAmazon/LoginWithAmazon.h>
    
  3. Call authorize:withHandler: in onLoginButtonClicked.

    If you followed the steps in Add a Login with Amazon Button to Your App, you should have an onLoginButtonClicked: method linked to a Login with Amazon button. In that method, call authorize:withHandler: to prompt the user to login and authorize your application.

    This method will enable the user to sign in and consent to the requested information in one of the following ways:

    1. Switches to web view in a secure context (if the Amazon Shopping app is installed to the device)
    2. Switches to Safari View Controller (on iOS 9 and later)
    3. Switches to the system browser (on iOS 8 and earlier)

    The secure context for the first option is available when the Amazon Shopping app is installed to the device. If the user is already signed in to the Amazon Shopping app, this API will skip the sign in page, leading to a Single Sign-On (SSO) experience.

    The first parameter to authorize:withHandler: is an AMZNAuthorizeRequest object that indicates what scope your application is requesting authorization for. A scope encompasses the user data you are requesting from Login with Amazon. The first time a user logs in to your app, they will be presented with a list of the data you are requesting and asked for approval.

    The second parameter to authorize:withHandler: is AMZNAuthorizationRequestHandler, described in the next step.

  4. Create an AMZNAuthorizationRequestHandler block object.

    AMZNAuthorizationRequestHandler processes the result of the authorize:withHandler: call. To learn more about objective-c blocks, see Working with Blocks on developer.apple.com.

    The first parameter of AMZNAuthorizationRequestHandler is an AMZNAuthorizeResult object. After a user is authorized successfully, AMZNAuthorizeResult will contain an access token which can be used to access a user’s profile data, and an AMZNUser object, which contains the user’s profile data.

    The second parameter of AMZNAuthorizationRequestHandler is a Boolean called userDidCancel. This parameter will be set to true if the user:

    1. Closes the Safari View Controller during login and authorization (on iOS 9 and later)
    2. Closes the web view in the Amazon Shopping app
    3. Cancels the login or reject authorization

    The third parameter of AMZNAuthorizationRequestHandler is an NSError object which contains error details if the login or authorization fails due to the SDK or the authorization server.

    NSString *productId = @"INSERT YOUR PRODUCT ID FROM AMAZON DEVELOPER CONSOLE";
    NSString *productDsn = @"INSERT UNIQUE DSN FOR YOUR DEVICE";    
    
    - (IBAction) onLogInButtonClicked:(id)sender {
        NSDictionary *scopeData = @{@"productID": productId,
                                    @"productInstanceAttributes": @{@"deviceSerialNumber": productDsn}};
    
        id<AMZNScope> alexaAllScope = [AMZNScopeFactory scopeWithName:@"alexa:all" data:scopeData];
    
        AMZNAuthorizeRequest *request = [[AMZNAuthorizeRequest alloc] init];
        request.scopes = @[alexaAllScope];
        request.grantType = AMZNAuthorizationGrantTypeToken;
    
        //Make an Authorize call to the LWA SDK.
        AMZNAuthorizationManager *authManager = [AMZNAuthorizationManager sharedManager];
        [authManager authorize:request withHandler:^(AMZNAuthorizeResult *result, BOOL userDidCancel, NSError *error) {
            if (error) {
                // Notify the user that authorization failed
                [[[UIAlertView alloc] initWithTitle:@"" message:[NSString stringWithFormat:@"User authorization failed due to an error: %@", error.localizedDescription] delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] show];
            } else if (userDidCancel) {
                // Notify the user that the authorization was cancelled
                [[[UIAlertView alloc] initWithTitle:@"" message:@"Authorization was cancelled prior to completion. To continue, you will need to try logging in again." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] show];
            } else {
                // Fetch the access token and return to controller
                self.token = result.token;
                [self userSuccessfullySignedIn];
    
            }
        }];
    }
    
  5. Check for user login at startup.

    If a user logs into your app, closes the app, and restarts the app later, the app is still authorized to retrieve data. The user is not logged out automatically. At startup, you can show the user as logged in if your app is still authorized. This section explains how to use authorize:withHandler: to see if the app is still authorized.

    1. Create an AMZNAuthorizeRequest object and specify scopes that indicate the user data your application is requesting authorization for. For more information, see step 3.
    2. Set AMZNAuthorizeRequest.interactiveStrategy to AMZNInteractiveStrategyNever. AMZNAuthorizeRequest supports multiple strategies for prompting user login:

      • AMZNInteractiveStrategyAuto (default): The SDK looks for a locally stored authorization grant from previous authorize:withHandler: responses. If one is available, valid, and contains all requested scopes, the SDK will return a successful response via AMZNAuthorizationRequestHandler, and will not prompt the user to login. Otherwise, the user will be prompted to login.
      • AMZNInteractiveStrategyAlways: The SDK will always prompt the user to login regardless of whether they have previously been authorized to use the app. When the user is prompted, the SDK will remove all locally cached authorization grants for the app.
      • AMZNInteractiveStrategyNever: The SDK looks for a locally stored authorization grant from previous authorize:withHandler responses. If one is available, valid, and contains all requested scopes, the SDK will return an AMZNAuthorizeResult object that contains an access token and user profile data. Otherwise, it will return an NSError object via AMZNAuthorizationRequestHandler.
    // Build an authorize request.
    AMZNAuthorizeRequest *request = [[AMZNAuthorizeRequest alloc] init];
    request.scopes = @[alexaAllScope];
    request.grantType = AMZNAuthorizationGrantTypeToken;
    
    request.interactiveStrategy = AMZNInteractiveStrategyNever;
    
    [AMZNAuthorizationManager sharedManager] authorize:request
    withHandler:^(AMZNAuthorizeResult *result BOOL
    userDidCancel NSError *error) {
       if (error) {
            // Error from the SDK, indicating the user was not previously authorized to your app for the requested scopes.
       } else {
            // Fetch the access token and return to controller
            self.token = result.token;
            [self userSuccessfullySignedIn];
       }
    }];
    
  6. Implement application:openURL:sourceApplication:annotation: in the class in your project that handles the UIApplicationDelegate protocol.

    By default this will be the AppDelegate class in your project. When the app presents the Amazon login page, if the user completes log in, it will redirect to the app using the URL Scheme the app registered earlier. That redirect is passed to application:openURL:sourceApplication:annotation:application:openURL:sourceApplication:annotation: returns YES if the URL was successfully handled.

    handleOpenURL:sourceApplication: is an SDK library function that will handle LWA redirect URLs for you. If handleOpenURL:sourceApplication: returns YES, then the URL was handled.

    - (BOOL)application:(UIApplication *)application
       openURL:(NSURL *)url
       sourceApplication:(NSString *)sourceApplication
       annotation:(id)annotation
    {
        // Pass on the url to the SDK to parse authorization code from the url.
    
        BOOL isValidRedirectSignInURL =
          [AIMobileLib handleOpenURL:url sourceApplication:sourceApplication];
        if(!isValidRedirectSignInURL)
            return NO;
    
        // App may also want to handle url
        return YES;
    }
    
  7. Now you have an access token that can be used for requests to AVS.

Resources