Best practices for using AWS Cognito with AWS SNS and expiring push tokens - amazon-web-services

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 😆

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.

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.

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.

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 - where in code should I process oAuth authorization code?

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.