Skip to content

Migrate users from MWS to SP API #123

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
jmawebtech opened this issue Feb 25, 2022 · 41 comments
Closed

Migrate users from MWS to SP API #123

jmawebtech opened this issue Feb 25, 2022 · 41 comments
Assignees
Labels
bug Something isn't working

Comments

@jmawebtech
Copy link

Hi,

I have users running on the MWS Amazon API:

https://docs.developer.amazonservices.com/en_US/dev_guide/index.html

I have a seller ID, marketplace ID, and an MWSAuthToken. How do I generate an access and refresh token from these fields? I tried this call, but it failed to work. Do you have logic?

https://sellingpartnerapi-na.amazon.com/authorization/v1/authorizationCode?sellingPartnerId=X&developerId=X&mwsAuthToken=X

{
"errors": [
{
"message": "Access to requested resource is denied.",
"code": "MissingAuthenticationToken"
}
]
}

@abuzuhri
Copy link
Owner

its very strange its request Authentication Token because this will generate the token ,
I also add this method in library and i get another error
{
"errors": [
{
"message": "Access to requested resource is denied.",
"code": "Unauthorized",
"details": ""
}
]
}

@jmawebtech
Copy link
Author

Hi,

Thanks for the information. I have an Amazon user using the Amazon MWS API. I have a seller ID, marketplace ID, and MWS token. Do you have to code to migrate the user to SP API? How do I generate a refresh token from a seller ID, marketplace ID and MWS token?

@abuzuhri
Copy link
Owner

It's look like no other code only the method you mentioned and I added to library

Do more search I will do from my side to check

@abuzuhri
Copy link
Owner

abuzuhri commented Mar 9, 2022

Hello @jmawebtech

Do you found any solution for this ?

@jmawebtech
Copy link
Author

jmawebtech commented Mar 9, 2022 via email

@abuzuhri
Copy link
Owner

which application you mean its look like no application id as parameter
can you share request sample to add it to library

@nafberger
Copy link
Contributor

hi @abuzuhri do u please have any examples on using the getAuthorizationCode call with your library, would really appreciate that

@abuzuhri
Copy link
Owner

Hello @nafberger
No its not work with me when i test

I will wait @jmawebtech reply to give more details to fix this in the API

@jmawebtech
Copy link
Author

jmawebtech commented Mar 14, 2022 via email

@nafberger
Copy link
Contributor

so @jmawebtech can u please incorporate it in the code of @abuzuhri please

@abuzuhri
Copy link
Owner

abuzuhri commented Mar 14, 2022

Hello @jmawebtech
I do some fix for our API to do the same code you sent , but i can't test beaucse i dont have MWS application and keys, can you please test this code after get last commit 94ef5ea

AmazonConnection codeAmazonConnection = new AmazonConnection(new AmazonCredential()
            {
                AccessKey = config.GetSection("MWSAmazonAPI:AccessKey").Value,
                SecretKey = config.GetSection("MWSAmazonAPI:SecretKey").Value,
                ClientId = config.GetSection("MWSAmazonAPI:ClientId").Value,
                ClientSecret = config.GetSection("MWSAmazonAPI:ClientSecret").Value,
                MarketPlace = MarketPlace.GetMarketPlaceByID(config.GetSection("FikaAmazonAPI:MarketPlaceID").Value),
                IsActiveLimitRate = true
            });
            var code = codeAmazonConnection.Authorization.GetAuthorizationCode(new Parameter.Authorization.ParameterAuthorizationCode()
            {
                developerId = "999999999999999",
                mwsAuthToken = "amzn.mws.9999999-ac85-07fc-999-9999999",
                sellingPartnerId = "AAAAAAAAAAA"
            });

@abuzuhri abuzuhri self-assigned this Mar 14, 2022
@abuzuhri abuzuhri added the bug Something isn't working label Mar 15, 2022
@jmawebtech
Copy link
Author

With your code, I get this error:

{
"errors": [
{
"message": "Access to requested resource is denied.",
"code": "Unauthorized",
"details": ""
}
]
}

My best guess is you have an issue generating the access token. My code throws a different error. In the app settings, should I leave refreshToken blank?

{
"FikaAmazonAPI": {
"AccessKey": "X",
"SecretKey": "X",
"RoleArn": "",
"ClientId": "X",
"ClientSecret": "X",
"RefreshToken": "",
"MarketPlaceID": "ATVPDKIKX0DER"
}
}

