Testing Cognito user pool auth with API gateway - amazon-web-services

I would like my client application to insert records in my dynamoDb instance using API gateway secured with Cognito user pools.
I have created my user pool and added it as an authorizer to my API gateway method call. Using AWS Cli I ran the following command which gave me my access token:
aws cognito-idp initiate-auth ...
My infrastructure seems to be working, now which direction do I need to go to pragmatically achieve signing-in as my user in the user pool, grabbing the token and calling my API method?

Well it's not difficult. You need to follow certain steps.
Create an user in Cognito user pool. Confirm it, by the means of activation message you have chosen. It can be sms or email as per the user pool settings.
After you confirm the user, you need to call the login API from Cognito SDK. Since I am comfortable in NodeJS, let me grab the method name - https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_InitiateAuth.html. Set AuthFLow to ADMIN_NO_SRP_AUTH .The response from this APi will have one idToken, one accessToken and one refreshToken. Since you need these credentials at your client, write an API in your preferred language, expose it your client and return the tokens.
Use the idToken to make API calls to your API Gateway Authorizer. This is how you pass the token using Postman -
You can replicate the same using any client. If you face any error, It'd be better if you show me your APIG authorizer configuration.

Related

User Management and Token based authentication in AWS Cognito and AWS API Gateway

I am running a simple Rest API based on FastAPI. This API runs in a AWS Lambda container. I have added API Gateway as a trigger.
Now I want to secure this API.
My expectation:
I create a User and a Password manually
The user can call a specific endpoint with his User and Password to receive an access token
With this access token the user should be able to access the API e.g. by passing a Bearer Token.
Actually I have tried AWS Cognito, but the only way to receive an access token is to use the CLIENT_ID and the CLIENT_SECRET. And I don't want to share this to external users of the API.
I think this CLIENT_ID and CLIENT_SECRET is made for a web-app or sth. like that but this is not what I want. I just need a simple pipeline of: user creation -> user login -> Access_token -> API.
I hope anyone of you is able to share a guide or similar. Maybe AWS Cognito is not made for such a use case , if you think so then just let me know and why.
Thanks in advance.
yes, absolutely it's possible, please refer below image.
In the first step your app user signs in through a user pool and
receives user pool tokens after a successful authentication.
Next, your app exchanges the user pool tokens for AWS credentials
through an identity pool.
Finally, your app user can then use those AWS credentials to access
other AWS services such as Amazon S3 or DynamoDB.
later on you need some custom authorizer in API-Gateway (lambda) to validate the token.

Run Lambda function with same permissions as user invoking API Gateway endpoint

I have the following setup:
REST API Gateway containing one endpoint with a proxy Lambda integration and secured using the AWS_IAM authorizer. End users retrieve temporary AWS credentials from a Cognito Identity Pool in exchange for tokens retrieved from a Cognito User Pool and then call the API using these credentials.
When users call the API Gateway, I want the invoked lambda function to run with the same permissions as the invoking user. For example, if the user only has the permission to read items from DynamoDB with a PK of CUSTOMER1234, I want the lambda function to also only have that permission. Different users will have different permissions so I can't "hard-code" that into my Lambda permissions.
This seems like a fairly common use case, but I was unable to find any documentation on how to achieve something like this.
One possibility would be to send the AWS credentials (i.e. access key and secret key) of the user with every request and then construct a new session using these credentials in the Lambda, but this probably is a terrible idea (it also increases function runtime by 5x).
It doesn't seem like a good idea to send AWS credentials over the network, as there is the chance that they could be intercepted by an attacker and used to access your resources until they expired.
It could be possible to use the JWT from your Cognito User Pool to get the AWS credentials in the lambda function e.g. using:
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: 'IDENTITY_POOL_ID',
Logins: {
'cognito-idp.<region>.amazonaws.com/<YOUR_USER_POOL_ID>': 'ID_TOKEN'
}
});
This would mean that your lambda's API calls would run using the role mapped to in your identity pool, and you could use the LeadingKeys condition to ensure that your web identity could only access their own data:
"Condition": {
"ForAllValues:StringEquals": {
"dynamodb:LeadingKeys": ["${cognito-identity.amazonaws.com:sub}"]
}
}
However, this would add processing time because you are making extra API calls (CognitoIdentityCredentials() makes 2 API calls behind the scenes) on every request to get the credentials. Plus, you couldn't use the AWS_IAM authorization on your API Gateway method because you won't have got the credentials yet. So you are then talking about having a two authorization setups. One to allow your web identity to call the API Gateway method, and a second for your Lambda function to run as your user.
So perhaps your choices are:
Make your API calls direct from your client
Instead of going via API Gateway, you could make the DynamoDB API calls directly from the client. This would work well with your Identity Pool setup, as you can make the CognitoIdentityCredentials() call just once when the user logs in to get the AWS credentials. The subsequent DynamoDB calls would then be made with your user permissions and you could use the LeadingKeys condition to ensure that your user only accesses their own data.
Accept that your lambda function will always run with the same execution role
If you want to use API Gateway backed with Lambda, then you could just accept that you will use Lambda or Cognito Authorizers to authorize your users have permissions to execute the API method, and then some further application-level authorization in the Lambda function to ensure they only call their own partition space. In fact, this way you might not need the Identity Pool, but rather just use the sub claim from the User Pool JWT token. After all, you will have validated the JWT containing the sub hasn't been tampered with, and that it was issued by the correct user pool and application client, so you can trust its contents.
You could integrate API Gateway directly with DynamoDB
Depending on your required logic, rather than have your API method backed by a lambda function you could integrate your API Gateway method directly with DynamoDB as shown in this amazon tutorial. Again, you would use the sub from the validated JWT as the partition key to enforce the correct data access.

