TL;DR A role allows an identity to call the APIGateway. The UserPool is attached to the identity, and also attached to the app client id, and issues JWT tokens containing the app client id.

The API Gateway allows JWT tokens which have recently been issued for that client id and will forward requests to the Lambda.

What and Why

I spend a long day working it out and the documentation while large, is not quick. It seems to be you need to know it all before you can understand it. So here is my summary.

What is a JWT token?

Google it. But in brief it contains 3 sections (header.payload.signature), each of which is base64 encoded. When you call the user login URL that is hosted by Cognito, you get back a long URL containing an id_token, run that through a JWT decoder and you can see the payload contains the a payload of:

{
  "at_hash": "redacted",
  "sub": "redacted",
  "email_verified": true,
  "iss": "https://cognito-idp.eu-west-1.amazonaws.com/redacted",
  "cognito:username": "redacted",
  "preferred_username": "redacted",
  "aud": "redacted",
  "event_id": "redacted",
  "token_use": "id",
  "auth_time": redacted,
  "exp": redacted,
  "iat": redacted,
  "email": "redacted"
}

The iss field is the Issuer needed by the ApiGateway security config.

Lambda

Your GoLang code, which adheres to the ApiGateway JSon input and outputs.

ApiGateway

This directs a public url to your lambda. It also allows CORS and Authentication.

CORS - if you are running your javascript in a web page locally you cannot call another website url unless the server you are calling tells the browser that it expects this. You can google the implementation. The important thing is that the browser enforces CORS by asking the server what OPTIONS it supports.

JWT security. You can hook the APIGateway to into the issuer and client app id from the Cognito user pool, and you need the iss (issuer) field from the JWT id_token that Cognity UserPool issues.

Cognito User pool

Create a user pool, and define an App Client - which allocates an App client id. You should at the same time create an SES authenticated email to issue verification, but that is a different concern.

This is the critical bit, the UserPool App Client Id has to be the same as the one in the ApiGateway.

Cognito Identity pool

The identity pool should be created, and this is what lets a logged in user invoke an ApiGateway using a JWT token.

You need the user pool id, to hook this identity pool up to it.

IAM roles

The identity pool will create an authenticated role and an unauthenticated role. You need to go to the IAM console in AWS and configure the authenticated roll to have the permission: AmazonAPIGatewayInvokeFullAccess

Summary of AWS Cognito invoking a Lambda via ApiGateway

A user logs into a pool and is given back a JWT id_token containing the app client id and issuer, plus other stuff.

The identity pool has an authenticated role which is configured to allow it to invoke the AWS APIGateway via an IAM role.

The javascript in your browser at the logged in URL can extract the id_token and place into the REST call header to the ApiGateway.

The APIGateway will confirm to the browser that CORS allows javascript loaded from that domain to call it. It will also confirm the id_token has the correct client id, and that the issuer and other time based details for the token are correct (this is all hidden from you as a dev, its internal to AWS).

The APIGateway will then forward the request using its standard JSON representation to the Lambda.