@jmawebtech
Copy link
Author

Did you add this code to get the access token? public AmazonOAuth GetAccessTokenForSPAPIMigration()
{
string data = string.Empty;

        using (HttpClient client = new HttpClient())
        {
            client.BaseAddress = new Uri("https://api.amazon.com");
            var byteArray = Encoding.ASCII.GetBytes($"{credentials.LWA_App_ClientId}:{credentials.LWA_App_ClientSecret}");
            client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray));

            Dictionary<string, string> items = new Dictionary<string, string>();
            items.Add("grant_type", "client_credentials");
            items.Add("scope", "sellingpartnerapi::migration");
            items.Add("client_id", credentials.LWA_App_ClientId);
            items.Add("client_secret", credentials.LWA_App_ClientSecret);

            FormUrlEncodedContent formUrlEncodedContent = new FormUrlEncodedContent(items);
            var rs = client.PostAsync("/auth/o2/token", formUrlEncodedContent).Result;
            data = rs.Content.ReadAsStringAsync().Result;
        }

        return JsonConvert.DeserializeObject<AmazonOAuth>(data, Serialization.Settings);
    }

@abuzuhri
Copy link
Owner

Yes this code exist already ,

Can you debug the code to double check form your side , it's hard for me test this

@nafberger
Copy link
Contributor

ok I will

@nafberger
Copy link
Contributor

this library does it successfully.

https://github.com/amz-tools/amazon-sp-api.

I checked your version and his, it seems that u skip the call to https://sts.amazonaws.com/

@nafberger
Copy link
Contributor

the other code should work. i added 2 lines for the "code" and "redirecturi"

        public AmazonOAuth GetAccessTokenForSPAPIMigration(string code, string appRedirectUri)
        {
            string data = string.Empty;

            using (HttpClient client = new HttpClient())
            {
                client.BaseAddress = new Uri("https://api.amazon.com");
                var byteArray = Encoding.ASCII.GetBytes($"{credentials.LWA_App_ClientId}:{credentials.LWA_App_ClientSecret}");
                client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray));

                Dictionary<string, string> items = new Dictionary<string, string>();
                items.Add("grant_type", "client_credentials");
                items.Add("scope", "sellingpartnerapi::migration");
                items.Add("client_id", credentials.LWA_App_ClientId);
                items.Add("client_secret", credentials.LWA_App_ClientSecret);
                items.Add("code", code);
                items.Add("redirect_uri", appRedirectUri);

                FormUrlEncodedContent formUrlEncodedContent = new FormUrlEncodedContent(items);
                var rs = client.PostAsync("/auth/o2/token", formUrlEncodedContent).Result;
                data = rs.Content.ReadAsStringAsync().Result;
            }

            return JsonConvert.DeserializeObject<AmazonOAuth>(data, Serialization.Settings);
        }
    }

@abuzuhri
Copy link
Owner

this library does it successfully.

https://github.com/amz-tools/amazon-sp-api.

I checked your version and his, it seems that u skip the call to https://sts.amazonaws.com/

Can you mention the problem in which file and line

@abuzuhri
Copy link
Owner

I will try again review my code and check

@nafberger
Copy link
Contributor

nafberger commented Mar 15, 2022 via email

@nafberger
Copy link
Contributor

but I really want to help u, because u helped me A LOT

@abuzuhri
Copy link
Owner

Did you add this code to get the access token? public AmazonOAuth GetAccessTokenForSPAPIMigration() { string data = string.Empty;

        using (HttpClient client = new HttpClient())
        {
            client.BaseAddress = new Uri("https://api.amazon.com");
            var byteArray = Encoding.ASCII.GetBytes($"{credentials.LWA_App_ClientId}:{credentials.LWA_App_ClientSecret}");
            client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray));

            Dictionary<string, string> items = new Dictionary<string, string>();
            items.Add("grant_type", "client_credentials");
            items.Add("scope", "sellingpartnerapi::migration");
            items.Add("client_id", credentials.LWA_App_ClientId);
            items.Add("client_secret", credentials.LWA_App_ClientSecret);

            FormUrlEncodedContent formUrlEncodedContent = new FormUrlEncodedContent(items);
            var rs = client.PostAsync("/auth/o2/token", formUrlEncodedContent).Result;
            data = rs.Content.ReadAsStringAsync().Result;
        }

        return JsonConvert.DeserializeObject<AmazonOAuth>(data, Serialization.Settings);
    }

