aws4 icon indicating copy to clipboard operation
aws4 copied to clipboard

Issue when + sign is present in URL (Amazon SP-API, NextToken)

Open GbalsaC opened this issue 3 years ago • 6 comments

aws4 v. 1.5.1 Ubuntu 20 LTS NodeJS 12.6.9 request 2.48.5 request-promise 4.1.46

I'm currently using aws4 for Amazon SP-API (Selling partner API).

Overall, all methods work great except for one query parameter. NextToken

NextToken (Original value) is passed as a query parameter, and has the following value: aQVM/pLGd/WaJqJYLDm0ZAmQazDrhw3CIiPeQUe9nqoU5ywFddC8C8NI3HOI22PIxqXyQLkGMBs8VhF73Xgy+zFWYRqN5/If2Yapt4MO4XEckwaFrMP2PNhNqgDpVGhEInTAy+XKVmRZBY+oaVuyc8QON+K1yc/YJ8IamK5qOBQwadZWHCdmNwFvOUDdDJWhf2GLmUGyr9UGnxD0RJmrryegoU0IPZxXMHbcorlruypW//smqbZGEWWjslwBjY4mMBO/reDY2s/v6DywD2BmVI0KxWlk275HeLE0br61/ZeG1bEi00oPms+RCEjxtHY0Jjna3DT40pCuDpTeKOS1CbZT8ssvaHo22iqc+HOHQDMXf4cGOMyIyW3zKN+nx8rxYJu46S68kxWtOgCxg3zeweCR1k9eFxFwVqnodKShpq/Y/mfOjS3d9A==

However, this returns the final query, replacing + char with %20, where the query ends looking like this: https://sellingpartnerapi-na.amazon.com/orders/v0/orders?NextToken=aQVM%2FpLGd%2FWaJqJYLDm0ZAmQazDrhw3CIiPeQUe9nqoU5ywFddC8C8NI3HOI22PIxqXyQLkGMBs8VhF73Xgy%20zFWYRqN5%2FIf2Yapt4MO4XEckwaFrMP2PNhNqgDpVGhEInTAy%20XKVmRZBY%20oaVuyc8QON%20K1yc%2FYJ8IamK5qOBQwadZWHCdmNwFvOUDdDJWhf2GLmUGyr9UGnxD0RJmrryegoU0IPZxXMHbcorlruypW%2F%2FsmqbZGEWWjslwBjY4mMBO%2FreDY2s%2Fv6DywD2BmVI0KxWlk275HeLE0br61%2FZeG1bEi00oPms%20RCEjxtHY0Jjna3DT40pCuDpTeKOS1CbZT8ssvaHo22iqc%20HOHQDMXf4cGOMyIyW3zKN%20nx8rxYJu46S68kxWtOgCxg3zeweCR1k9eFxFwVqnodKShpq%2FY%2FmfOjS3d9A%3D%3D&MarketplaceIds=A1AM78C64UM0Y8

So, char replacement can be seen in: +XKVmRZBY+oa becomes %20XKVmRZBY%20oa

I understand in query, + sign becomes a space, and probably %2B should be used instead, my question is, how should I add the parameter into the sign method if the original has a + char, should I replace it before passing? or should I replace it after the path is returned from sign()

My complete code is the following:

import aws4 from "aws4";
import { RequestPromiseAPI } from "request-promise";

const _requestWrapper<T>(opts: { host: string; path: string; method: string; headers: Headers }): Promise<T> {
    return this.request(`https://${opts.host}${opts.path}`, {
      method: opts.method,
      headers: opts.headers,
      json: true,
      resolveWithFullResponse: true,
    }).then((response) => {
      console.log('<SP-API> Response Headers: ', response.headers);
      const d: T = response.body;
      console.log('<SP-API> Response BODY: ', d);
      return d;
    })
  }

