API Gateway authorization for Cognito User pool+Identity pool - aws-api-gateway

I am working on a web app where users can login/signup with their personal email addresses or login with federated identities like Facebook/Twitter. I have set up Cognito User pool and identity pool for the same.
After successful login , APIs hosted on API gateway would be invoked to display some data on the application. I would like to implement authorization for every API invoke call and return the response only for authorized users.
I have created User Pool Authorizer in API Gateway and I am able to authenticate users created in userpool based on the Id Token.
As per my understanding , to authenticate users from Identity pool , I can use AWS_IAM in Api Gateway. AWS_IAM may not be right solution for my application as API can be invoked by user in userpool as well as identity pool.
I am thinking of implementing authentication using Custom Authorizer using Lambda functions.
If custom Authorizer has to be implemented , should validating policy document based on the session token be sufficient to validate the users from both Userpool/Identity Pool? Kindly suggest alternatives for custom authorization,if any.
Thanks in advance

Have you seen this blog post? https://aws.amazon.com/blogs/mobile/integrating-amazon-cognito-user-pools-with-api-gateway/
It's possible to directly integrate your Cognito user pools tokens as an authorizer for API Gateway, and it simplifies the flow you described greatly.

Related

How to use cognito id token as authorization header for API gateway?

I have an API http gateway (at say https://example.com) integrated with an API REST gateway which uses a Cognito authorizer. All of this to serve a single-page React application. The behaviour is as expected:
I launch the Cognito hosted UI and sign in,
It redirects to the url https://example.com/#id_token=123
If I use PostMan, I can access that url if I pass that id_token in the Authorization header.
Now my question is: how can I pass the header automatically after signing in so I can visit https://example.com?
I have spent a long time on this and have found many similar posts without an answer:
How to use the code returned from Cognito to get AWS credentials?
How can I link cognito token and API authentication header automatically?
AWS Cognito hosted UI returning id_token in URL
How can I make the redirect_uri of AWS Cognito (Hosted UI) authenticated?
Set Authorization header when redirecting client from Cognito to AWS API Gateway
How do I handle a Cognito auth redirect for a Lambda / API Gateway for UI?
We faced the same question a couple of years ago. Our solution was creating a proxy (using API Gateway and Lambda) that "moved" the id_token (stored in a cookie) to the Authorization header for every request to the server. It was ugly, but it worked.
BTW, getting id_token in the URL is how Implicit Grant works. But Implicit Grant is generally considered less secure than Authorization Code Grant. We have since migrated from Implicit Grant to Authorization Code Grant. However, we continue to use the proxy pattern (again using API Gateway and Lambda) as follows.
Exchange the returned code for access_token and id_token at the Cognito user pool's token endpoint. Store the tokens in a DynamoDB table with session_cookie as the partition key. Return the session_cookie as a cookie (with HttpOnly, Secure and SameSite=Strict) to the browser.
For each request from the browser, use the cookie to find the token in the DynamoDB table and put the token in the Authorization header.

How to allow guest access in Cognito

We are looking to move to Cognito for user authentication. Currently we rely on our system to create the user and authenticate using JWT tokens generated internally. We also have a guest user role where anonymous users are given access to limited apis. To achieve this, we first create the guest user as a normal user in our system and mark it a guest in db. This way we can generate JWT tokens for guest users that can be used to authorize limited set of apis.
With Cognito, creating authenticated users is straightforward as userpool token (ID token) generated can be used in Api Gateway with Cognito authorizer. However, we are looking to implement guest user access as well via Cognito. Userpools does not have that support. The only option seems available is Cognito Identity pool for unauthenticated access. But this requires IAM credentials to be generated and passed to Api Gateway which is different than ID Token flow for authenticated users. Also, it does not mention how we can attach custom information to the identity (guest) so that it can be decoded at the authorizer level in Api Gateway and passed to backend service.
Is Identity pool the only approach to implement guest access? My usecase does not require access to any AWS resources except Api Gateway for guest users. Please note the Api Gateway apis used for guest users are also being used for authenticated users.

Integrate Cognito with API Gateway and static credentials

So we built our service to give our users API Keys to access API Gateway and our service. Gateway acts as an endpoint for our Lambda functions.
The problem is, we got an email from Amazon saying that we hit our API Key limit of 500 keys. They said that we shouldn't be giving users API Keys because keys are meant for integrating with other services, not users. They said we should be using Cognito User Pools and our limit can't be increased.
The problem is, our users build HTTP requests in a tool called ManyChat - a tool for building chat bots.
Our users build dynamic requests and then save their chatbot to use that dynamic request. Our users can't go back and refresh those credentials as is necessary with Cognito tokens. The authentication method will have to use a static API Key I believe.
Is there a way to manage our users' usage while keeping the authentication credentials static?
1) Update 401 Unauthorized response template as per your need so that it contains the WWW-Authenticate header set to 'Basic'.
2) Create a custom authorizer that match your credentialand and retyrn response.
https://medium.com/#Da_vidgf/http-basic-auth-with-api-gateway-and-serverless-5ae14ad0a270