Using Authorizers in API Gateway and Cognito User Pools

I've managed to setup a third party google login by integrating it with Cognito user pools. On successful sign-on, I am able to access an id_token as a query parameter in the redirect url.
I'm trying to sign REST calls to API gateway using this id_token. I have an authorizer configured on that particular API using Cognito user pools. When I try to test this on the Authorizer UI by setting the Authorization(header) field to this id_token which I received as a query parameter, I keep getting an Unauthorized request error.
Also, I have configured an IAM policy for my user according to this doc: https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-user-pool-authorizer-permissions.html
Can someone help me with what I'm doing wrong?
Thanks
Turns out you have to pass the access_token that Cognito returns as part of the authorization header. You can try if your access token works by testing it in the UI offered by the Authorizor interface of API Gateway.

Trying to setup user pool authentication for API Gateway

I'm trying to setup security on an API using Cognito user pools. I'm getting back 401 Unauthorized.
The API and User Pools are existing, and I've been using the user pool to log into an application. I'm now trying to secure the API calls.
I created an authorizer on the API,
Then I added the authorizer to one GET method in the API
Then finally I tried to test the API in Postman. I'm using the AWS Signature authorization.
Calling the method returns 401. The method functioned before with no security, and turning off the authorizer makes it work again (without security).
Any ideas what step I'm missing?
The AWS Signature authorization is different than a Custom Authorizer.
The AWS Signature authorization (Postman) requests an AWS AccessKey and SecretKey to authenticate requests. This corresponds to IAM Authentication in API Gateway. The AccessKey and SecretKey are received through IAM.
A Custom Authorizer takes a JWT called #id_token that is issued by your specified Cognito User Pool. To test the validity of the token, go to your custom authorizer and click test, and then copy and paste the token into the text area.
The way to perform the Custom Authorizer authentication is this:
obtain an #id_token from the your user pool by following AWS Configuration
Configure API gateway with a Cognito custom Authorizer with your user pool as the source (Seems that you have done correctly)
Use OAuth 2.0 as Authorization in postman, with your #id_token as the Access Token, Or add the header: Authorization with the value Bearer and the #id_token
Drop a comment if you want me to add the AWS Signature Auth Flow.
For authorization using Postman when using Cognito user pools, chose No Auth. Then add a header Authorization (the value in token source field of your authorizer) and copy the id_token into that header value. I did not have to add anything else besides that to make it work (i.e. no bearer).

AWS Lambda Authorizer

I got a graphql server running in Lambda, and everything works fine and I want my endpoint to only be accessible by authenticated users, my authentication providers are cognito identity with cognito user pool and facebook. So how can I check if the user sending request is authenticated? I'm new to AWS so, my question might confusing for AWS experts, but the main issue I have is "how can I check if the request is from authenticated user"? should I use AWS_IAM as authorizer or should custom authorizer?
What I initially did was setup a custom authorizer that checks if the accessToken from congito is valid, but I think this is not the right way and this will only work for cognito but not for facebook users.
you don't need to check anything... in API Gateway, select your lambda method, and in Method Request box, select "Auth: AWS_IAM" and then only logged in cognito users will be able to call your lambda method