Getting the Cognito User ID in API Gateway Lambda

The Problem

You have an API Gateway endpoint backed by a Lambda function, secured with a Cognito User Pool authorizer. You want to know which user made the request—but you don't want to trust a user ID passed from the client (because that's trivially spoofable).

The good news: Cognito has already authenticated the user by the time your Lambda runs. The user ID is in the request context. The bad news: it's buried in a string that looks like this:

cognito-idp.us-west-2.amazonaws.com/us-west-2_xxxxxxxxx,cognito-idp.us-west-2.amazonaws.com/us-west-2_xxxxxxxxx:CognitoSignIn:a1b2c3d4-5678-90ab-cdef-EXAMPLE11111

There's no clean userId field. You have to parse it out yourself.

The Solution

The user ID (the Cognito sub) is the UUID at the end, after CognitoSignIn:. Here's a function to extract it:

const userIDKey = 'CognitoSignIn';

function getUserIdFromCognitoProvider(cognitoAuthenticationProvider) {
  try {
    const segment = cognitoAuthenticationProvider
      .split(',')
      .find((part) => part.includes(userIDKey));

    const parts = segment.split(`${userIDKey}:`);
    return parts[parts.length - 1];
  } catch (error) {
    console.error('Failed to parse Cognito user ID:', error);
    return null;
  }
}

And to use it in your Lambda:

export const handler = async (event) => {
  const cognitoProvider = event.requestContext?.identity?.cognitoAuthenticationProvider;
  const userId = getUserIdFromCognitoProvider(cognitoProvider);

  if (!userId) {
    return { statusCode: 401, body: 'Unauthorized' };
  }

  // Now you have the authenticated user's ID
  console.log('Request from user:', userId);

  // ... rest of your handler
};

Why This Works

When API Gateway validates the JWT from Cognito, it populates requestContext.identity with authentication details. The cognitoAuthenticationProvider field contains the identity provider info and the user's sub claim.

It's not elegant, but it's reliable—and more importantly, it's not something the client can fake. If this field is populated, Cognito has verified the token.

TypeScript Version

If you want type safety:

function getUserIdFromCognitoProvider(
  cognitoAuthenticationProvider: string | undefined
): string | null {
  if (!cognitoAuthenticationProvider) return null;

  try {
    const segment = cognitoAuthenticationProvider
      .split(',')
      .find((part) => part.includes('CognitoSignIn'));

    if (!segment) return null;

    const parts = segment.split('CognitoSignIn:');
    return parts[parts.length - 1] || null;
  } catch {
    return null;
  }
}

I wish AWS provided a cleaner way to get this, but until they do, string parsing it is.

  • aws
  • cognito
  • lambda
  • api-gateway