// >> Where nextToken is the one posted as "Original"
async getOrder(nextToken:string){
   const ss = aws4.sign(
      {
        host: `sellingpartnerapi-na.amazon.com`,
        method: "GET",
        path: `/orders/v0/orders?NextToken=${nextToken}&MarketplaceIds=A1AM78C64UM0Y8`,
        region: "us-east-1",
        service: "execute-api",
        headers: {
          "User-Agent": "Fiscalpop/2.0 (Language=JavaScript; Platform=Ubuntu/16)",
          'x-amz-access-token': tokenized.access_token
        },
      },
      {
        accessKeyId: "ASIA2PIENJRBC...",
        secretAccessKey: "IePqZ5lBHhrJdzQbqyZ8U5t0...",
        sessionToken: "FwoGZXIvYXdzED8aDKQUTa4ly/nPYc+PuSKqAfQd60R...",
      }
    );
    return _requestWrapper<{ payload: SP_Order }>(ss);
}

GbalsaC avatar Feb 19 '21 22:02 GbalsaC

What's converting the + into %20?

mhart avatar Feb 19 '21 22:02 mhart

The returned aws4.sign() path value has the + replaced with %20.

From the above code, If I do a console.log('ss: ', ss) where ss is the variable returned from the aws4.sign() method:

Original NextToken: gtaZal63YIiaJqJYLDm0ZAmQazDrhw3CgJalwszeUhoU5ywFddC8C8NI3HOI22PIxqXyQLkGMBs8VhF73Xgy+zFWYRqN5/IfQ/jTgP4cXDpuvG9fmlR56zT99DMY0KuTInTAy+XKVmRZBY+oaVuyc8QON+K1yc/Yfb9rRgL4TdE0EBf7igWxmmRLuJ4BeSGYf2GLmUGyr9UGnxD0RJmrryegoU0IPZxXv6JqHKIDsst6Zei4iUx8iJbwRJ+1RJ66MBO/reDY2s/v6DywD2BmVI0KxWlk275HeLE0br61/ZeG1bEi00oPms+RCEjxtHY0TuNAtmdHevXpo/P/8H1yryuTIyiVCSA2bGl11BXVovsrAC7MwVMzx+UDRT6zkDPnSJxHPsySa7tPoHVKB7NbV61OyEkQXs58jYa3TOdM+ra8ZiM67cQNng==

ss:  {
  host: 'sellingpartnerapi-na.amazon.com',
  method: 'GET',
  path: '/orders/v0/orders?NextToken=gtaZal63YIiaJqJYLDm0ZAmQazDrhw3CgJalwszeUhoU5ywFddC8C8NI3HOI22PIxqXyQLkGMBs8VhF73Xgy%20zFWYRqN5%2FIfQ%2FjTgP4cXDpuvG9fmlR56zT99DMY0KuTInTAy%20XKVmRZBY%20oaVuyc8QON%20K1yc%2FYfb9rRgL4TdE0EBf7igWxmmRLuJ4BeSGYf2GLmUGyr9UGnxD0RJmrryegoU0IPZxXv6JqHKIDsst6Zei4iUx8iJbwRJ%201RJ66MBO%2FreDY2s%2Fv6DywD2BmVI0KxWlk275HeLE0br61%2FZeG1bEi00oPms%20RCEjxtHY0TuNAtmdHevXpo%2FP%2F8H1yryuTIyiVCSA2bGl11BXVovsrAC7MwVMzx%20UDRT6zkDPnSJxHPsySa7tPoHVKB7NbV61OyEkQXs58jYa3TOdM%20ra8ZiM67cQNng%3D%3D&MarketplaceIds=A1AM78C64UM0Y8',
  region: 'us-east-1',
  service: 'execute-api',
  headers: {
    'User-Agent': 'Fiscalpop/2.0 (Language=JavaScript; Platform=Ubuntu/16)',
    'x-amz-access-token': 'Atza|IwEBIDpYYDWUQ_r-iiRtwgxesg50OBOAhYGcY3Cd0Xl2Uh1T9...',
    Host: 'sellingpartnerapi-na.amazon.com',
    'X-Amz-Security-Token': 'FwoGZXIvYXdzEKD//////////wEaDCe1a8JIcLAD6B5a6iKqAU4M5...',
    'X-Amz-Date': '20210219T230345Z',
    Authorization: 'AWS4-HMAC-SHA256 Credential=ASIA2PIENJRBKGWCAJJ3/20210219/us-east-1/execute-api/aws4_request, SignedHeaders=host;x-amz-access-token;x-amz-date;x-amz-security-token, Signature=392f6da19a053af7b32f34578...'
  }
}

