AWS Lambda with Cognito right approach - amazon-web-services

I would like to make a simple API available to a client. The client uses the output of my API within his application. The API is a pretty simple one. I'm deploying with the serverless framework to AWS Lambda. The functions exposed via the API don't use any other AWS services (like S3 etc).
My question is what kind of authentication to use. I was thinking to try to use cognito for this.
1. Question:
Does this make sense? Or is for this simple use case even an easier option available?
2. Question:
So I get this right. I would first create a user pool. Then create an identity pool based on this user pool?
3. Question:
At the end, my client gets the access token from cognito and attaches is to the header in the request. This gives him then access through API Gateway to my REST API and the lambda function is triggered. But how does the client in the first place can create an "account" doe the user pool? Am I involved i this?

Cognito Authentication does sound like a good option for this use-case. You can have a flow as follows:
Cognito User Pool Authentication -> Token passed as header to the API in API Gateway -> API returns JSON data after successful authentication
[a].
I would like to emphasise that a Cognito User Pool is enough to satisfy this use-case. Cognito User Pools are used for Authentication, and Cognito Identity Pools are used for Authorization. Cognito Identity Pools essentially generates temporary AWS credentials, which are vended by AWS STS. Hence, I do not see where you would require Cognito Identity Pools here.
And to generate a JWT Token, you would need to have the user perform a successful authentication operation. To perform a successful authentication operation that returns tokens, you could have a look at the InitiateAuth API call[b].
References
[a]. https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-integrate-with-cognito.html
[b]. https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_InitiateAuth.html

Related

3rd Party App Tokens within AppSync with User Pools

after some reading on Using multiple authorization types with AWS AppSync GraphQL APIs and The Complete Guide to User Authentication with the Amplify Framework , one thing I could not figure out is if I can have 3rd Party Application Tokens (e.g. like Twitter API) and use AppSync+Cognito to generate credentials for service-to-service mutations/query?
I already have a user flow via Cognito (type AMAZON_COGNITO_USER_POOLS). I want to centralize service-to-service calls using my AppSync. Limiting the service/token access would be great too (to only X Mutations, instead of the whole schema). Would that be possible?
I'm a bit lost around what are the current limitations.
do I need a Custom Authorizer in Cognito?
should I move everything to IAM credentials?
a Lambda Resolver with manual credentials check + AppSync call?
I can't do it and I need to store these tokens in a different place (DynamoDB, etc), with metadata/some id to have some kind of identity and always use Lambda Resolvers etc.
thoughts and insights are more than welcome,
thanks!
As of today, AppSync does support 4 types of user authentication
API key (no authentication)
IAM credentials
OpenID tokens
Cognito User Pool tokens
There is a request to add custom lambda authorisers as well, but nothing has been announced to date.
In your scenario, I would use Cognito User Pool authentication on the App Sync side and federate Cognito User pool with Twitter OIDC. I know a couple of years ago Twitter was only supporting a custom subset of Oauth2. I'll let you check if they do support OIDC now :-)
But you're not the only asking this question
https://forums.aws.amazon.com/thread.jspa?messageID=881666
User pools for users who register via twitter?

AWS Cognito and API gateway using Lambda authorizer

