amzn / selling-partner-api-models

This repository contains OpenAPI models for developers to use when developing software to call Selling Partner APIs.
Apache License 2.0
611 stars 733 forks source link

getAuthorizationCode() for Auth MWS Token - MissingAuthenticationToken #1311

Closed leoplct closed 2 years ago

leoplct commented 3 years ago

I am following this guide to run SP-API using my existing MWS AUTH token: https://github.com/amzn/selling-partner-api-docs/blob/main/guides/en-US/use-case-guides/authorization-api-use-case-guide/authorization-api-use-case-guide-v1.md

When I run this code I get the error: Access to requested resource is denied - MissingAuthenticationToken. What am i missing? I just did step-by-step as suggested in the doc.

def self.get_authorization_code()
         selling_partner_id = 'A27XXXXXX'
        mws_auth_token     = 'amzn.mws.cXXXXX'
        endpoint           = "sellingpartnerapi-eu.amazon.com"
        url = "https://#{endpoint}/authorization/v1/authorizationCode"

        # Passing selling_partner_id, DeveloperId and MWS auth token as GET PARAMS
        return Faraday.get(url, {
            sellingPartnerId: selling_partner_id, 
            developerId: ENV['MWS_EU_DEVELOPER_ID'],
            mwsAuthToken: mws_auth_token
        })
end
marconline commented 3 years ago

Did you add the "X-Amz-Security-Token" header? Check here: https://marco-tibaldeschi.medium.com/amazon-sp-api-auth-auth-demystified-ab3bc746729b

leoplct commented 3 years ago

Thank you very much for your guide. I believe I am near the end. I just got Access token is missing in the request header.

I have checked all request headers and it looks ok. Do you know what am I missing?

REQUEST

INFO -- request: GET https://sellingpartnerapi-eu.amazon.com/authorization/v1/authorizationCode?developerId=123456&mwsAuthToken=amzn.mws.XXXXX&sellingPartnerId=A27E0XXXXX
INFO -- request: host: "sellingpartnerapi-eu.amazon.com"

x-amz-date: "20210504T174042Z"
x-amz-security-token: "IQoJb3JpZ2luX2VjEHoaCWXXXX"
x-amz-content-sha256: "e3b0c44298fc1c149afbf4c8996fb92427ae41e4XXXXXXXX"
authorization: "AWS4-HMAC-SHA256 Credential=ASIAXXXXXXXX/20210504/eu-west-1/execute-api/aws4_request, SignedHeaders=host;x-amz-content-sha256;x-amz-date;x-amz-security-token, Signature=0f251c3abca8a73a764671418d64aXXXXXXXXX"
x-amz-access-token: "Atc|MQEBILWaaHz4CKGlzkSiMvrIqXXXXXXX"
user-agent: "App/1.0 (Language=Ruby)"
content-type: "application/json"

INFO -- response: Status 403
INFO -- response: date: "Tue, 04 May 2021 17:40:42 GMT"
content-type: "application/json"
content-length: "187"
connection: "keep-alive"
x-amzn-requestid: "2d51880c-6af3-4d93-9449-18e65b3e89e3"
x-amzn-errortype: "AccessDeniedException"
x-amz-apigw-id: "e0IMMGe-joEFsvA="

Access token is missing in the request header.

First I request a grantless access token

    ACCESS_TOKEN_URL = 'https://api.amazon.com/auth/o2/token'.freeze
    AWS_SERVICE      = 'execute-api'.freeze

    def request_grantless_access_token
        body = {
          grant_type: 'client_credentials',
          client_id: ENV['SP_LWA_KEY'],
          client_secret: ENV['SP_LWA_SECRET'],
          scope: 'sellingpartnerapi::migration'
        }
        response = Faraday.post( ACCESS_TOKEN_URL, body, {
            'Content-Type' => 'application/x-www-form-urlencoded;charset=UTF-8'
          }
        )
        JSON.parse(response.body)
    end

Then I build the request

def get_authorization_code()

        selling_partner_id = 'XXXXXXX'
        region             = 'eu'
        mws_auth_token     = 'amzn.mws.XXXXXX'
        endpoint           = "sellingpartnerapi-eu.amazon.com"

        aws_access_key_id     = ENV['SP_API_KEY']
        aws_secret_access_key = ENV['SP_API_SECRET']
        sts_iam_role_arn      = ENV['SP_IAM_ARN_ROLE']

        # REQUEST STS TOKEN
        aws_region = {
            'na' => 'us-east-1',
            'eu' => 'eu-west-1',
            'fe' => 'us-west-2'
        }[region.to_s] 

        # REQUEST STS TOKEN
        client = Aws::STS::Client.new(
            region: aws_region,
            access_key_id: aws_access_key_id,
            secret_access_key: aws_secret_access_key
        )

        # A “SessionToken” that is the value you must specify for the X-Amz-Security-Token Header
        sts_token       = client.assume_role(role_arn: sts_iam_role_arn, role_session_name: SecureRandom.uuid)

        # URL
        url          = "https://#{endpoint}/authorization/v1/authorizationCode?sellingPartnerId=#{selling_partner_id}&developerId=#{ENV['MWS_EU_DEVELOPER_ID']}&mwsAuthToken=#{mws_auth_token}"
        http_method  = 'GET'

        #SIGNED REQUEST
        request_config = {
            service: AWS_SERVICE,
            region: aws_region,
            endpoint: endpoint
        }

        # A credential provider is any object that responds to #credentials returning another object that responds to #access_key_id, #secret_access_key, and #session_token
        request_config[:credentials_provider] = sts_token

        # SIGNER: https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/Sigv4/Signer.html
        signer      = Aws::Sigv4::Signer.new(request_config)
        # Sign request: https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/Sigv4/Signer.html#sign_request-instance_method
        signature   = signer.sign_request(http_method: http_method, url: url)

        # Request Headers
        headers = signature.headers.merge({
            'x-amz-access-token' => request_grantless_access_token['access_token'],
            'user-agent' => "App/1.0 (Language=Ruby)",
            'content-type' => "application/json",
        })

        puts "---- AWS SIGN ----"
        puts "CANONICAL REQUEST: #{signature.canonical_request}"
        puts "HEADERS: #{headers}"
        puts "--------"

        conn = Faraday.new(url: url, headers: headers) do |f|
            f.response :logger # log requests and responses to $stdout
        end

        response = conn.send(http_method.downcase.to_sym) do |req|
            req.body = nil
        end

        return response
ytcitsupport-jlin commented 3 years ago

HI @leoplct Have you solved this issue? I'm having the same problem as you.

leoplct commented 3 years ago

I haven't found a solution. Maybe because I have a wrong IAM ARN (user instead of role) in my app settings. I've asked support to change it, but they ask me to delete the production app. Which is crazy because we have live users and reviews.

Mike-the-one commented 3 years ago

Anyone got this working?

marconline commented 3 years ago

@Mike-the-one Yes, I did. Even if a perfectly working, PII-enabled MWS token is converted to a SP-API token which hasn't access to PII. :(

github-actions[bot] commented 2 years ago

This is a very old issue that is probably not getting as much attention as it deserves. We encourage you to check if this is still an issue after the latest release and if you find that this is still a problem, please feel free to open a new issue and make a reference to this one.