I have a project that needs to make use of Lambda functions which are triggered by API Gateway with protected authorizer, i have set the resource method to require an authorization header which is the token id given in Cognito's authentication response. Basically all protected routes in the application are handled by ALB which will always check if the requested route is protected and if so then redirect to cognito's sign-in in case there is no session, after the authentication is successful, the Load Balancer will redirect the request to the application with additional headers, which are:
x-amzn-oidc-data
x-amzn-oidc-accesstoken
Both are in a manner of speaking JWT with user claims from the authentication. Normally the API Gateway endpoint protected by cognito authorizer requires a token id which is easily retreived using the implicit flow in cognito's authentication, but the ALB is using the authorization code flow which only gives a session code. Both data from x-amzn-oidc-data and token id looks the same but when i try to access the endpoint using the data from ALB i only get unauthorized.
The ideal flow goes like this:
I know i could avoid all this process by just implementing the Lambda function directly to ALB as trigger but my project is only looking for automated deployments and CloudFormation still does not support Lambda implementations for ELB.
TL:DR
The simple question is: How can i grant access in API Gateway using a token given by authorization from ALB?
Related
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.
I have an serverless application which uses AWS Cognito, Lambda, and API Gateway.
The user signs in using AWS Cognito (with external identity provider) for user authentication and authorization.
The API gateway uses Cognito Authorizer to secure access to the lambda function.
The initial use case is simple, any request sent to API Gateway need to be authenticated with Cognito, and they are authorized to invoke the lambda function. As long as they can sign in, they can invoke the lambda.
Now I want to change the authorization. Even if the user is able to authenticate with Cognito, they must contain certain scopes in order to be authorized to invoke the lambda. These scopes can be fetch or checked in an external authz service. Cognito authorizer on the API gateway do not allow me to implement custom logic to call external authz service.
What is the recommended way to handle this?
You can use lambda authorizer for this use case.
In your lambda you can first authenticate your incoming token (example) and once authentication is successful you can check authorization scopes using authz service.
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.
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.
I'm using AWS Gateway as my web API with AWS Lambda as my serverless backend. Lambda functions are only invoked by my Gateway APIs. Through Lambda I call and execute operations on other AWS Services (RDS, SNS, etc.).
I want only my clients to get access to my web APIs. To do so I setup all of my Gateway APIs with AWS_IAM authorization. An unauthenticated client have only policies that let him invoke e.g. the function for login/sign up a user. In comparison an authenticated client have policies that enables him to access more recourses.
The question now is: Because I only want my clients to get access to my Gateway APIs and to do it as secure as possible, is it necessary to create a custom authorizer which checks the validity of tokens?
Neither I did setup a cognito user pool, nor I did setup a external public provider (google, Facebook, openId, amazon, etc.). I'm working with custom developer authenticated identities. All users are saved in AWS RDS. When a user tries to login and gets correctly authenticated through his email and password a open id and a jwt token is returned to the client. This is done by invoking 'getOpenIdTokenForDeveloperIdentity'.
I found some recourses on the web where people created a custom authorizer, but they did always verify the validity of the token by a external provider (google, facebook, auth0, etc.). This member did wrote that you only need to have a external provider when you have "[...]some totally different auth logic[...]" https://stackoverflow.com/a/39407156/5181862. And I don't think this is the case here.
The clients that run the application are iOS and later Android devices, if this information is necessary.
If all the APIs have AWS_IAM authorization, that is already pretty secure. AWS_IAM requires that the client have valid AWS credentials from the same account as the API (your account).
It sounds like you are using Cognito (talking about unauthenticated client policy), in which case your authorization model is secure if implemented correctly.