I am trying to create APIs using API gateway and Lambda functions.
Based on the user group ( not the Cognito user groups ), I want to provide access to separate DynamoDB tables.
The approach I am following is, I am creating a separate Cognito user pool for every group of users.
When the user logs in, he is authenticated with the appropriate user pool.
For calling the subsequent APIs, I am planning to make use of Lambda authorizer.
The user will pass the ID token in the HTTP header request and I want to validate this ID token.
Is this the right approach? Or if there is any better approach for implementing this workflow.
Can we make use of Cognito user groups and will it be a secure approach?
I want to strictly separate the tables of one user group from another.
I came across the below link, to verify the ID token.
https://github.com/awslabs/aws-support-tools/blob/master/Cognito/decode-verify-jwt/decode-verify-jwt.js
There are some proven architectures and tools provided by AWS to simplify the above usecase.
There is no need of multiple user pools for the above usecase. This can be handled with a single user pool itself.
A simple architecture can be UI->API gateway->Lambda->DynamoDB
Users in Cognito user pool can be added into groups and set with IAM policies. Then API Gateway can be configured for IAM or cognito authorizer. Each Lambda writen for accessing different DynamoDb tables can be authorised at API Layer.
There is no need for a custom authorizer in this case.
Use AWS Amplify for user authentication and all other communication. Amplify will handle the token passing part by itself with any extra code written. JWT tokens can be read/validated and logically used in the client UI layer as well as in server code (lambda) seemlessly in this approach. The same token is used in API gateway for authorization by default (without any code written).
Cognito user pool and identity pool are enterprise-grade AWS solutions and AWS Amplify compliments the high secure implementation of Sigv4, SRP, etc. protocols which are very tough and complicated to implement using custom code.

Lookup cognito userpool uset based on cognito dentity pool identity in API Gateway

