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.