AWS Cognito - where in code should I process oAuth authorization code? - amazon-web-services

I have got one beginners questions. I am just starting with AWS Cognito User Pools and set oAuth "Authorization Code Grant" workflow succesfully - so now, after the login, I am succesfully redirected and get the authorization code in the url. The next step is to exchange it for the actual JWT token, but the problem is that I miss some broader perspective and dont know whats the best practice in this case. I know the javascript code to exchange the code for token, but I dont know where it should run.
Shall I use Triggers functionality in my user pools, tie Lambda function to some event (which one? "Post Authentication"?) and let this Lambda function exchange the code for token and save it as a session?
Or shall I put all this functionality into the url I redirect to after a successful login? Is there some best practice for this situation?
Thank you

The question to ask is: "Now the user is authorized.. now what?"
The AWS services that you want to make available to your users will determine what type of authentication flow you need to use. Since your question is fairly broad.. I will give you the high level of two types of authentication flow.
Federated Identities:
You can configure federated identities to grant users AWS IAM credentials (AccessKey and AccessSecret). When you set up a Federated Identity Pool, you specify the identities that can receive IAM credentials (for example: Your cognito pool, google, any other openID provider) and the IAM policy which will grant access to specified resources. This guide will review how to do this in your application code.
API Gateway Custom Authorizer You can also configure a Custom Authorizer with the source being your Cognito User Pool. This will allow you to make a request using the jwt #id_token received from authenticating against the user pool.
Specific answers to questions:
Shall I use Triggers functionality in my user pools, tie Lambda function to some event (which one? "Post Authentication"?) and let this Lambda function exchange the code for token and save it as a session? - Generally Triggers are used to store user data for analytics or server side processing. If you are using Cognito for authentication you don't need to use Lambda
Or shall I put all this functionality into the url I redirect to after a successful login? Is there some best practice for this situation? - I would recommend using a library such as AWS Amplify to manage Authentication with Cognito.

Most common approach I have seen with recommendation for code grant flow is the approach you mentioned,
shall I put all this functionality into the url I redirect to after a
successful login
The advantage of this is that you can store the refresh token server side and use it to refresh the id_token before it expires (There are several places which states not to store the refresh token client side).
However, if you look at the implementation in AWS AmplifyJS library for Code Grant, it does this in client side storing the refresh token also in local storage and refreshes the id_token from client side using JavaScript.
So both approaches are there while using both in different projects, I feel the latter is easy to implement and maintain.

Related

How do I manage AWS cognito code grant flow on the frontend using the hosted ui

I would like to use Amazon cognito as a way to allow users to sign up to my app and validate api calls, so I don't have to handle user passwords or create a custom account recovery email system.
The problem is im not sure I understand how its supposed to work or what tools I am meant to use. Heres how I imagine it:
This way I could use cognito to identify users and authorize api calls.
But I am not sure if this is correct. For example I'm not sure if the frontend is supposed to refresh the tokens or the backend.
I am also not sure if I am meant to implement the code for exchanging and refreshing the token and logging out of users myself, but it seems that way since I can't find any tools that would do that for me.
I have found some libraries concerning aws cognito, but none of them mention exchanging or refreshing tokens:
https://www.npmjs.com/package/amazon-cognito-identity-js
https://www.npmjs.com/package/amazon-cognito-auth-js
https://www.npmjs.com/package/#aws-cdk/aws-cognito
I did find this library mentioned in the documentation that can be used to validate jwt id tokens on the backend.
https://github.com/awslabs/aws-jwt-verify
I am using userpools and no identity pools, since I don't grant users access to my aws resources.
So basically my question is, is my perception of the cognito workflow correct and if yes, how can I exchange the grant code for an id token and how can i use the refresh token to refresh the id token.

Best practices for using AWS Cognito with AWS SNS and expiring push tokens

I have an application (Java Spring backend + iOS/Android native frontends) that uses AWS Cognito for Authentication and AWS SNS for sending push notifications to devices. The client apps currently pass the device-specific push tokens (FCM, APNS) to the backend, which informs SNS.
We are struggling to figure out the best way to deal with users logging out or simply not using the mobile apps for a while, and expiring/disabling those push tokens. Cognito does not appear to have any sort of trigger or notification for when a token expires or a user signs out. This leads to users still receiving app pushes after logging out or when their access/refresh tokens have expired.
I am looking for suggestions and best practices on what to do here. Some options we entertained are to inform our backend in a separate call, move all device management there, or even façade all of Cognito behind our own backend calls, but maybe there’s better ways.
last month they released refresh token revocation, is a way to revoke a refresh token and all access tokens that were previously issued by that refresh token become invalid
this is enabled for new user pools but i believe in your case, you need to manually enable it in (e.g. you created the user pool before the feature was released)
Cognito does not appear to have any sort of trigger or notification for when a token expires or a user signs out.
you are correct here, but, in case you use GlobalSignOut API in your App, you could track it via CloudTrail or EventBridge and trigger a lambda do to something with the event
Some options we entertained are to inform our backend in a separate call, move all device management there, or even façade all of Cognito behind our own backend calls
i worked in both scenarios, while the façade gives a lot of flexibility, if you are offering social login, it is annoying to setup the whole oidc flow,
in my projects i usually use cognito as an user directory to generate unique user ids and integrate with other aws services.
like DynamoDB with item-level control based on the Cognito User Id, which is handy:
https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_examples_dynamodb_items.html
https://aws.amazon.com/blogs/mobile/building-fine-grained-authorization-using-amazon-cognito-user-pools-groups/
making it easy to create and manage user devices token etc
but maybe there’s better ways.
hope never dies 😆

