If using multiple UserPool's "App clients", do I need to add them all to IdentityPool's "Authentication providers"? - amazon-web-services

I'm writing a web app which is using AWS Cognito UserPools for user authentication and IdentityPools for granting direct access to an S3 bucket.
This JavaScript web app has its own App client ID in the UserPool with which it interacts with it.
I also have a couple of Lambda functions doing some admin functions towards the UserPool and IdentityPool. These lambda functions have their own App client ID.
I used to have only a single Authentication provider added to the IdentityPool, with the same App Client ID that the lambda functions have set.
In this setup, the web app was having issues. I was able to authenticate towards the UserPool, but when the identity token was sent to the IdentityPool, I received an error "Token is not from a supported provider of this identity pool.". I believe this was because the aud parameter of the JWT was set to the UserPool ID which was not added to the IdentityPool
I eventually realized that I could get rid of the error if I added another "Authentication provider" to the IdentityPool, filling in the same UserPool ID and the other App client ID.
My question now is - is this the correct approach? Am I perhaps misunderstanding the App client ID meaning and usage? Am I way off base with my approach?

Yes that sounds like a perfectly good approach. If you don't encounter any security or functional issues it is the "correct" approach.

Related

Could I use multiple AWS Cognito app clients to give API access to my users?

So, I know the answer is "yes I can", but is this the right path?
I have a Cognito userpool within all my platform users, now we would like to open specific API Gateway endpoints to specific users, so I just thought about using a Cognito app client for each user who wants these special access.
If a user wants to use the API will need an app client setup with its id/secret keys, then I can create an authorizer in the API Gateway pointing to this userpool and add it to specific endpoints.
Then the user will use his/her id/secret keys to generate a token to be used against specific API endpoints.
This seems to be clean and neat, but there is a big problem: Cognito limits to 10k app client per userpool
We don't actually have so much users wanting to access our API but who knows in the future.
So is this still the right path?

What is the best way to authorize an AWS API call for a logged in user?

I have a spring boot based web application which already authenticates the user. I would like to create some AWS APIs using AWS api gateway and a springboot rest app deployed on EC2. The user will log into the existing application and call the new AWS APIs from the browser ajax calls (like an SPA I guess but I have a server and can use client credentials/secrets if needed). What is the best way to handle security for the APIs. My first thought was to generate a JWT using a shared server side secret for hash and verify it with an AWS lambda. But this seems a bit non standard. Oauth2 might be better but might also be over kill. Not sure the performance would be good. Few requirements
token passed to the API should be a user specific token and have an expiration (and hence a refresh token)
The user is already logged into my web app and calling the api should not issue a login challenge.
AWS API Gateway should be able to verify the token before passing it to the application
Any token passed to the API should probably be generated on the logged in web application. Server knows the user is authenticated and should generate the user access token on behalf of the user. The AWS api should be able to figure out what privileges the user has based on the user principle or scopes in the token
I've thought about using Cognito AWS but I dont want to require the users to preexist in a user pool. Cognito seems geared more for the authentication rather than authorization and I would not be using the cognito login functionality. I dont know if its possible to use the oauth2/token endpoint alone with cognito.

Testing Cognito user pool auth with API gateway

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.

AWS Cognito HTTP authentication

