Link to chapter - http://serverless-stack.com/chapters/mapping-cognito-identity-id-and-user-pool-id.html
What will be the usage of the UserPool User Id inside the lambda?
Iâve trying to store some user data that wanted to retrieve inside Lambda and couldnât figure out how to do it and ended up with a dynamodb table that has stored the CognitoIdentityId as a way to retrieve that data.
If this chapter is a solution to my problem I donât see which part of the JS sdk I have to use inside the lambda to access the user pool.
I think itâs useful for looking up user attributes for instance, if you wanted a subscription/follow feature between users. It appears to me to open up your userpool to be more like a dynamoDB table you can query.
It seems so but unfortunately I could find what part of the JS sdk letâs you get that information. Maybe @jayair could give us a hint about what was the meaning of that chapter.
Yeah the basic problem is that when you authenticate your Lambda functions with IAM, you only get the Identity Id to work with. But there is no way to get the User Pool Id given the Identity Id. But this chapter details a little trick to let you get that.
You could then use that to get info using the Admin Cognito User Pool - https://docs.aws.amazon.com/cognito-user-identity-pools/latest/APIReference/API_AdminGetUser.html.
@jayair back to this old topic
I have been trying to find how to get username & email for the IAM authenticated user in WS API $connect and this article and forum gave a bit hope. I can extract the UserPoolId and UserPoolUserId, but I still canât figure out how to get username. AdminGetUser requires to have parameters UserPoolId and Username. So there is no help there? What I am missing?
Thatâs weird. That AdminGetUser API used to take the user id. Can you try passing that it to see if that works?
I tried already and it worked, yee. That was so confusing, I lost days for looking the answer. All good now. This blog post helped to get to the track, thanks.
Hello! thanks for your post and all the website, it helps a lot! I am trying to get the cognito id and user pool id but I get null values for the event.requestContext like:
identity: {
cognitoIdentityPoolId: null,
accountId: null,
cognitoIdentityId: null,
caller: null,
sourceIp: ,// my ip
principalOrgId: null,
accessKey: null,
cognitoAuthenticationType: null,
cognitoAuthenticationProvider: null,
userArn: null,
userAgent: 'insomnia',
user: null
},
Do you know why could this be happening? thank you!!
Hmm that means that the auth didnât happen. How are you making this request?
It looks like this method of extracting of the Cognito user pool user ID page (aka âsubâ or subject) has become obsolete. I proposed a new approach further below. But first an explanationâŚ
Problem: The following cognitoIdentityId
property no longer exists embedded within the event object passed into Cognito-authenticated Lambdas:
event.requestContext.identity.cognitoIdentityId
Gone. This was a reasonable approach seemingly due to Cognito design/API shortcomings, but it has now become obsolete likely due to Cognito refactoring its internals. This may have worked some time ago, however this is an âunofficialâ way to fetch user pool user ID (aka âsubâ or subject.) Below is an alternative which should presently work.
Solution: I was able to workaround this by injecting the header object with a new header, through an API Gateway endpoint & method integration, with the value for the $context cognitoAuthenticationProvider
value, which similarly has the user pool user sub ID embedded inside. Once on the header, you can access it in your Lambda, parse and use.
Implementation:
- Add an integration. In the API Gateway management console, for each endpoint and method combination, go to its integration screen. Add a Parameter mapping, of Mapping type âAll incoming requestsâ. The âParameter to modifyâ should be something like âheader.subâ, Modification type âOverwriteâ, Value of â$context.identity.cognitoAuthenticationProviderâ
Save and repeat for all endpoint & method combinations needing access to this subject user ID.
The downside is this integration needs to be manually added in the console for each endpoint/method combo needing user ID. Hopefully SST devs will add it to their âconstructsâ to better automate or expose through CDK.
- Create a utility function in your serverless app like the following:
const TOKEN_STRING = "CognitoSignIn";
// cognito-idp. region.amazonaws.com/user_pool_id,cognito-idp.region.amazonaws.com/user_pool_id:CognitoSignIn:token subject claim
export function extractUserPoolId(event) {
const cognitoAuthenticationProvider = event.headers.sub;
/*
For example, for an identity from an Amazon Cognito user pool, cognito-idp.
region.amazonaws.com/user_pool_id,cognito-idp.region.amazonaws.com/user_pool_id:CognitoSignIn:token subject claim
We want the part after the CognitoSignIn
*/
const tokenStartIndex = cognitoAuthenticationProvider.indexOf(TOKEN_STRING);
const subId = cognitoAuthenticationProvider.substring((tokenStartIndex + TOKEN_STRING.length + 1));
console.log(`subId = ${subId}`);
return subId;
}
- Finally, use it in your Lambdas:
const userPoolUserId = extractUserPoolId(event);
Disclaimer: as with any AWS API or structure: subject to change.
This approach is probably more suitable as AWS should not be refactoring the $context constant in the integration to retrieve this value, at least without advanced notice. I did much online investigation and found my approach here to be the best in this scenario. Feel free to use and/or update this page with the new approach. All ears if there is a better way.