I am confused how I am meant to control access in a API Gateway Rest API using Amazon Cognito User Pools

I have spent 2 days trying to understand the idea behind Amazon Cognito Access Control for a site I am trying to create. Its very simple:
The site allows users to create posts
Anyone (anonymous users and signed in users) should be able to see posts
Only signed in users should be able to create posts
Only the original author should be able to edit his own posts
Now heres the things I think I have understood about amazon cognito:
Cognito user pools are meant for rest interfaces and identity pools are used to create temporary amazon roles with specific policies so people logged on to my service can access aws services such as dynamodb or s3 buckets directly
In order to make an authorized request to my rest interface, a user has to sign in using the cognito UI and receive an access token, that has to be sent with every request to the Rest API to verify the request
The verification can be done automatically using the cognito authorizer right in API Gateway or by redirecting the access token to lambda and verifying it directly there
If its done with the cognito authorizer, the username and other information cannot be read from within lambda
If I use AWS Amplify to handle request authorization on the client side, the access tokens are renewed automatically
But theres still some questions I have about the whole process:
Are Cognito usernames guaranteed to be unique? And if there not, how can I let the user choose a guaranteed unique username after registration or using a google login?
Are access tokens equivalent to session cookies?
If I am meant to handle access tokens on inside a lambda script, is there a library or service I can use? Because I haven't found a way to verify the token or get the user associated with the token
Why doesn't the built in authorizer redirect the user information to the lambda script?
Is there a prebuilt lambda authorizer that I could plug into API Gateway directly, that would allow both signed in and anonymous users to make requests to it and redirects user information to the lambda script? Because I couldn't find one in the repository or anywhere else?
So, I dont have all the answers, but I have some that will hopefully direct you:
Are Cognito usernames guaranteed to be unique
A User cannot signup if a username/email is already used. You need to specify which field to use for username (ie email or username)
Are access tokens equivalent to session cookies?
No, an access token is normally communicated within the authorization header of a request via a bearer token strategy and the cookie is within the cookie header. Some services will validate a cookie, others (especially machine to machine) will validate an authorization header. In some cases, developers may decide to make these the same, but its not always this way.
If I am meant to handle access tokens on inside a lambda script, is there a library or service I can use.
If you are looking to get context (like the username, which is encoded within the JWT string) of an access token, then you can use JWT decode functions. By the time the request hits lambda, the Authorizor has already validated it, so you do not need to do the same again.
Why doesn't the built in authorizer redirect the user information to the lambda script
Because not all services need/want it. Its better for consuming services to do what they need with the context after they decode the token
Is there a prebuilt lambda authorizer that I could plug into API Gateway directly, that would allow both signed in and anonymous users to make requests to it and redirects user information to the lambda script?
This question shows a problem with your understanding of rest. An API should leverage CRUD actions; so Create may only be granted to contributors, Read may be granted publicly, Update may only be granted to owners, Delete may only be granted to owners. The above is a generalization, but you need an API strategy; when you develop this strategy, you will realize there is no "easy" button.
In general, I would have 2 API Gateways, one for read-only purposes and another for managing content. This keeps it simple and allows you to scale in different ways (ie you may want your contributors to not be blocked by read-only uses in situations of scale issues).
Also, adopting a path based strategy can help with simplifying who has access to what resources. Take the below example:
a user sends a POST request to /api/blog/ to create a new blog (resulting in /api/blog/:blogId). The /api/blog/ endpoint is not "owned" by any specific contributor. Later the user makes an update to /api/blog/1234-abcd...now your service must make an additional call to see if that resource is owned by the user (this is called the "entitlement" process). In psuedo-sql, you would SELECT created_by FROM blogs WHERE id='1234-abcd' and then see if the created_by field matches your user id.
Anywho, you get the point :) This becomes even MORE complex if you allow teams/multiple users the ability to modify resources...and new we get into RBAC (role based access control), which is a much longer topic.
Sorry for the digression, but hopefully this gives you more direction.

AWS API Gateway authorizer google sign in

I have an API Gateway/lambda REST API that is being accessed from a react web app. I need to add authentication using google as an identity provider. The app should also keep the user signed in.
I understand when the user first grants access to the (react) client app, it should send the ID token to my backend, which should then verify the token.
Since my architecture is serverless, I assume the verifying should be done in the API Gateway authorizer function, which then grants access to the API on successful verification of the token.
My question is, how do I then create a persistent session? Should I be saving anything to my database about the user? Does the token need to be verified on every API call?
Should the authorizer be checking if the user is already registered or if it's a new user?
It would be easiest to use AWS Cognito for this. Configure a user pool as an authorizer for your API gateway and then configure Google as an identity provider for that user pool. This link might be helpful: https://docs.aws.amazon.com/cognito/latest/developerguide/google.html. Cognito even has a hosted UI if you want to use it for signing users in.
As for your question about persisting user sessions, they usually get persisted in local storage in the browser or in a cookie or some similar mechanism. You can also persist them on the server-side in a database like you were mentioning but that isn't really for authentication purposes.
The user session will contain an access token. The access token is short-lived, meaning you can only use them for an hour usually. After that you have to use a separate refresh token to generate a new access token. And to be extra safe the refresh token itself will expires after a few days (and you have to sign back in).

AWS Lambda with Cognito right approach

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