Tesuji
Tesuji

Reputation: 1675

Unable to resolve " not a valid key=value pair (missing equal-sign) in Authorization header" when POSTing to api gateway

I created an api-gateway to put data in my s3 bucket. When I test it in console it works with no problem. Even when I test my token in the authorizer test it returns an "Allow", so there's nothing wrong with my token. My token validation is

^Bearer [-0-9a-zA-z\.]*$

so my python code for generating my header looks like this:

headers = {
    "Authorization": "Bearer " + token,
    "Content-type": "application/json"
}

The rest of my code is:

response = requests.post(url, headers=headers, data={"id":"0678a93d-ee8c-4db5-a831-1e311be4f04b", "test":"12345"})
print(response.text)

The error message I get is "{"message":"'{My Token}' not a valid key=value pair (missing equal-sign) in Authorization header: 'Bearer {My Token}'."}"

My url looks like this:

https://my-api-gateway.amazonaws.com/MyStage, and I am using a {proxy+} in my resources. I noticed if I change my header from Content-type to Accept, it gives me the same error, but if I also change my url to https://my-api-gateway.amazonaws.com/MyStage/any-arbitrary-string/, I get a

   {"response":{"status":"VALID", "message": "success"}} 

but the file does not show up in my s3 bucket. How do I resolve this?

Upvotes: 98

Views: 189411

Answers (18)

Mercury
Mercury

Reputation: 7988

For me the issue caused because I was using API mapping wrongly.

So in the API Gateway Custom domain names > my.api.customer.domain.com > API mappings > Configure API mappings

I had this:

