AWS API Gateway authentication error IncompleteSignatureException using JWT with Auth0 - amazon-web-services

Where I'm At
I'm currently working through setting up Auth0 delegated authentication for AWS API Gateway. I've followed the documentation and tutorials below with the exception that I have an app in place rather than their example apps:
https://auth0.com/docs/quickstart/spa/angular2/aws
https://auth0.com/blog/2015/11/10/introducing-angular2-jwt-a-library-for-angular2-authentication/
https://auth0.com/docs/client-platforms/angular2
https://auth0.com/docs/integrations/aws-api-gateway/part-2
What is Working
Auth0 sign on from my Angular2 app is working correctly and I'm getting a token.
Auth0's AuthHttp component is attaching the bearer token to the Authenticate header when I call the AWS API Gateway.
What is Not Working
Status 403 response from AWS API Gateway indicating a Cloudfront IncompleteSignatureException; "Authentication header missing equal-sign".
The authentication header is
Authentication: Bearer edJ0e...[I've truncated for brevity]
Could AWS be expecting a different type of authentication which uses key value pairs? How to I tell AWS API Gateway that it should be looking for a JWT?

I'm guessing you have AWS_IAM authentication enabled for your API Gateway endpoint. You need to disable that if you aren't planning to use it. If you plan to use AWS_IAM authentication in addition to JWT then you will have to send the JWT token using a different field.
From part 5 of the Auth0 tutorial you linked:
The final step is to pass the JWT to the method from the browser
client. The standard method is with an Authorization header as a
bearer token, and you can use this method if you turn off IAM
authorization and rely solely upon the OpenID token for authorization
(you will also need to map the Authorization header into the event
data passed to the AWS Lambda function). If you are using IAM, then
the AWS API Gateway uses the Authorization header to contain the
signature of the message, and you will break the authentication by
inserting the JWT into this header. You could either add a custom
header for the JWT, or put it into the body of the message. If you
choose to use a custom header, you'll also need to do some mapping for
the Integration Request of the POST method

Based on the error message, it sounds like you've configured your API for AWS_IAM authentication. This requires your request be signed with AWS Signature Version 4.
In order to execute API Gateway functions you will need to do 1 of 3 things:
Get AWS credentials via IAM/STS as noted in the auth0 example and use those to sign your request.
As noted in Mark B's answer, follow the instructions in step 5 of the tutorial from auth0 and disable AWS_IAM auth and do the validation inside your Lambda.
Switch to use a custom authorizer to validate the JWT directly at the API Gateway layer. This would require you to take the code Auth0 provides to validate the token then build your own authorizer result.

(Posted on behalf of the question author).
Update
Both Mark B and Bob Kinney are correct. What I did (and you may have as well) is jump around in the various Auth0 links I posted at the top of this question and attempt to use their angular2-jwt library (with the AuthHttp component) to adapt the tutorial to Angular2 while following along with their 5-part example of setting up Auth0 with AWS API Gateway. The AuthHttp component will automatically put the JWT Bearer token in the "Authentication" HTTP header which is incompatible with an AWS API Gateway call secured by IAM authorization. As these gents showed me, this is explained in part 5 of the tutorial. If you only made it to part 4 and it's not working hopefully this answers your question as it did mine.
Update 2
The Auth0 Angular2 tutorial has been updated to reflect Angular2 rc 1. https://auth0.com/blog/2015/05/14/creating-your-first-real-world-angular-2-app-from-authentication-to-calling-an-api-and-everything-in-between/

Related

HTTP API Gateway JWT Authorizer to take identity source from cookie

I am working with HTTP API Gateway with JWT Authorizer. I have got it to work with placing the JWT in the Authorization header with the request. However, due to a requirement, I need to be able to place the JWT in the Cookie header instead. I am not able to get the API Gateway to pick a particular cookie inside the Cookie header. I tried the following identity source expressions:
$request.header.Cookie.[myCookieName]
$request.header.Cookie.myCookieName
None of them worked and I am not sure what else could be done. Does HTTP API version of API gateway supports this? If it does, any suggestions?
The alternate solution would be to use the REST version with a custom authorizer lambda but I do not want to go that route because of another problem not mentioned here.
Accessing cookies is currently not possible.
Such a feature request has been posted on AWS Forums and is in the backlog.

AWS API Gateway Authorizer using Cognito Identity Pool

The test enviornment for the API Gateway..... Cognito Authorizer.
What value is it expecting ?
I tried to use accessKeyId returned from CognitoIdentityCredentials and it did not work.
Identity Flow
'Testing the accessKeyId gives Error
I also tried _identityId and that did not work as well.
The error for both is "Unauthorized request"
I think your API endpoints are protected by AWS_IAM authorization method. you can confirm it from the Method Execution section of your API endpoint.
If you are using AWS_IAM method, the api end points excepts a signature to be generated using your aws credentials and pass it in the request under the Authorization header.
You can use postman app to test the endpoint, follow these steps
create a new request with the correct http method and the url
under Authroization tab, select AWS Signature
Enter the values for AccessKey, Secret Key
under the Advanced section, enter your region and Session Token
Postman application is very handy to test rest api endpoints. it's even handy to test the api gateway endpoints protected by AWS_IAM authorization method. The postman app generates the signatures required using your AWS credentials and include the generated signature part of http headers of the request.
Note: Also make sure your identity pool's Authenticated role has permission to invoke the api endpoint.
Reference:
https://docs.aws.amazon.com/apigateway/latest/developerguide/how-to-use-postman-to-call-api.html
you can download postman application if you dont have - https://www.getpostman.com/downloads/

Do I need to verify a AWS Cognito token in BOTH Lambda AND as API Gateway?

When using a AWS Cognito attribute from a JWT token in a lambda, do I need to verify the JWT? The Lambda is only triggered by an API Gateway which already verifies the token.
Adding details:
- I'm using Cognito Authorizer in the API Gateway to verify the token.
- The lambda is connected to the API Gateway as proxy.
No you don't need to verify the JWT in backend lambda if protected by a custom lambda authorizer by API Gateway. I would suggest you to use REQUEST based lambda authorizer and attach attributes in the response. So your backend lambda will be able to access attributes in event.requestContext.authorizer['your_attribue'].
This will also enable you to test your Lambda in isolation without needing to get attribute from JWT. You can always mock the event object for unit testing.
I ran into the same conundrum, and was trying to find documented confirmation that, within the Lambda, I wouldn't have to do any validation on my own, and that I can safely rely on the the token / claims being genuine. Unfortunately, nothing in the AWS documentation or the forum posts that I've seen so far has explicitly confirmed this.
But I did find something similar for GCP, and how the API Gateway there validates the JWT. From the GCP documentation:
To authenticate a user, a client application must send a JSON Web
Token (JWT) in the authorization header of the HTTP request to your
backend API. API Gateway validates the token on behalf of your API, so
you don't have to add any code in your API to process the
authentication. However, you do need to configure the API config for
your gateway to support your chosen authentication methods.
API Gateway validates a JWT in a performant way by using the JWT
issuer's JSON Web Key Set (JWKS). The location of the JWKS is
specified in the x-google-jwks_uri field of the gateway's API config.
API Gateway caches the JWKS for five minutes and refreshes it every
five minutes.
So, it seems that within GCP at least, we don't have to do anything, and the API Gateway will handle everything. Even though this is not a confirmation that this is how it works in AWS as well, but the fact that this is how it works in GCP, it gives me some more confidence in assuming that it must be so in AWS too.

AWS Cognito UserPool Authentication on HTTP Request

I'm building an API using the serverless framework. I'm trying to authenticate requests coming in through API Gateway by leveraging Cognito (UserPools), and giving each of my users their own authorization token for each API call they make.
Trying to test it with postman I'm not able to make a call and pass authorization. I've tried setting Authorization in the header with the App Client Secret, but I'm just getting "Unauthorized" back. Is there something I'm missing?
You should be using the token rather than the App Client Secret. How are you retrieving the token?
For user sign in authorization, you must be sure you uncheck the option to generate client secret when you are creating a new Client Application inside UserPool.
In your API Gateway you create an authorizer making a reference to you before created UserPool. Inform "authorization" for the header.
Using a AWS third party SDK service (or just their API), signin with a valid user. You will get 2 types of tokens after the login, make sure you keep the right one. I advise you to check the token through the API Gateway authorizer testing option. Note: This step is the most important, as you are isolating the token you get and the authorization service. This way you can track the source of your problem.

How do I use AWS cognito response to authenticate API requests

I am building a web app that authenticates via AWS Cognito, and uses an existing API gateway configuration to talk to Lambda functions.
In my app, when I authenticate, I get the following data back from Cognito:
The sample headers I've been given to authenticate to the Amazon API gateway look like this (x's added for obfuscation):
Content-type: application/json
Host: <API Gateway host>
X-Amz-DateL <Date>
Authorization:
AWS4-HMAC-SHA256 Credential=XXXXXXXXXXXX/20170222/ap-southeast-2/execute-api/aws4_request, SignedHeaders=content-type;host;x-amz-date, Signature=f25e2a18d8c81fe9e7XXXXXXXXXXXXXXXXb7d586d24a3e39
Access_key:XXXXXXXX (this is a large string)
My question is what information do I need from my cognito result to craft the headers that I need to connect to the api?
I'm using Vue.js as a Javascript front end, and I've looked at the AWS SDK for Javascript but not sure if that helps me - for the moment I feel crafting the headers manually may be easier?
I believe what you're trying to do is authorize your already authenticated users. Explanation of the difference between authorization and authentication can be found here
In the case of authorization, you can create a Custom Authorizer. However, since you're using Amazon Cognito, be sure to create a Cognito User Pool Authorizer
Essentially, you'll use the IdToken from Cognito and pass it as the Authorization header to your authorizer function.
See also Integrating Amazon Cognito User Pools with API Gateway