What You’ll Learn

What You’ll Need

If you are new to Amazon API Gateway, please make sure to read Getting started with API Gateway. If you already have an API set up, skip this step by clicking the Next button at the bottom of this topic. However, if you’d like to deploy a new API in API Gateway, continue reading below.

From the different API types offered by Amazon API Gateway, we will go with REST API because it offers more features, one of which is important to the Cognito authorizer integration that we will use in this tutorial.

Please follow the instructions from Tutorial: Build a Hello World REST API with Lambda proxy integration.

At the end of that tutorial, you should have:

Choose a Method

Once you are done creating your Lambda function and API Gateway resource, you will need to create a method within the resource.

To get started, I recommend creating a GET method, but if you follow the tutorial completely, you will end up with an ANY method, which will work too.

Verify Your API Method

If you have followed all the steps from the tutorial, your deployed method should look similar to this image:

Deployed API method

Keep note of the REST API ID as well as the resource ID of the GET or ANY method that you configured. You will need them to configure the Cognito authorizer in the next steps.

After deploying your API, click GET, and use the invoke URL as shown in the image above. The URL format should be similar to the following:

curl https://<RESOURCE-ID>.execute-api.<REGION>.amazonaws.com/prod/helloworld

If you use curl to test, the response should be:

Hello, World!

Add the string parameter ?greeter=ThousandEyes:

curl --location 'https://<RESOURCE-ID>.execute-api.<REGION>.amazonaws.com/prod/helloworld?greeter=ThousandEyes'

The response should be:

Hello, ThousandEyes!

There are different methods that you can use to verify your configuration, including your browser and Postman.

If you are getting the above response, you can proceed to the next step.

The first step is to create the user pool with minimum and default parameters.

aws cognito-idp create-user-pool \
    --pool-name <YOUR_USER_POOL_NAME> \
    --admin-create-user-config AllowAdminCreateUserOnly=true \
    --policies PasswordPolicy='{"MinimumLength":8,"RequireUppercase":true,"RequireLowercase":true,"RequireNumbers":true,"RequireSymbols":true}' \
    --auto-verified-attributes email \
    --region <YOUR_REGION>

Make sure that you take note of the user pool ID and the user pool Amazon Resource Name (ARN) from the output of the create-user-pool command:

    "UserPool": {
        "Id": "us-west-xxxxxx",
        "Name": "my-user-pool",
        ....
    }

Create a resource server that will be used as the scope that we need to pass when using the client credentials flow.

aws cognito-idp create-resource-server \
    --user-pool-id <USER_POOL_ID> \
    --identifier <RESOURCE_SERVER_ID> \
    --name <YOUR_RESOURCE_SERVER_NAME> \
    --scopes ScopeName=<SCOPE_NAME>,ScopeDescription=<SCOPE_DESC> \
    --region <YOUR_REGION>

Next, create an app client within the user pool.

aws cognito-idp create-user-pool-client \
    --user-pool-id <YOUR_USER_POOL_ID> \
    --client-name <YOUR_APP_CLIENT_NAME> \
    --callback-urls <YOUR_CALLBACK_URL> \
    --explicit-auth-flows ALLOW_USER_SRP_AUTH ALLOW_REFRESH_TOKEN_AUTH \
    --allowed-o-auth-flows-user-pool-client \
    --allowed-o-auth-flows client_credentials \
    --allowed-o-auth-scopes "<RESOURCE_SERVER_ID>/<SCOPE_NAME>" \
    --generate-secret \
    --prevent-user-existence-errors ENABLED \
    --region <YOUR_REGION>

Finally, create a user pool domain. Try adding your name or a nickname to increase your chances of finding a domain that is available.

aws cognito-idp create-user-pool-domain \
    --domain <YOUR_USER_POOL_DOMAIN> \
    --user-pool-id <YOUR_USER_POOL_ID> \
    --region <YOUR_REGION>

The create-user-pool-domain command does not return any information. However, keep note of the domain that you choose; the Cognito URL will be in the following format.

The Cognito user pool is ready! Test your configuration by doing a POST request to your Cognito domain following the right syntax:

https://<YOUR_USER_POOL_DOMAIN>.auth.us-west-1.amazoncognito.com/oauth2/token?grant_type=client_credentials&client_id=<YOUR_APP_CLIENT_ID>&scope=<RESOURCE_SERVER_ID>/<SCOPE_NAME>

Use basic authentication where the username is your app client ID and the password is the app client secret. Both of these values are present in the output of the create-user-pool-client command.

curl -X POST \
-H "Authorization: Basic <username and password in base64>" \
-H 'Content-Type: application/x-www-form-urlencoded' \
'https://<YOUR_USER_POOL_DOMAIN>.auth.us-west-1.amazoncognito.com/oauth2/token?grant_type=client_credentials&client_id=<YOUR_APP_CLIENT_ID>&scope=<RESOURCE_SERVER_ID>/<SCOPE_NAME>'

