Step 4: Make an Authorization Request from Your App


In this step, you make an authorization request to the Alexa app to get the user's Amazon authorization code. If the Alexa app isn't installed on the user's mobile device, you make the request to the Login with Amazon (LWA) authorization server. The authorization code is valid for five minutes. For details about the URL parameters, see URIs and endpoints.

Get the Amazon authorization code

Follow these steps to get the user's Amazon authorization code from the Alexa app or the LWA authorization server.

To get the Amazon authorization code

  1. If your backend supports PKCE, generate the code_verifier and derive the code_challenge using SHA-256, as defined in RFC 7636, before constructing the URLs.
  2. From your app backend, construct the Alexa app URL and the LWA fallback URL with the required query parameters. Include the state for cross-site request forgery (CSRF) protection and the PKCE code_challenge and code_challenge_method parameters for enhanced security.
  3. Determine whether the Alexa app is installed on the user's device.
  4. If the Alexa app is installed, open the Alexa app URL. If the Alexa app isn't installed, open the LWA fallback URL in an in-app browser tab, not a native browser app.
  5. After the user acknowledges the linking request, the Alexa app or LWA redirects the user back to your app at your redirect URL with the Amazon authorization code and state.
    For details about how to handle the redirect, see the Apple guidelines on Supporting Universal Links in Your App and Android guidelines in Handling Android App Links.
  6. To prevent CSRF attacks, validate the returned state value against the value you sent in step 1. If your backend supports PKCE, use the code_verifier to validate the token endpoint, based on the stored PKCE parameters.
  7. Extract the Amazon authorization code from the redirect.

Success response

After the user acknowledges the linking request, the Alexa app or LWA redirects the user back to your app with the Amazon authorization code. The following example shows a successful redirect to your app's Universal Link or App Link from the Alexa app.

https://yourAppRedirectUri?
code=amazonAuthorizationCode&
state=yourStateValue

The following example shows a successful redirect to your app's Universal Link or App Link from LWA.

https://yourRedirectURL?
code=amazonAuthorizationCode&
scope=alexa::skills:account_linking&
state=yourStateValue

For additional details about OAuth2.0 authorization responses, see Authorization Response.

Error response

If the user denies the request or an error occurs, the Alexa app or LWA redirects the user back to your app with an error. The following example shows an error redirect:

HTTP 200
https://yourAppRedirectUri?
error=access_denied&
error_description=The%20user%20denied%20the%20request.&
state=yourStateValue

For additional details about OAuth2.0 error responses, see Error Response.

Browser fallback

If the user's device can't launch your app by using the redirect URL that you configured, the Alexa app redirects the user to that same redirect URL in their default browser.

Fallback might happen, for example, when one of the following occurs:

  • Universal Links or App Links aren't enabled in your app.
  • Universal Links or App Links aren't enabled in your app for the redirect URLs that you provided.
  • The version of the app on the user's device is an older version that doesn't support Universal Links or App Links.

To handle these scenarios, host a web page at the same URL as your Universal Link or App Link to receive the authorization code. When the user opens your web page, you might request them to log in so that you can get the authorization code from your service.

iOS examples

Android examples

State generation example

In this example, the app generates and validates the state between the request and the response. You must validate incoming requests by using the state to prevent cross-site request forgery.

import Foundation
import Security

class StateHelper {
    private static let STATE_VALID_FOR = 3600
    // Base64 (iOS + TimeStamp + Secure Random UUID)
    private static let NUMBER_OF_PARAMETER = 3
    
    static func generateState(session: Session)-> String {
        var buffer = Data(count: 30)
        let _ = buffer.withUnsafeMutableBytes {
            SecRandomCopyBytes(kSecRandomDefault, 30, $0)
        }
        let state = ("iOS." + String(Int64(Date().timeIntervalSince1970)) + "." + buffer.base64EncodedString()).encodeToURISafeBase64()
        
        // store state in session manager for future validation
        session.state = state
        LocalSessionManager.saveSession(session: session)
        
        return state
    }
    
    static func validateState(state: String) -> Bool {
        guard let originalState = LocalSessionManager.loadSession()?.state  else {
            return false
        }
        if state != originalState {
            return false
        }
        if let timeStampString = originalState.decodeFromURISafeBase64()?.split(separator: "."), timeStampString.count == NUMBER_OF_PARAMETER, let timeStamp = Int64(timeStampString[1]){
            if Int64(Date().timeIntervalSince1970) - timeStamp <= STATE_VALID_FOR {
                return true
            }
        }
        if let session = LocalSessionManager.loadSession() {
            session.state = nil
            LocalSessionManager.saveSession(session: session)
        }
        return false
    }
    
    private init() {}
}

extension String {
    func decodeFromURISafeBase64() -> String? {
        let base64String = String(self.map {
            // replace unsafe characters 
            character in
            if character == "." {
                return  "+"
            } else if character == "_" {
                return "/"
            } else if character == "-" {
                return "="
            }
            return character
        })
        guard let data = Data(base64Encoded: base64String) else {
            return nil
        }
        return String(data: data, encoding: .utf8)
    }
    
    func encodeToURISafeBase64() -> String {
        return String(Data(self.utf8).base64EncodedString().map{
            // replace back unsafe characters 
            character in
            if character == "+" {
                return  "."
            } else if character == "/" {
                return "_"
            } else if character == "=" {
                return "-"
            }
            return character
        })
    }
}

Errors

If an error occurs when your app tries to get the Amazon authorization code, the redirect_uri that the Alexa app uses to redirect the user back to your app includes an error query parameter, as described by the OAuth 2.0 specification. The Alexa app and the LWA fallback both follow the OAuth 2.0 specification, so they both return the same error codes to your app. For details about why the request to get the Amazon authorization code failed, check the error_description query parameter and the OAuth 2.0 specification description for that error code.

Error code Message to show to user Possible causes

invalid_request

We are experiencing a problem connecting with Alexa to link your account. Please try again later.

Request is missing state, scope, and/or response_type

unauthorized_client

We are experiencing a problem connecting with Alexa to link your account. Please try again later.

The provided client_id doesn't have access to request consent to link the user's account

access_denied

None. (The user shouldn't see an error message because they were the one who denied the access.)

The user rejected the request to link their account

unsupported_response_type

We are experiencing a problem connecting with Alexa to link your account. Please try again later.

Parameter response_type isn't equal to code

invalid_scope

We are experiencing a problem connecting with Alexa to link your account. Please try again later.

Invalid scope parameter

server_error

Sorry, Alexa encountered an unexpected error while trying to link your account. Please try again.

Unexpected server error

temporarily_unavailable

Sorry, Alexa encountered a momentary error while trying to link your account. Please try again later.

Temporary server error


Was this page helpful?

Last updated: frontmatter-missing