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

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.

Related

AWS API Gateway - Using custom API endpoint for authorization running always on an EC2 instance

We are planning on setting up an AWS API Gateway. We also have a requirement that every call that hits our API gateway should go through a JWT token validation. We are using Okta as our IDP which will generate an access token.
We tried AWS REST API gateway which supports lambda authorizer but the problem we have with it is that lambda's are too slow and there is no way we can cache the JWKS URI and keys. We would get 1000's of requests within a second and lambda's does not work well here. Our goal is to achieve token validation within 2 digit milliseconds which is only possible if we are able to cache the JWKS public key and refetch it only when it is rotated. Please note we do not want to use the caching option of REST API to cache authorization.
We also tried AWS HTTP API which support JWT authorizer but even here we are getting only 3 digit millisecond performance like 500ms-700ms. The majority of the time is spent on fetching the OIDC metdata endpoint and fetching the public key from okta issuer endpoint.
Now, we know that the we could implement our own custom token validation (Authorizer) within one of our own REST API service (Using golang or nodejs) that will run always within an EC2 instance or fargate server within an ECS cluster or for simplicity just within an EC2 instance.
Does AWS API gateway by any chance allow some kind of custom hook where whichever endpoint on the gateway is invoked it should first invoke our custom REST API endpoint which is running in an EC2 instance and then once it gets a valid token response it should invoke the actual URL. Is this even possible? If not, what other options do we have.
Thanks

Set HTTP Only cookie with an AWS Authorizer (Cognito or Lambda) using API Gateway V2

I have an existing API Gateway -> Lambda -> DynamoDB RESTful API that is working.
I would like to set up a login system to gate access to this API using Cognito + Cognito (or a custom lambda) Authorizer
I set up Cognito and am able to sign up a user (and also hit a callback URL with a returned code to swap for an access_token and id_token).
My UI is a React app and I am not using Amplify.
Every single tutorial out there suggests you set the callback to your UI (SPA) and parse out the token to use in further API calls. This isn't good because your token is exposed.
I would like to instead set this token in an HTTP-only cookie in the backend, and have it validated when the Cognito (or custom) authorizer is hit.
I also want to check if the token is expired (1 hour) and refresh it with a stored refresh_token, and set it for the user again in the same HTTP-only cookie.
Does Cognito Authorizer do this automatically? And if not, how can I do this in the authorizer so I can avoid duplicated code in each of my lambdas (since the authorizer only validates and then passes the request to the lambda, I don't think you can set the response headers then).
Is this even possible?
It is my understanding that Cognito does not support this functionality currently.
It sounds to me like the best approach might actually be to write a simple authentication/identity micro-service which can be responsible for the generation and management of tokens, which abstracts away Cognito from your front-end application. This micro-service could also be responsible for refreshing tokens.
Then you can pass these tokens from your authentication/identity micro-service to any API Gateway you have hooked up with a Cognito authoriser.

using api gateway with aws cognito for protected routes

So I'm going to put a public facing API up using AWS API Gateway, where I'll have back end lambda resources that handle the logic for each route (decoupled microservice).
What should I be storing in the JWT? Currently, I've disabled all read attributes, so the token only contains cognito:username, where in my database I will store this as the user id for each user. My understanding is that once a JWT is properly generated, I can use Cognito as an authorizer with API Gateway, and then once the token JWT details are received at the lambda layer, all I need to do is use the cognito:username key to lookup the user profile in my database.
Should I be implementing any other checks in the backend, or is it safe to rely on API gateway to pass the authenticated request?
Thanks!
The cognito API Gateway authorizer will only check if the token has not expired and if it belongs to the correct user pool. But since you will be extracting username from the token itself, you should be safe. Just make sure to configure API Gateway to pass Authorization header to the lambda, it does not do this by default.

Using AWS API Gateway for Lumen based REST API Service with Passport authentication hosted in EC2

I am entirely newbie in Amazon Web services. Currently i am developed a REST API service using Laravel's micro frameworks called Lumen. I am using passport for token based authentication and all that working fine. I need a proxy server to hide my actual endpoints and do some other functionality so i am planning to use AWS API Proxy Gateway and host the API endpoints in EC2 instance.
i went through Build an API with HTTP Proxy Integration from Aws documentation. but there is nothing about using a custom authentication using Oauth.
My Doubts are
How to use Passport authentication when using AWS API Gateway
Is there any good method to hide my REST Endpoint from customer and need a way to change the proxy end point from time to time.
I don't know Laravel ecosystem, but:
if passport expose something like an OpenId Connect you could use Cognito Federated Identities for, precisely, federate your identity, and associate the authorized identities with a given IAM role and unauthorized with another role;
you can use an Api Gateway Custom Authorizer to perform fully customizable auth;
Try expanding your question so we could add more details...
Yes, like what BAD_SEED said, you can use API Gateway Lambda authorizer (formerly known as the custom authorizer) to do any logic to verify the token, since it's just a javascript package.
So, one option is like what auth0 does in (https://auth0.com/docs/integrations/aws-api-gateway/custom-authorizers/part-3) and (https://github.com/auth0-samples/jwt-rsa-aws-custom-authorizer). Their sample authorizer does followings:
It confirms that an OAuth2 bearer token has been passed via the Authorization header.
It confirms that the token is a JWT that has been signed using the RS256 algorithm with a specific public key
It obtains the public key by inspecting the configuration returned by a configured JWKS endpoint
It also ensures that the JWT has the required Issuer (iss claim) and Audience (aud claim)
But unfortunately, Passport does not support JWKS endpoint (which exposes public key for the token signature). So you may have to expose it by yourself.
Another option is much easier, you just make a token verification endpoint in your application, something like /users/me, and protect it with auth middleware. Then in your Lambda authorizer, call it with the token in the request to your other micro service endpoints. By this way, all token verification stuff is left to Passport, and the authorizer just executes policy based on the result of the verification.
Not very sure about what you want to reach, but API Gateway is just a proxy, so you can certainly change backend side endpoints for its frontend one, which is better not changing so often.

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/