For some reason, Cognito authorizer gets ignored when I test invoke the method (It works with Postman and any client requests though). I pass the idToken on the Header Authorization so I can use $context.authorizer.claims.sub as my uuid on request transformation, but to no avail.
Right now the test invoke ignores any pre-integration steps, including authorization and throttle/quota check by API Key. We'd like to support a full end-to-end test invoke in the future, but for now you'll have to rely on end-to-end testing via the deployed API.
Related
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.
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).
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.
We are trying to use the API Manager (1.10) to call an existing API (POST) that already uses an Authorization header token. I several things including using mediation according to an article entitled "Pass a Custom Authorization Token to the Backend" and that didn't seem to work.
I finally tried setting the "Auth Type" to "None" which according to documentation should just pass the API call directly to the backend (including the authorization header). This didn't work either. The call gets to the backend service but seems to lose the Authorization header so it throws an 400 error (the same error I get when I leave out the header and call the backend api directly using SoapUI).
Any help would be appreciated!
If you followed the instructions here, it should work.
I have implemented this for several projects and I can attest it did work.
You may turn on wire logs via configuring log4j.properties, inspect the wire log and see what happens.
If you want to have authorization (oauth token validation) at the API gateway as well as want to pass the custom authorization header to back end, you will need to follow the setup described in the documentation[1].
If you want to disable authorization at the API gateway level by setting the authorization type[2] to "none" and want to pass the Authorization header (custom) from client to the back end through the API gateway, you need to do the following steps.
By default, the API gateway will drop the "Authorization" header without sending it to the backend[3]. To send the Authorization header to the backend through the API gateway, uncomment the following property and set its value as "false" in <wso2am-home>/repository/conf/api-manager.xml and
<RemoveOAuthHeadersFromOutMessage>false</RemoveOAuthHeadersFromOutMessage>
[1] https://docs.wso2.com/display/AM1100/Pass+a+Custom+Authorization+Token+to+the+Backend
[2] https://docs.wso2.com/display/AM1100/Key+Concepts#KeyConcepts-HTTPmethods
[3] https://docs.wso2.com/display/AM1100/FAQ#FAQ-HowcanIremovetheauthenticationheadersfromthemessagegoingoutoftheAPIGatewaytothebackend
A backend service needs to know the user for the service call. Reading through the API 1.6.0 documentation I have configured it to generate JWT and removed and republished my services as stated. Running tests, I am not seeing the JWT being passed to the backed service in the response headers in Fiddler. I am not using the ESB or Identity services from WSO2.
What am I missing?
JWT information should be passed in the header under the parameter X-JWT-Assertion. The Content is been encoded. Use TCPMon to intercept the request and see if the API Manager is actually passing the JWT. This would be a good starting point to debug.