Now I change to use same method you use
@jmawebtech and @nafberger please give another try

public static async Task<TokenResponse> GetAccessTokenForSPAPIMigration(string ClientId, string ClientSecret)
        {
            string data = string.Empty;

            using (HttpClient client = new HttpClient())
            {
                client.BaseAddress = new Uri("https://api.amazon.com");
                var byteArray = Encoding.ASCII.GetBytes($"{ClientId}:{ClientSecret}");
                client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray));

                Dictionary<string, string> items = new Dictionary<string, string>();
                items.Add("grant_type", "client_credentials");
                items.Add("scope", "sellingpartnerapi::migration");
                items.Add("client_id", ClientId);
                items.Add("client_secret", ClientSecret);

                FormUrlEncodedContent formUrlEncodedContent = new FormUrlEncodedContent(items);
                var rs = client.PostAsync("/auth/o2/token", formUrlEncodedContent).Result;
                data = await rs.Content.ReadAsStringAsync();
            }

            return JsonConvert.DeserializeObject<TokenResponse>(data);
        }

@nafberger
Copy link
Contributor

nafberger commented Mar 15, 2022

Lets not get confused, in order to migrate MWS credentials to seller-api and get a token and refresh token u need 2 steps, first is to call GetAuthorizationCode and get a code, and then use that to call GetAccessTokenForSPAPIMigration.

I tested the GetAuthorizationCode call and its not working (access denied) the reason is that u need to call https://sts.amazonaws.com/ and get a session token as u do with all other calls.
your call is missing the x-amz-security-token header which comes from the session token as u know.

I couldn't test the GetAccessTokenForSPAPIMigration but is it missing the 2 parameters I added. it doesn't need all the fancy amazon security stuff, and the authorizations header is not needed. its a plain simple call which you can do in postman. but it needs the code and the appredirecturl as query parameters

@abuzuhri
Copy link
Owner

I tested the GetAuthorizationCode call and its not working (access denied) the reason is that u need to call https://sts.amazonaws.com/ and get a session token as u do with all other calls.
your call is missing the x-amz-security-token header which comes from the session token as u know.

I don't think this true in GetAuthorizationCode , but we need help from @jmawebtech he know how its work

@abuzuhri abuzuhri reopened this Mar 15, 2022
@abuzuhri
Copy link
Owner

abuzuhri commented Mar 15, 2022

Closed by mistake

@nafberger
Copy link
Contributor

my answer was based on examining the API traffic from the the other library. which works

@nafberger
Copy link
Contributor

nafberger commented Mar 15, 2022

YOURS
GET /authorization/v1/authorizationCode?sellingPartnerId=00000&developerId=0000&mwsAuthToken=amzn.mws.000000 HTTP/1.1
Host: sellingpartnerapi-na.amazon.com
x-amz-access-token: Atc|MQEBIFLT9Q-D1Nr4ZsvMIij.............
X-Amz-Date: 20220315T211628Z
Authorization: AWS4-HMAC-SHA256 Credential=AKIAYNSEBDN757O4JVXA/20220315/us-east-1/execute-api/aws4_request,
SignedHeaders=host;x-amz-access-token;x-amz-date, Signature=a6834aea8a3c117442b193d213f2b4ce3284302b232ab3972a2caa3315a35251
Accept: application/json, text/json, text/x-json, text/javascript, application/xml, text/xml
User-Agent: RestSharp/106.12.0.0
Connection: Keep-Alive
Accept-Encoding: gzip, deflate

OTHER
GET /authorization/v1/authorizationCode?developerId=0000000&mwsAuthToken=amzn.mws.00000000000sellingPartnerId=00000 HTTP/1.1
Authorization: AWS4-HMAC-SHA256 Credential=ASIAYNSEBDN7UV2PJH7H/20220315/us-east-1/execute-api/aws4_request,
SignedHeaders=host;x-amz-access-token;x-amz-date, Signature=0b1f27d1b35205a2998d3cbcd0f555cae2a208227068b8786e06fc4658e7e3e5
Content-Type: application/json; charset=utf-8
host: sellingpartnerapi-na.amazon.com
x-amz-access-token: Atc|MQEBIBJdjkJB61bTZfuJFnYRUlR_r.................
x-amz-security-token: FwoGZXIvYXdzEBcaDHW1hA9oeLfXdtjWuSKwAZd3vLX2IflV...............
x-amz-date: 20220315T212106Z
Connection: close