![enter image description here

And in the REST API gateway the resources looks like:

enter image description here

And I was invoking the API like this:

GET <my.api.customer.domain.com>/accounts2/987654321/permissions

Then I've realized that if you define the accounts2 path part in the API mappings you don't need it within the REST resource

So invoking (with accounts2 twice):

GET <my.api.customer.domain.com>/accounts2/accounts2/987654321/permissions

Resolved the issue

Upvotes: 0

Eric Fu
Eric Fu

Reputation: 301

In my case, the error occurred after I added the custom domain name to the API gateway.

Eventually, I discovered that the requested URL "https://myapi.example.com/Prod/hello" is incorrect. The stage name "Prod" should be removed from the URL since the custom domain name is already mapped to this stage. It was a silly mistake.

Upvotes: 3

Arkadas Kilic
Arkadas Kilic

Reputation: 2484

In my case I was trying to access API gateway via Postman by using OAuth 2.0 Implicit Grant, it always returns this error message. Unfortunately if method authorization is set to AWS_IAM, you can not make this API call via pPostman.

enter image description here

You can remove Authorization until you tested your endpoint via Postman.

Upvotes: 0

ar.freitas
ar.freitas

Reputation: 43

I had the same message when I tried to get a inexistent endpoint to test my gateway.

I thought was token error, but no. This is caused because I dont had defined default gateways responses.

To solve, I create this code below, to add via terraform the same header to multiples errors/status code.

variable "http_responses" {
  type    = list(object({
    name          = string
    status_code   = string
    response_type = string
  }))
  default = [
    { name = "AccessDenied",                    status_code = "403", response_type = "ACCESS_DENIED" },
    { name = "ApiConfigurationError",           status_code = "500", response_type = "API_CONFIGURATION_ERROR" },
    { name = "AuthorizerConfigurationError",    status_code = "500", response_type = "AUTHORIZER_CONFIGURATION_ERROR" },
    { name = "AuthorizerFailure",               status_code = "500", response_type = "AUTHORIZER_FAILURE" },
    { name = "BadRequestBody",                  status_code = "400", response_type = "BAD_REQUEST_BODY" },
    { name = "BadRequestParameters",            status_code = "400", response_type = "BAD_REQUEST_PARAMETERS" },
    { name = "ExpiredToken",                    status_code = "403", response_type = "EXPIRED_TOKEN" },
    { name = "IntegrationFailure",              status_code = "500", response_type = "INTEGRATION_FAILURE" },
    { name = "IntegrationTimeout",              status_code = "504", response_type = "INTEGRATION_TIMEOUT" },
    { name = "InvalidApiKey",                   status_code = "403", response_type = "INVALID_API_KEY" },
    { name = "InvalidSignature",                status_code = "403", response_type = "INVALID_SIGNATURE" },
    { name = "MissingAuthenticationToken",      status_code = "403", response_type = "MISSING_AUTHENTICATION_TOKEN" },
    { name = "QuotaExceeded",                   status_code = "429", response_type = "QUOTA_EXCEEDED" },
    { name = "RequestTooLarge",                 status_code = "413", response_type = "REQUEST_TOO_LARGE" },
    { name = "ResourceNotFound",                status_code = "404", response_type = "RESOURCE_NOT_FOUND" },
    { name = "Throttled",                       status_code = "429", response_type = "THROTTLED" },
    { name = "Unauthorized",                    status_code = "401", response_type = "UNAUTHORIZED" },
    { name = "UnsupportedMediaType",            status_code = "415", response_type = "UNSUPPORTED_MEDIA_TYPE" },
    { name = "WafFiltered",                     status_code = "403", response_type = "WAF_FILTERED" },
    { name = "DEFAULT_4XX",                     status_code = "", response_type = "DEFAULT_4XX" },
    { name = "DEFAULT_5XX",                     status_code = "", response_type = "DEFAULT_5XX" },

  ]
}

resource "aws_api_gateway_gateway_response" "http_responses" {
  for_each = { for response in var.http_responses : "${response.name}-${response.status_code}" => response }

  rest_api_id   = aws_api_gateway_rest_api.my_api.id
  status_code   = each.value.status_code
  response_type = each.value.response_type

  response_templates = {
    "application/json" = "{\"message\":$context.error.messageString}"
  }

  response_parameters = {
    "gatewayresponse.header.Access-Control-Allow-Headers" = "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'"
    "gatewayresponse.header.Access-Control-Allow-Methods" = "'GET,OPTIONS'"
    "gatewayresponse.header.Access-Control-Allow-Origin"  = "'*'"

  }
}

Now, when I try to get an inexistent endpoint, I get this response:

   {
   "field" : null,
   "exceptionClass" : "ResponseStatusException",
   "message" : "field não encontrado",
   "statusCode" : 404,
   "statusText" : "404 NOT_FOUND"
}

Is it.

Upvotes: 2

abhish
abhish

Reputation: 439

If you are using aws-api-gateway.
if the api is working fine in api-gateway of aws console and not working in the postman.

chances are you might have forgotten to deploy your api in api gateway

Upvotes: 4

VigneshwaraMoorthy
VigneshwaraMoorthy

Reputation: 21

Along with Will's answer, please also ensure the URL that you are calling is same case (lowercase or otherwise) as defined in API Gateway. The URL is case-sensitive

Upvotes: 1

Ben
Ben

Reputation: 318

in my case it worked when I replaced POST by PATCH

curl_setopt_array($curl, array(
...
CURLOPT_CUSTOMREQUEST => 'PATCH',
...

Upvotes: 1

Yogi Arif Widodo
Yogi Arif Widodo

Reputation: 679

in my case very similar, using third api payment has wrong set on request METHOD , instead of DELETE I use POST. ah my bad.

Upvotes: 4

hamza felix
hamza felix

Reputation: 39

for postman code generator , please make sure to remove unnecessary spaces from the URL , that was my issue

Upvotes: 1

TWitt
TWitt

Reputation: 81

When I got this, I was being braindead and was hitting the apigateway root, and not an endpoint with a handler.

Upvotes: 2

kokociel
kokociel

Reputation: 529

For me, the issue was similarly an incorrect URL. My endpoint was meant to accept another URL as a path argument; and I'd applied Pyton's urllib.parse.quote(url) instead of urllib.parse.quote_plus(url), so I was making requests to https://apigw.playground.sweet.io/gameplay/pack/https%3A//collectible.playground.sweet.io/series/BjqGOJqp instead of https://apigw.playground.sweet.io/gameplay/pack/https%3A%2F%2Fcollectible.playground.sweet.io%2Fseries%2FBjqGOJqp 🤕

Upvotes: 0

In my case, I chose wrong method. Please check your request method

Upvotes: 1

Sean
Sean

Reputation: 1364

I had the same error when just running AWS.config.update. I had an extra space character and it gave this error. Just posting it here as it wasn't clear - but easily discoverable I am sure.

Upvotes: 0

Avinandan
Avinandan

Reputation: 81

I had faced the same issue. For me, the issue was due to a case-sensitive url. Please make sure, the spelling and the casing of each of the words are correct.

Upvotes: 7

Will
Will

Reputation: 7027

I have run across this error when the resolved URL was incorrect. (Or without a proxy but with an incorrect URL.)

Upvotes: 112

Tommy Nguyen
Tommy Nguyen

Reputation: 3633

For me the reason why it didn't work is because I didn't redeploy when making changes to the integration.

So if you use terraform to create resources, you need to include the triggers part. See: https://www.terraform.io/docs/providers/aws/r/api_gateway_deployment.html#redeployment-triggers

If you're using UI, check: enter image description here

Upvotes: 21

ravi
ravi

Reputation: 1019

When using "{proxy+}" in the path, you also need to add a root path. Adding "{proxy+}" is how api gateway knows you are using Lambda proxy integration. So don't leave it out.

viz.,

Type: AWS::Serverless::Function
    Properties:
       Events:
         ProxyResource:
           Type: Api
           Properties:
             RestApiId: ...
             Path: /{proxy+}
             Method: ANY
         RootResource:
           Type: Api
           Properties:
             RestApiId: ...
             Path: /
             Method: ANY

Upvotes: 3

Tesuji
Tesuji

Reputation: 1675

I resolved it. I changed my method to come from the root resource (instead of the unnecessary {proxy+}, and also noticed that my python method was incorrect. I had response = requests.post(url, headers=headers, data=my_json), but data only accepts a string. I have to use either requests.post(url, headers=headers, json=my_json) or requests.post(url, headers=headers,data=json.dumps(my_json))

Upvotes: 9

Related Questions