AWS API Gateway with cognito authorization

Currently I'm developing serverless architecture where there are set of resources and methods in AWS API gateway. I plan to add Cognito authentication(user pool) and authorization as secure layer to AWS API gateway.
There are 3 authorizer in AWS API Gateway which are IAM, Cognito User Pool and custom lambda.
For my use case, the sign-in and sign-up(authentication) are using cognito user pool via API gateway. It's perfect works. My user will given app client id and client secret to enable both processes. Once after sign-in, my intention is get user able to use the access token(returned by user pool) to access resource via api gateway.
However, my user can has different role such admin, owner or guest. User only can access the authorized api. My approach is to put user into different group in user pool, assign IAM policy to group and enable identity pool. This force me to change the authorization type in api gateway to IAM. and IAM require every request to be signed by Signature V4.
It means every requests have to sign up by session token, access key, secret (returned after exchange id token with federated pool) instead of using access token based approach. So in my use case, after my user sign-in via api gateway, my client app(web/mobile/postman tool) has to generate signature and put in Authorization header. Is there alternative ways to control authorisation in user pool group but using access token in api gateway? My understanding is access token (in Authorization header) is much easier to use than complex signed signature process.
Correct me if I'm wrong. Thanks.
Will this help instead?
Create groups in user pool and assign IAM role to the group.
And then add users to the group.
More documentation here: https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-user-pools-user-groups.html
You are on the right track but you have chosen one of the paths of Authorizing the user requests on AWS. You are using IAM and Identity Pool and because of that, you are forced to sign every request using Signature V4 provided by AWS.
Instead of going for I would suggest as per my experience to choose custom Lambda Authorizer over Identity Pool. In this case, your authentication will remain as it is that you have already built. But instead of applying IAM as Authorizer in API gateway, you can create a lambda function that will receive the ARN of the API gateway that the user wanted to authorize in the request and user ID_TOKEN that you received in during authentication from User Pool.
{
...
"cognito:roles": [
"arn:aws:iam::**********:role/addBookSellerRole"
],
"exp": 1565758916,
"iat": 1565755316,
...
}
You can see you will get the roles array from the ID_TOKEN in JWT received from authentication. You can use this role to fetch the attached policies to this role. Follow this document to fetch the policies from the role.
Once you get the policy JSON you can compare it with the ARN of the method received in request with the list of policies. And this way you have to generate a Policy Document that will either Allow or Deny the request.
To read more about it visit my medium blog Authorization using Cognito + API Gateway + IAM.

AWS Cognito, Lambda, User credentials in DynamoDB

I established a authentication flow with Facebook Login and AWS Cognito on the client site. Works fine. But now I need a reference of the user with its facebook id in a dynambodb table. Of course I could just call a AWS lambda function exposed via AWS API gateway, but how can I verify that the API call actually has a valid facebook id and that this facebook id matches the AWS Cognito Id. Maybe I am missing something here, I hope you guys can point me in the right direction ;) thanks!
If you can key your ddb table by cognito id instead of facebook id, you can invoke api gateway with cognito credentials. If you use callee credentials when calling lambda you can access the cognito id via the token $context.identity.cognitoIdentityId. This ensures the call was made by the owner of this id. You can further check that $context.identity.cognitoAuthenticationProvider is graph.facebook.com to ensure they authed via Facebook. Unfortunately, the facebook id is not passed in the credentials, so if you need it you will need a lookup table mapping cognito id to facebook id. For more details on the available tokens see here.
I would suggest to do the following (I'm new to AWS as well, Let me know if you have any suggestions):
Create a API Gateway /fblogin endpoint where you will POST the Facebook Access Token (You will authenticate with Facebook on the client side to get this token). That endpoint is linked to a Lambda function say fb_login.
In fb_login function you will authenticate with Amazon Cognito to get its credentials. You should have created a Federated Identity user pool in Cognito and assign appropriate roles to assume for this user pool. This helps if you want to restrict your API only to those who are authenticated and authorized. So, the result from Cognito will have IdentityId and Credentials. You can return them as a result of your request to /fblogin.
Using the above result you can sign the requests you send to your API on API Gateway (Or you can use AWS custom generated SDK for your API to handle the signing). On the API Gateway endpoints, enable CORS and authentication as AWS_IAM. This way, API Gateway verifies the user automatically by checking the signature in the request. You can get the User Id from $context.identity.cognitoIdentityId as others suggested. This way, you can be sure that the user is authorized and authenticated.
Note: Make sure you implement /fblogin endpoint on HTTPS, then the FB Access token will be secure. If not, it will be visible as plain text over HTTP.
Also, use a Dynamo DB table as a log for CognitoID - FacebookID. You can incorporate this in the Step 2 Lambda function ifself or anything you think is appropriate.