I am an AWS newb, so please go easy on me :)
I have setup a proof of concept to proove out an authenticated API backed by lambda with the following components.
API Gateway -> backed by Lambda
Federated Identities backed by AWS Cognito UserPool
I have the authorizer setup in the API gateway to use the IAM role which is being provided by the Federated Identity pool.
I can see the identity (ap-southeast-2:<GUID>) coming through into the gateway ( using this in my integration request mapping template "$context.identity.cognitoIdentityId" ) from https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-mapping-template-reference.html#context-variable-reference
From either the gateway or lambda how can I resolve the 'ap-southeast-2:<GUID>' back to the source identity which resides in the user pool. (E.g. Pull one of the custom attributes from it)
Other information if relevant, i'm using Amplify-AWS for the client calling into the API Gateway.
TIA.
As you're noticing, Cognito as an identity provider is not the same as Cognito as a user pool.
Federated Identities provide a way of giving someone identified access to your AWS resources. The identity_id the identity provider gives you can almost be thought of as a tracking code. CIP (Congito [Federated] Identity Provider) allows you to get an identity id by signing in through any number of providers (not just the user pool), and even by not signing in at all.
User Pools give you a way of managing users for your application (i.e. a set of usernames, emails, passwords, etc).
This is the reason getting from identity_id back to the user pool user is hard (because, there's no guarantee it is a user pool user, it could well be someone from Facebook).
From what you've said, however, the assumption that said identity_id came from a UserPool authentication is safe. This means you have two options:
The official way will be to use identity:GetOpenIdToken to convert identity_id (you can ignore the logins part of the request) into an OpenId token. You can then use this token against the userpools:GetUser end point. There's a few pitfalls here, like ensuring you authenticate with a scope that allows you to see all the attributes you care about.
Curiously, however, the value of cognitoAuthenticationProvider is not opaque, and can (unoffically) be decoded:
// Cognito authentication provider looks like:
// cognito-idp.us-east-1.amazonaws.com/us-east-1_xxxxxxxxx,cognito-idp.us-east-1.amazonaws.com/us-east-1_aaaaaaaaa:CognitoSignIn:qqqqqqqq-1111-2222-3333-rrrrrrrrrrrr
// Where us-east-1_aaaaaaaaa is the User Pool id
// And qqqqqqqq-1111-2222-3333-rrrrrrrrrrrr is the User Pool User Id
The above example, with more details about how you can then use this with userpools:AdminGetUser can be found here: https://serverless-stack.com/chapters/mapping-cognito-identity-id-and-user-pool-id.html

Use custom authorization logic with AWS Cognito authentication

We have a Cognito User Pool which contains the users we would like to allow access to, to our API. Our API uses Lambda functions to service the endpoints. The Cognito pool is configured with a custom field roles which is essentially a comma-separated list of roles that user possesses.
Now, first, we want the Cognito authentication to take place (to determine whether the user does belong to our pool and the credentials are valid). Then, we somehow want to run our custom logic to run which will look at the roles field which it will receive through the claims, and then allow or deny the request based on internal business logic.
We tried using a custom authorizer to implement this logic and set it as the authorizer for our endpoints. Then, we enabled Cognito authorization for this authorizer function. The problem is that since Cognito protects API endpoints and not lambda functions per se, the Cognito authorization simply does not run when an API endpoint is hit and the custom authorizer is called.
How do we achieve our objective of using custom logic with Cognito authorization? Any help in this regard would be highly appreciated.
All of the claims in the users' token are available in the context that can be passed to your lambda function if you are using cognito authorizers under $context.authorizer.claims.property Would mapping that claim into your lambda function and checking that the roles is present at the beginning of your lambda work for you?

lightweight rbac for federated identities using aws api gateway with or without cognito

I can't see a good design for claims- or role-based authorization over an AWS PaaS (gateway/lambda) API. Right now, there seems to be a functionality blindspot regardless of how you combine the following:
gateway cognito user pool or custom authorizers
cognito identity pools used for web and user pool identity federation
IAM roles for gateway execution authorization
Specifically, the blindspot seems to be associating cognito identities with roles (more varied than keys and suffixes in dynamo and s3) based on user attributes in a way that:
doesn't require a custom endpoint in your API to vend IAM temp creds (and consequently using something other than the supplied and/or generated SDKs)
doesn't require authorization logic in every lambda function
doesn't require persisting the above mapping in dynamo, cognito sync, etc
doesn't layer or sequence a separate flow for authorization (e.g. separate token)
lets your users sign in using external idps
I assume the following is impossible or excessively hacky:
cognito user pools that overlap or moving users between pools to represent the configuration of their roles
directly getting cognito user pool attributes from congito identity pool identity tokens (GetOpenIdToken)
having a readily-modifiable client pick its own privileges (e.g. choose an IAM role)
running every request as dry-run in a custom authorizer or otherwise shadow-implementing IAM
securing actually role-specific IAM roles with some kind of shared secret, etc.
Here are some examples and their shortcomings:
A user logs in with user pool credentials and attempts to execute a gateway api method.
A cognito authorizer over gateway api methods would let me say autheticated-therefore-authorized and map attributes/claims into the integration request, still leaving it to the lambda function to implement actual authorization logic.
A custom authorizer won't automatically validate and parse a user pool token, but I could still do so and conditionally construct a role.
A user logs in with google+ credentials, having a user pool identity as well, and attempts to execute a gateway api method.
A cognito authorizer is useless.
A custom authorizer won't automatically validate and parse the google+ token, but I could still do so and conditionally construct a role. Only now I'd need to map this to a user pool identity manually. Cognito adds no value at all here -- just an awkward document database as a service.
A user logs in with google+ credentials, having a user pool identity as well, then gets an identity pool token (GetOpenIdToken) and attempts to execute a gateway api method.
A cognito authorizer is useless.
A custom authorizer won't automatically validate and parse the cognito identity token, but I could still do so and conditionally construct a role. I still need to do manual mapping because I won't get the user pool attributes with this intermediate token.
A user logs in with google+ credentials, having a user pool identity as well, then gets temp creds (GetCredentialsForIdentity) and attempts to execute a gateway api method.
The default authorizer is useless. You just get authenticated-therefore-authorized.
A cognito authorizer is useless.
A custom authorizer is useless.
The easiest solutions to most of these problems are in User Pools (i.e. using Lambda hooks in the auth flow to check privileges, attributes can be retrieved from the token an authentication generates...etc.), however your requirement that users can sign in with external providers is not currently supported.
From that, you can potentially use Cognito federated identities with user pools and external providers, but that brings up some awkwardness. Building in the privilege authentication into the user pools lambda hooks when multiple providers are available is awkward and forces the usage of user pools with other providers.
From that, I would say mapping privileges to identity id in some external storage is the way to go, using some external hook (Lambda?) with that id to assume a role and get credentials, but you mentioned you wouldn't want to do that.
I would agree that what you're aiming for is not absolutely possible as is. My recommendation might be to get in touch with an SA and see if they can help you design a complex solution that fulfills your requirements.