Cognito user pool for single admin - amazon-web-services

I'm trying to create a personal blog using s3 and lambda. I already have the API setup but I'm trying to figure out how to make the blog post requests more secure by requiring an authorization token in order to access the API Gateway.
I believe this can be done with cognito user pools but is usually used with many users not a single admin user. However, if there's another way I should go about this then I'm all ears.

You can implement this by:
Creating a User Pool in Cognito
If you are using the Hosted UI login pages, I recommend having the pages send a code response rather than a token response because you can call the token endpoint to get all the appropriate tokens.
Call your token endpoint with the code you receive in Step 2 (it'll be in the URL when you are redirected back to your site) to retrieve the ID, Access, and Refresh Tokens.
Once you have your cognitoUser tokens, you can wrap your blog publish function with a token check function to ensure that your token is up-to-date and send the updated token to your publish blog callback.
Send the user token in your headers: { Authorization: token } API Call.
In API Gateway, choose the Method Request in your Blog Post API and select your Cognito User Pool name under authorizers.
As long as the token you send is valid, the Method Request is all you need to update in order to secure the ability to post.

Related

Differentiate user signup versus login for AWS Cognito callback

I'm using Cognito and have a successful flow to my backend service (a lambda function).
I would like to only create a user on signup, not login. However, Cognito calls back to the same URL for login.
Currently, I'm taking the code in the query param and exchanging it for id_token, access_token, and refresh_token. In the id_token, there's an email, which I use to query DynamboDB.
I would like to save a call the call to DynamoDB so I'm wondering if there was a way to differentiate signup versus login in either the headers or the tokens?

Validating jwt token in REST api

I have a doubt regarding the jwt token validation done by the REST api and was not able to find a simple yes/no answer. Assume that everything is being transferred over HTTPS.
I have the following setup
React app
REST API
AWS Cognito that handles the user registration/login
When a user wants to login, then the React app would call the AWS Cognito api and validate the credentials. If valid, Cognito will send back a jwt token (that will contain the necessary meta data) that can be passed to the REST API. Now I see two options
the backend verifies that the jwt token was not altered using the rfc spec. If valid, the api extracts the necessary meta data and continues to process the request
The backend verifies the validity of the jwt token, but also calls the Cognito service to verify the metadata in the token.
I think that since everything is handled over HTTPS and the fact that its hard create a valid token then the first point is enough. There is no need to have an extra call over the wire. Am I wrong ?
Found the following question from softwareengineering.stackexchange.com which pretty much answers my question. Link
The local validation of the JWT token is enough when the token was created with asymmetric encryption.

Is the Access Token for a Cognito user available serverside?

I'm dealing with the issue of users not explicitly logging out of a web application after use, which is not secure enough for the use case. It is a React app with AWS Amplify and Cognito.
I plan to do this by tracking sessions in a database (I can capture the start or refresh of a session using a Cognito Lambda trigger written in Go on PostAuthentication_Authentication or TokenGeneration_RefreshTokens events), and expiring sessions using GlobalSignOut after a period of inactivity, but in order to invalidate the user refresh tokens on session abandonment, I need the Access Token, which appears to only be available to the client.
I can get this explicitly on login from the web client, and post it back to the database using GraphQL to record it, but I was surprised to see that it's not available from the Cognito payload sent to the Lambda event triggers. I'm also not sure of how to grab the refreshed token on the client if it refreshes after an hour of continued application use, without adding overhead to every change in the application.
Is there a way to request the current access token for a Cognito user from a server side process like a Lambda function if you're using Amplify on the client for the authentication flows? I cannot see anything in cognitoidentityprovider that allows me to retrieve the access token, but it's clearly needed to use GlobalSignOut.
You could use the Authorisation Code Flow with PKCE instead so the client is only exposed to the code which is then exchanged server-side using the token endpoint for cognito user pool / id token, access token and refresh token. You can return the user pool token to the client as that will expire after an hour while keeping the refresh token in your session manager on the server-side allowing you to fetch fresh tokens as needed or invalidate the session based on your requirements.
https://docs.aws.amazon.com/cognito/latest/developerguide/token-endpoint.html
I've found a workable solution that does not involve fetching the Access Token server side. We use AppSync for GraphQL - the access token is passed with each GraphQL request as an authorization header, and it can be accessed in the request template as follows:
#set( $myMap = {
"field": "${field}",
"user_id": $context.identity.sub,
"source_ip": $context.identity.sourceIp,
"arguments": $context.arguments,
"access_token": $context.request.headers.authorization
} )
{
"version" : "2017-02-28",
"operation": "Invoke",
"payload": $util.toJson($myMap)
}
In each Lambda resolver, I simply cache the access token when encountered, so that I always have the latest access token for the current user. My scheduled session manager function then retrieves the access tokens from the cache for any users it detects with an abandoned session and can use it as an input to GlobalSignOut.

Amazon AWS getAttribute() using AWS.config.credentials

I have just started with Amazon Cognito and I want to use it for my web application. I want to develop a stateless app, in which I SignUp/SignIn using Cognito and then using the JWT token in rest of the requests.
I have implemented sign-up and sign-in flow in Node.js using amazon-cognito-identity-js package and then using the JWT token to call a lambda function using aws-sdk. Things are as expected till here.
But now the issue is with different user operations like get attribute, verify attribute, update password etc. as listed #
https://docs.aws.amazon.com/cognito/latest/developerguide/using-amazon-cognito-user-identity-pools-javascript-examples.html
All of these operations require cognitoUser object and in the documentation they are using userPool.getCurrentUser(); expression.
And I have read somewhere that this method returns the last authenticated user. So I think this expression userPool.getCurrentUser(); will cause conflicts. For example if UserB logs in after UserA and UserA tries to update his password, it will not work.
Can someone suggests me what are the possible solutions?
Should I store the cognitoUser object in session at server side ?
[This solution breaks my stateless requirement and I will have to maintain session on server side.]
Is there any way to perform these operations using JWT token ?
Please suggest if you can think of any other better approach to implement Cognito in web app.
Thanks.
We have a stateless app using cognito and lambdas.
The way we have set it up is to not call lambdas directly but to use Api Gateway and lambda-proxy integration.
If you call lambdas directly from your front end code and are using the cognito tokens for authentication then you need to put a lot of logic in each lambda to validate the token, e.g. download the relevant keys, check the signature of the jwt, timestamps, issuer etc. If you use API gateway then you can just create a cognito authorizer and place it in front of your lambdas.
We pass the id_token when making api calls, then the call is validated by the authorizer and the lambda receives all the current attributes set up in the user pool. This means we don't need to make additional calls to get attributes.
For changing the user passwords this can be done from the front-end of the app by calling the cognito api with the access_token if you have allowed it in the user pool client setup.

Securing API's with Multi Factor Authentication

I want to secure my API with Multi-factor-Authentication on top of Auth Token/JWT. I have been searching but couldn't find any package that can work with drf. I am thinking to write my own django app. Any comments on what should be the architecture ?
One solution that comes to my mind is to introduce the token base architecture.If a user is accessing the mfa secured api then the request instance should be saved alongside a token and a sms should be sent to his mobile (In case of mobile as mfa) and response should be a that token. Then another request should be made to a mfa endpoint with token and mfa-code. Once verified, We would take his previous request object and complete the request.