You'll see the %20 replaced the + inputs

GbalsaC avatar Feb 19 '21 23:02 GbalsaC

If I replace the + in NextToken's original value with %2B the query will pass correctly.

Something like this: NextToken=${queries.NextToken.split('+').join('%2B')}

const ss = aws4.sign(
      {
        host: this.ENDPOINT,
        method: "GET",
        path: `/orders/v0/orders?&MarketplaceIds=A1AM78C64UM0Y8&NextToken=${queries.NextToken.split('+').join('%2B')}`,
        region: "us-east-1",
        service: "execute-api",
        headers: {
          "User-Agent": "Fiscalpop/2.0 (Language=JavaScript; Platform=Ubuntu/16)",
          'x-amz-access-token': tokenized.access_token
        },
      },
      {
        accessKeyId: "ASIA2PIENJRBCFHH...",
        secretAccessKey: "IePqZ5lBHhrJdzQbqyZ8U5t0eRgz6SjIn...",
        sessionToken: "FwoGZXIvYXdzED8aDKQUTa4ly/nPYc+PuSKqAfQd60RsmIwhrqH...",
      }
    );

Then the returned path value keeps the %2B values and signs correctly. NextToken=CqT3Z2T9h1iaJqJYLDm0ZAmQazDrhw3CgJalwszeUhoU5ywFddC8C8NI3HOI22PIxqXyQLkGMBs8VhF73Xgy%2BzFWYRqN5%2FIfQ%2FjTgP4cXDpsHZtqbATNf3sogY7TweHPInTAy%2BXKVmRZBY%2BoaVuyc8QON%2BK1yc%2FYfb9rRgL4TdE0EBf7igWxmmRLuJ4BeSGYf2GLmUGyr9UGnxD0RJmrryegoU0IPZxXv6JqHKIDsst6Zei4iUx8iJbwRJ%2B1RJ66MBO%2FreDY2s%2Fv6DywD2BmVI0KxWlk275HeLE0br61%2FZeG1bEi00oPms%2BRCEjxtHY06ULiqinMRi1cjS%2FwODfiaNDlIVQVL%2BxW02hnPs00iV1GIfz4O%2BfU3p%2F7qvexBJaVfgRJHzL0fOvwK4TCp4Ag0EdDnjhHuqvYnjahUXM24sdp4r5C1zkSUg%3D%3D&MarketplaceIds=A1AM78C64UM0Y8

And I'm able to receive the query response using the token.

Otherwise, without replacing the + char in the parameter before passing it to sign(), I get an error:

We could not decode your NextToken. Possible reasons include: a transmission error, improper quoting or a truncation problem.

GbalsaC avatar Feb 19 '21 23:02 GbalsaC

hello @GbalsaC sir it is also notworking!!!!!!

{'errors': [{'message': None, 'code': 'InvalidInput'}]}

PrashantMalaviya avatar Apr 24 '21 11:04 PrashantMalaviya

Python 3.x import sys, os, base64, datetime, hashlib, hmac ,json
import requests from datetime import date Amazon Example to sending and signing a request from python, heavily modified for enterprise application.

GbalsaC, I have the same issue, i solved it with the %2B being replaced before sending the string to be signed. As you had encountered, using the other %20 caused a malformed or broken token response from AWS. Another response i got was that the message was null as PrashantMalaviya has indicated above. I am using

mavrick951 avatar May 11 '21 05:05 mavrick951

Python 3.x import sys, os, base64, datetime, hashlib, hmac ,json import requests from datetime import date Amazon Example to sending and signing a request from python, heavily modified for enterprise application.

GbalsaC, I have the same issue, i solved it with the %2B being replaced before sending the string to be signed. As you had encountered, using the other %20 caused a malformed or broken token response from AWS. Another response i got was that the message was null as PrashantMalaviya has indicated above. I am using

Hi, I am getting Same issue that was discuuing here, Any final conclusion on te same? I am using java

AruEnvista avatar Oct 27 '21 06:10 AruEnvista