@nafberger
Copy link
Contributor

the other makes a successful call. I spent my time researching it in order to help

@abuzuhri
Copy link
Owner

I see the library add x-amz-security-token header and to use this we need to call STS with roleRTN .

But @jmawebtech he don't mention this header in the code

@jmawebtech
Copy link
Author

Yes, you need that header. GetAccessTokenForSPAPIMigration generates an access token used for the x-amz-security-token header. In the Amazon console, go to edit app. Enter SPI and MWS as the types.

abuzuhri added a commit that referenced this issue Mar 16, 2022
@abuzuhri
Copy link
Owner

Now its should work with last version because I get this error , error mean app not published
{
"errors": [
{
"code": "InvalidInput",
"message": "A published application with the provided app-id not found",
"details": ""
}
]
}

@abuzuhri
Copy link
Owner

Please @jmawebtech and @nafberger try also from your side

@jmawebtech
Copy link
Author

jmawebtech commented Mar 19, 2022 via email

@abuzuhri
Copy link
Owner

Then it's work :) I will close the bug

@nafberger
Copy link
Contributor

thanks @abuzuhri @jmawebtech, both parts are working, but u need to change the GetAccessTokenFromCodeAsync method and put "grant_type":"authorization_code", not "client_credentials", because with client_credentials u get only an access token, with authorization_code you get back both, an access token and a refresh token, and that's the correct way as in the documentations.

https://developer-docs.amazon.com/amazon-shipping/docs/website-authorization-workflow#step-4-your-application-exchanges-the-lwa-authorization-code-for-a-lwa-refresh-token

see picture

Screenshot_1

@JonKragh
Copy link

Hi @abuzuhri - This is the area that seems to be broken when trying to migrate MSW users to SPAPI. It appears there was a commit that solved this maybe at one point that got rolled back?

94ef5ea

@tank104
Copy link
Contributor

tank104 commented Jul 24, 2022

I think the problem is here:
public static async Task GetAccessTokenFromCodeAsync(string ClientId, string ClientSecret, string code, string appRedirectUri, string grant_type = "client_credentials")

Where GetAccessTokenFromCodeAsync is not changing grant_type to authorization_code

@tank104
Copy link
Contributor

tank104 commented Jul 24, 2022

I tried to create a branch and PR for the change, but I don't have access (I am not to familiar with doing PRs in GitHub).

My suggested change is this:

    public async Task<TokenResponse> GetAccessTokenFromCodeAsync(string code, string appRedirectUri)
    {
        return await TokenGeneration.GetAccessTokenFromCodeAsync(AmazonCredential.ClientId, AmazonCredential.ClientSecret, code, appRedirectUri);
    }

    public async Task<TokenResponse> GetRrefreshTokenFromCodeAsync(string code, string appRedirectUri)
    {
        return await TokenGeneration.GetAccessTokenFromCodeAsync(AmazonCredential.ClientId, AmazonCredential.ClientSecret, code, appRedirectUri, grant_type: "authorization_code");
    }

    public static async Task<TokenResponse> GetAccessTokenFromCodeAsync(string clientId, string clientSecret, string code, string appRedirectUri)
    {
        return await TokenGeneration.GetAccessTokenFromCodeAsync(clientId, clientSecret, code, appRedirectUri);
    }

    public static async Task<TokenResponse> GetRefreshTokenFromCodeAsync(string clientId, string clientSecret, string code, string appRedirectUri)
    {
        return await TokenGeneration.GetAccessTokenFromCodeAsync(clientId, clientSecret, code, appRedirectUri, grant_type: "authorization_code");
    }

@tank104
Copy link
Contributor

tank104 commented Jul 24, 2022

Have managed to create a PR (I think I have done it right): #255

If possible are you able to complete and make new packages?

@abuzuhri
Copy link
Owner

Now merge and published, please share sample to add in read me

@cckrkmz-wi
Copy link

sorununuz çözüldü mü
ben de aynı sorunla uğraşıyorum yardımcı olabilir misin

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

6 participants