How do I use AWS cognito response to authenticate API requests - amazon-web-services

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

Related

AWS API Gateway Authorizer does not authorize non-default Cognito User Pool App client tokens

I have created a new app client in Cognito, the tokens from the default app client are marked as valid by the API Gateway but not the token from the new App Client.
The API Gateway responds with HTTP 401 - UnAuthorized.
This should work because both the app clients have full permissions to the underlying users stored in Cognito.
I couldn't find any relevant documents explaining this discrepancy.
So, I was linking my AWS User pool to Amazon Alexa Smart Home Skill using this blog https://aws.amazon.com/blogs/compute/amazon-cognito-for-alexa-skills-user-management/.
On successfully linking the skill, Alexa would only send the accessToken in the subsequent API's.
The AWS API Gateway authorizers only check for the ID token and will deem the request invalid if it is given an AccessToken.
Thus, the requests were failing. It has nothing to do with default or non-default app clients.
Using a Cognito custom authorizer seems the best option, will disable API Gateway authorization.

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.

aws cognito, api gateway and cognito with postman

How do I call API gateway with postman with cognito?
Tried to use AWS Signature in postman and this did not work.
https://docs.aws.amazon.com/apigateway/latest/developerguide/how-to-use-postman-to-call-api.html
I am using hosted UI in cognito if that makes a difference. I see that there is an Oauth 2.0 option in postman but dont know how to fill out the fields.
So my api works when I pass Authorization in the header with the id_token. Without the id_token is there any other way?
thanks
If you are using a Cognito user pool and have your API Gateway authorizer set to user pool, then you need to pass either the id or access token in the Authorization header.
If you are using a Cognito identity pool and have your API Gateway authorizer set to AWS_IAM you need to use AWS signatures

AWS API Gateway authentication error IncompleteSignatureException using JWT with Auth0

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/