To obtain the string to pass as the basic authorization header, you will need to format the client ID and client secret in Base64 as follows:

echo -ne "<CLIENT_ID>:<CLIENT_SECRET>" | base64

A successful response should look like this:

{
    "access_token": "eyJraW123465465as....",
    "expires_in": 3600,
    "token_type": "Bearer"
}

If you are getting an access token, you are ready to move to the next step. Save the access token value; you will need it in the next step.

First, create the authorizer in API Gateway:

aws apigateway create-authorizer \
--rest-api-id <value> \
--name <value> \
--type COGNITO_USER_POOLS \
--provider-arns <YOUR_USER_POOL_ARN> \
--auth-type cognito_user_pools \
--identity-source method.request.header.Authorization \
--region your-region

Then, configure your method to use the Cognito authorizer:

aws apigateway update-method \
    --rest-api-id <value> \
	--resource-id <value> \
    --http-method GET \
    --patch-operations op="replace",path="/authorizationType",value="cognito_user_pools" op="replace",path="/authorizerId",value="<value>"  \
	--region your-region

Everything is now configured and ready to test. From the previous test, you now have an access token. (If the token has expired, you can call the oauth2/token endpoint from the previous step to get a new valid token.) The access token can be used to make a call to the API, which is now requesting a Cognito token for authorization.

curl https://<REST-API-ID>.execute-api.<REGION>.amazonaws.com/prod/helloworld \
   -H "Accept: application/json" \
   -H "Authorization: Bearer <LongBearerTokenString>"

The response should be:

Hello, World!

Without the bearer token, the response will fail:

{"message":"Missing Authentication Token"}

So far, we have:

All this integration is now ready to be monitored by a ThousandEyes API test.

Let’s create an API test. We will need to make a POST request to the following endpoint:

https://api.thousandeyes.com/v6/tests/api/new.json

Remember to replace:

curl -X POST 'https://api.thousandeyes.com/v6/tests/api/new.json?aid=xxxxx' \
    -H 'Content-Type: application/json' -H "Authorization: Bearer <OAUTH_BEARER_TOKEN>" \
	  --data '{
        "agents": [
            {
                "agentId": "373421"
            }
        ],
        "interval": 300,
        "url": "<COGNITO_AUTH_URL>",
        "predefinedVariables": [
            {
                "name": "access_t",
                "value": "yyyy"
            }
        ],
        "requests": [
            {
                "authType": "BASIC",
                "username": "<APP_CLIENT_ID>",
                "password": "<APP_CLIENT_SECRET>",
                "url": "<COGNITO_AUTH_URL>",
                "method": "POST",
                "collectApiResponse":true,
                "name": "Get access token",
                "headers": [
                    {
                        "key": "Content-Type",
                        "value": "application/x-www-form-urlencoded"
                    }
                ],
                "assertions": [
                    {
                        "name": "RESPONSE_BODY",
                        "operator": "INCLUDES",
                        "value": "access_token"
                    }
                ],
                "variables": [
                    {
                        "name": "access_t",
                        "value": "access_token"
                    }
                ]
            },
            {
                "authType": "BEARER_TOKEN",
                "bearerToken": "{{access_t}}",
                "url": "<APIGW_AUTH_URL>",
                "collectApiResponse": true,
                "method": "GET",
                "name": "Make GET call",
                "assertions": [{
                    "name": "STATUS_CODE",
                    "operator": "IS",
                    "value": 200
                }]
            }
        ],
        "description": "Authenticated API Test",
        "testName": "Auth API Test from API"
    }'

If successful, the response will include a large JSON response with the test ID and other details about the test that was created.

Verify Your Test Configuration

Log in to app.thousandeyes.com. Navigate to Cloud & Enterprise Agents > Test Settings and search for the name of your test.

If you click your test, you should see a test with two steps in the target API. Click the 2-Step API button; you should see the following:

ThousandEyes API test view

The network test target is set to the Cognito URL. The network metrics will be collected for this URL; the API metrics are collected for each step in the test. Change this URL if you want to collect network metrics for the API instead.

We have configured the test to run every 5 minutes, so you might have to wait for a few minutes before the first test round is complete.

Navigate to Cloud & Enterprise Agents > Views. Select your test name from the drop-down menu. Your view should be similar to the following:

Test Views

If you would like to see the network metrics, click the Agent to Server layer.

Agent to Server View

In the Metrics drop-down menu, you can select different metrics and stack them for comparison and troubleshooting.

Go back to the API layer and click the Metrics drop-down. You will be able to select network metrics such as Latency, Loss, and Jitter and stack them together with API Transaction Time.

API Transaction Time View

This will help correlate network issues that have an impact on the API transaction time.

Stacked Views

Congratulations! You have created an API, and you are now monitoring it with the ThousandEyes API test.

Learn More