How can I get the identity id of the user (logged in by AWS Cognito) that invoked an AWS Lambda function? Do I have to use the SDK on the Lambda function to get the identity
If anyone else stumbles upon this, I think this will help you a lot.
Note this only applies if you're using the Cognito User Pool Authorizer. If you want to use AWS_IAM with Cognito Identitys check out my github example https://github.com/VictorioBerra/js-cognito-auth-example (read down to EDIT area below)
If you have "Use Lambda Proxy Integration" checked then you wont have access to Request Template Mappings. But you can get to the claims inside the token in your lambda function:
exports.handler = (event, context, callback) => {
//create a response
const response = {
statusCode: 200,
body: JSON.stringify({
"user email": event.requestContext.authorizer.claims.email,
}),
};
callback(null, response);
};
Basically you need to have your APIG secured with AWS_IAM AND you must auth via a Cognito Federated Identity which will return a sessionToken example using user pools. This is what makes the AWS IAM credentials temporary. Now you have everything you need to auth to your APIG.
To test this, download the desktop version of postman, toss in your API URI (grab this from the stages area) and then under Authorization fill out the 5 fields you need for Sig4 signing. You will see 'event.identity' object in your lambda function is loaded up with properties such as the user
object.
If you want to use the APIG auto-generated SDK it comes built in with a factory that takes the accessKey
, secret
, and token
and signs everything for you. Same with the aws-sdk. You can init the credentials with those three items and it will automatically sign all requests for you with those temp creds. If you want to straight up manually hit your API with window.fetch, request, curl, (insert http client here) you can calculate your own Sig4 (beware it can be a little complicated or use a modern library to do it for you.
Also for the record, while doing my research I noticed that if you want to NOT use AWS_IAM as an APIG authorizer, and you want to use "Cognito Identity Pool Authorizer" which is a fancy new option in the dropdown in APIG you can still get a ton of info on the user in the lambda event if you just pass the JWT gained from a successful Cognito popl auth to the APIG as the Authorization header. Inside that JWT is a lot of attributes which you can customize in your pool settings.
IMO professional opinion I think using the AWS_IAM temp creds authorizer is preferred. This way, you can use as many different IdPs as you want in Cognito Identities (Facebook, Twitter, pools, etc.)
Per the docs, it looks like information about the identity provider would only be available for an invoke through the Mobile SDK.
To get around this, one option is to pass the identity ID to the function manually as part of the event. Assuming you are doing something like AWS.config.credentials = new AWS.CognitoIdentityCredentials(...)
then you should be able to get the ID via AWS.config.credentials.identityId
(after the credentials are refreshed).
EDIT: A better option for identity validation is to let Cognito/IAM handle it, and assume that if a user can successfully invoke a Lambda function, that means they are allowed to. In this case to manage per-user validation, take a look at whitelisting.
My observation is the following.
If you call the API Gateway with a signed Request where you actually provide the accesskey, secret and sessionToken which you can extract via (JS SDK):
AWS.config.credentials = new AWS.CognitoIdentityCredentials(...)
AWS.config.credentials.get(..)
And assumed that your lambda is called from API-Gateway via LAMBDA_PROXY and Authorizer AWS_IAM. You can only access user stuff in lambda with:
exports.create = function (event, context) {
secdata = event.requestContext.identity.cognitoAuthenticationProvider;
}
Then you will get, apart from other stuff, the "sub" of the cognito UserPool User. So if you really want to know more about the user, it seems you need to ask AWS again via SDK call.
For a Python Lambda, invoked via Javascript AWS SDK / Cognito / Amplify...
https://docs.aws.amazon.com/lambda/latest/dg/python-context-object.html
context.identity.cognito_identity_id
It should look something like this:
{aws region}:{ GUID }
Assuming you are using an Identity Pool, this will return the Cognito Federated Identity, that can be used for fine grained access control. This is safer than relying on the Javascript payload containing the identity id.
The Cognito Identity Pool Auth Role will need to have Lambda:InvokeFunction policy, otherwise the user won't be able to invoke the function in the first place.
Edit: This works when calling the Lambda function DIRECTLY, not via API Gateway.
Edit2: The Cognito user is allowed to call the lambda because it is explicitly set in the IAM Cognito Auth role.
I was using Kotlin and my Lambda handler was
override fun handleRequest(event: APIGatewayProxyRequestEvent, context: Context): APIGatewayProxyResponseEvent
But event.requestContext
had no authorizer
. The solution was to upgrade the dependency in build.gradle from
com.amazonaws:aws-lambda-java-events:2.1.0
to com.amazonaws:aws-lambda-java-events:2.2.7
. After that, I got the username as follows.
val claims = requestContext.authorizer["claims"] as Map<String, String>
println(claims["cognito:username"])
println(claims["email"])
In AWS javascript SDK inside lambda function just use context.identity.cognitoIdentityId It is working for me