Is it necessary to use triggers in CUSTOM_AUTH of AWS cognito? - amazon-web-services

I want to create OTP based authentication using AWS cognito (CUSTOM_AUTH), all resources I saw were having 3 triggers(defineauth, createauth etc). Can I implement custom auth without using them ?

You need all three. The first (Define Auth Challenge) lets you define the cognito auth statemachine execution (can include built in challenges). The second (Create Auth Challenge) sets up the challenge and defines the values to check against. The last (Verify Auth Challenge Response) lets you perform tests against the response and define whether the challenge succeeded. That gets passed back into the state machine which calls back to the first handler (Define Auth Challenge) which is where you can declare whether the user successfully authenticated.
Amazon has some examples of their own. I've seen a few random tutorials post flows that have security flaws so I'd stick with AWS for this.
Email OTP example can be found here.

Related

Custom phone verification in AWS Cognito?

AWS Cognito SDK provides two methods:
GetUserAttributeVerificationCode
VerifyUserAttribute
The first one generates a 4-digit code for the provided attribute (email or phone) and the second one verifies the provided attribute with the provided code.
I want to use my own service for sending SMS verification codes. Unfortunately, AWS doesn't seem to provide an API, where I can manually set a 4-digit code on a cognito user awaiting confirmation inside something like a custom attribute phone_code_verification and then call VerifyUserAttribute to verify that code.
Is there a way to achieve this ?
Also, AWS Cognito throws LimitExceededException, TooManyRequestsException and other useful errors, so I would like the proposed method to be wrapped in the same AWS logic and not have to implement rate limit or request limits myself.

Serverless AWS - is it worth using custom authorizers (as a lambda)?

Hey I am getting started with the serverless framework, apigateway, lambdas and authorizers.
Here my questions:
In order to verify a proper JWT token (which seems nowadays the best solution for serverless authentication), I would need a client id. Since the authorizer lambda is not capable(?) of reaching any other parameters of the request into the lambda except for the token itself, this is a difficult task to do. How can I achieve this?
Since with every authenticated call, an additional lambda is called, my costs are doubled?! May be I am misunderstanding something here, but it seems to me like implementing a method for verifying my token without using the authorizer is cheaper and I don't need to implement the authorizer lambda itself.
The whole point of OAuth2 is that at the point of authorization you don't care who the bearer presenting you with a token is or which client they are using (web app, Postman, etc.), only that the token is valid for whatever the token bearer is trying to do. You trust that the authentication has happened because the token issuer has done the authentication.
When you talk about the aud(audience) (from comments) in JWTs, which may or may not be included dependent on the JWT issuer, this is intended to reflect the service or services that the JWT is valid for.
This could for example have a value of 'myAPIName' or 'myAPIName/test' or even ['myAPIName/test1', 'myAPIName/test2'].
If you need to validate an individual aud claim you have two choices, you can either have different Lambdas authorizing different api routes and methods with hardcoded aud variables or you can get the name of the api being called and map it back to something that would match an aud claim.
For example the method arn for the incoming request can be found in event.methodArn. This looks like arn:aws:execute-api:{regionId}:{accountId}:{apiId}/{stage}/{httpVerb}/ potentially with [{resource}/[{child-resources}]] dependent on your implementation. With a bit of string manipulation, you could map this back to the format of an audience claim (whatever that looks like for you).
If you would rather work an api name instead of an api name you can use the apigateway.getrestapi method for whatever sdk you are using. Documentation on this method for the JavaScript sdk can be found here.
The JWT may have a sub(subject claim), again dependent on implementation of the JWT issuer, this could relate to any of your users (or at least the users the JWT issuer knows about). Validating this beyond checking the signature of the JWT is pointless. The best you could do is check if that user exists and only if you have access to the same user database that the JWT issuer does. Although this can be used to ensure that UserA only has access to UserA's data. Again, you are trusting that the fact a bearer has a token is proof that they have authenticated (proved who they are).
I hope that answers part one of your question.
In regards to part 2, the advantage of using a Lambda Authorizer over doing the authorization in the target Lambda is caching.
So envisage I have a token valid for one hour and I call your API once every second for 30 minutes (1,800 calls). You have a Lambda authorizer with a response cache time of 10 minutes. That means you check the JWT 3 times for 1800 api calls.
But if you do the validation of that token in your target Lambda, you are doing that processing 1,800 times.
There is authentication with AWS Cognito which will allow you to use authentication outside your application and still being able to let your application divide the users into subgroups based on custom roles or similar.
If for some reason you cannot use AWS Cognito (Why not?) there is both the possibility of custom authentication (the same for each function with SLS) or even authenticating with custom code inside each lambda function.
I would recommend to use Cognito, and only custom if you know you need it.

Combine client_credentials and Custom authentication flow in Cognito?

Wondering if it's possible to combine using the client credentials OAuth flow in Cognito with a custom authentication flow as described here: https://docs.aws.amazon.com/cognito/latest/developerguide/user-pool-lambda-challenge.html
I know about custom authentication flows in Cognito, but I am not so well versed in OAuth itself. But as far as I understand it, the client credentials flow, is unrelated to a user? Because in that case, I would think it is impossible to use a custom authentication flow since the SDK documentation states the following (taken from the AWS node.js SDK):
The authentication parameters. These are inputs corresponding to the AuthFlow that you are invoking. The required values depend on the value of AuthFlow:
[...] For CUSTOM_AUTH: USERNAME (required)
If the value passed as USERNAME in the CUSTOM_AUTH flow is not a known user in Cognito, the lambda trigger for the custom flow will never be executed. And since it is never executed, it is not possible to use the USERNAME parameter to pass any other data to the lambda trigger (you can of course use custom authentication parameters, but you also need a valid USERNAME).

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.

'Unauthorized' when using Cognito User Pool Authorizer

So I had an API (let's call it API number 1) and one user pool. The API was used for testing purposes. It called a lambda function to update an IOT shadow. Now I used cognito to create a user pool and added some users in it. Then, I created an authorizer for API number 1 with the same user pool and enabled authorization in POST method execution for it. I created a login form so that I could log into cognito user pool and would get an ID token from it. I used that id token in POSTMAN along with Authorization header and the post worked. When I did not provide the id token, I got message: unauthorized as a response. The IOT shadow was updated only when I provided the authorization header and id token which meant everything went smoothly.
Then for testing purpose I created another API (API number 2), I replicated API number 1 entirely, created an authorizer with the same pool, enabled Authorization, logged in, got the id token used it in POSTMAN with Authorization header (the same process) and it didn't work. I kept getting message: unauthorized.
Then I thought maybe the problem was with API number 2 and created API number 3. This time I also created an entirely new user pool. I used that user pool to create an authorizer. The rest, I replicated API number 1 entirely again. I enabled CORS, in POST method execution I added Authorization. I did everything. Still when I tried again with POSTMAN, it didn't work.
So, API number 1 still functions perfectly like it should. API 2 and API 3 do not work despite having the exact same configurations as API 1.
I really do not know where I am going wrong. I even tried creating separate lambda functions for each API. Even the lambda code is the same (except for the IOT certificates and the IOT shadow URL).
Please, Help!! At this point I think I have tried almost everything and still I don't know whats wrong. One seems to work with the same configuration that the other two have whereas the other two don't. Thanks alot in advance.