I try to set up a test API with AWS API Gateway, Lambda and Cognito so secure the access. Since I am new to the AWS world, I am not sure how can I create a "logged in" post request to the AWS service with for example the request library
I guess on the client side I first have to log in via Cognito and the AWS Api and then use the informations I get to create a signed request like it is described here:http://docs.aws.amazon.com/general/latest/gr/sigv4_signing.html ?
If I am on the wrong path, please tell me and point me in the right direction :)
Preface:
I will explain the flow of Google+ integration with Cognito, it goes almost the same for others. I will use node.js (javascript), after that you can have your users authenticated from Google and authorized by IAM and Cognito to access API Gateway.
Cognito is a federated login service, it offers you to sync "configuration" of your mobile/web app. First you have to setup cognito with an identity provider, say Google+ for example. for that:
Create a Google app in your Developer console
Create a pool in cognito and add google as a provider, configure your pool with the policies and the roles (services you want to give your users access to, in this case only API Gateway).
In your web/mobile app, show the user Google+ Signin button, after the user clicks on it, google will call back a callback url with code parameter code, use that token
Use this code to get a Cognito identity for your user, in this case We trust Google:
var params = {
IdentityPoolId: setting.POOL_ID,
Logins: {
'accounts.google.com': google_token // Coming from Google OAuth2
}
}
// Get Id from Cognito
cognitoIdentity.getId(params, resolverFunction);
Get IAM temporary credentials forthat Identity IdentityId, your Google authenticated user:
var params = {
IdentityId: IdentityId,
Logins: {
'accounts.google.com': google_token // Coming from Google OAuth2
}
}
cognitoIdentity.getCredentialsForIdentity(params, resolverFunction)
Your user is now authenticated with Google and have the authorization from the IAM service (through the roles/policies you attached to your Cognito pool).
In your API Gateway, activate the IAM authorization, and use the Credentials you got from point 7.
Use the Accesskey, secretKey and the token to sign every request you make for your API built on top of API Gateway, you can you use this lib: aws-v4-sign-small
Quick notes and headsup:
All of this is Asynchronous actions, so If you are in node js, it is way better to use Promises (ES6 or Bluebird).
Pay super attention to the roles you attached (acces to dynamodb document or S3 file, etc. read more about IAM it is suer helpful and you can do a fine grained authorizations)
Hope it is clear or at least it gives you a direction to start with.
One of the benefits of using API Gateway is that you can automatically generate SDKs for your API, which easily integrate with Cognito credentials. This saves you from the trouble of implementing SigV4 auth yourself.
Here are a couple of simple examples using Cognito credentials with a generated JavaScript SDK:
https://github.com/rpgreen/aws-recipes/blob/master/app/index.html
https://github.com/awslabs/api-gateway-secure-pet-store
Cheers,
Ryan
As Ryan mentioned, the best way to do this is via the API Gateway SDK. The downside to using this stack is that it becomes harder to integrate with off the shelf front-end tools. You can no longer make direct request to your REST end-points, you will want to go through the SDK.
You definitely lose some ease of development because you can't just slap something like ngResource on top of your endpoints and call it a day. You'll have to set up the calls to each of your AWS end points in a service layer yourself.

sendMessage to SQS from Browser

I am building an SPA with Django REST as the backend. Right now I am using the standard Django authentication system and User models.
I would like the JS running on the SPA to be able to insert messages into an AWS SQS (i.e. sendMessage).
AWS has these doc on calling sendMessage from JS in the browser.
They also provide these docs on how to authenticate the user. My thought right now is to use Amazon Cognito. From the FAQ:
Q: What if I register and authenticate my own users?
Amazon Cognito can integrate with your existing identity system. With
a simple API call you can retrieve a Cognito ID for your end users
based on your own unique identifier for your users. Once you have
retrieved the Cognito ID and OpenID Token Cognito provides, you can
use the Cognito client SDK to access AWS resources and synchronize
user data.
Am I correct that for this to work, I would need to:
Create an IAM user for each user in my system. Or do I just need one IAM role?
When the user logins in my site (Django backend), I would have my backend then make "a simple API call [to] retrieve a Cognito ID"
Send that Cognito ID when the user loads the SPA.
User the Cognito ID from the JS running in the browser to call sendMessage to the SQS queue
Am I missing something here? Is there someway to remove the Django User backend and just user IAM Users so that I can avoid having to keep the two users lists in sync? I found this project but it does not seem to be maintained.
UPDATE:
It seems that there might be an alternative method of doing this where I don't use Cognito at all but rather expose an endpoint that can sign requests, "Query Request Authentication". This Heroku page talks a little about building a signing service.
Is this in fact an alternative option and if so what are the pro/cons of these approaches?
Amazon Cognito does not require you to register IAM users, just the 2 IAM roles. A slight modification to what you would need to do:
Create an Amazon Cognito Identity pool, configure with your developer provider.
Update the IAM roles associated with your pool to allow access to the services you want (for instance SQS).
From your Django backend, call GetOpenIdTokenForDeveloperIdentity to get the OpenId Connect token and identity Id for this user, return this to your JS application.
Configure your CognitoCredentials in the JS SDK. In the logins map, use the key cognito-identity.amazonaws.com and the value as the token returned from your Django backend.
Use the JS SDK to call SQS or any other services you wish from your application.
While using pre-signed URLs for SQS can work, using Cognito with the JS SDK will allow you to leverage other services supported by the SDK (DynamoDB, SNS, S3, etc).