Part 1: Building Production-Ready AI Agents with Amazon Bedrock AgentCore (Architecture & Auth)

Part 1: Foundation, Architecture & Authentication

Introduction

Building a production-ready AI agent chatbot requires more than just connecting to an LLM. You need secure authentication, scalable infrastructure, persistent memory, and seamless tool integration. In this three-part series, I walk through implementing a complete Amazon Bedrock AgentCore solution for a business assistant chatbot. I’ll try to elaborate on the authentication piece to provide deeper insights into securing your AI agents.

This first article lays the foundation by:

  • Understanding the solution architecture
  • Setting up infrastructure with Terraform
  • Understanding & Configuring AWS Cognito for secure authentication

What This Series Builds

The business assistant chatbot provides:

Local Tools:

  • Company policy information
  • Client account lookup
  • Document analysis

Lambda/Gateway Tools:

  • Warranty status checks
  • Web search

Additional Capabilities:

  • Persistent memory across sessions
  • Secure user authentication

Solution Architecture

Solution Architecture

Architecture Main Components

1. AgentCore Runtime

The serverless runtime that hosts the AI agent. It processes user requests, executes tools, and orchestrates responses using the Strands Agent framework with Claude Sonnet.

2. AgentCore Gateway

Exposes Lambda functions as MCP-compatible tools. The agent can invoke serverless tools like warranty checks and web search through this gateway.

3. AgentCore Memory

Manages conversation history and context with three strategies:

  • Semantic: Stores business facts and client information
  • Summary: Maintains conversation summaries
  • User Preferences: Captures client preferences and patterns

4. AgentCore Identity (AWS Cognito)

Provides OAuth 2.0 authentication with:

  • Web Client: For user login via the Streamlit frontend
  • M2M Client: For service-to-service authentication between Runtime and Gateway

5. AgentCore Observability

Built-in OpenTelemetry integration with CloudWatch for tracing, debugging, and monitoring agent performance.

Simplified Data Flow

User Authentication Flow — Web Client

The diagram below illustrates how users authenticate through the Web Client to access the AgentCore Runtime:

Web Auth Flow

User authentication flow using OAuth 2.0 authorization code flow. The Web Client (public client) authenticates users through Cognito, which issues access and ID tokens. The Streamlit frontend then uses these tokens to invoke the AgentCore Runtime.

Backend Service Authentication Flow — M2M Client

While users authenticate via the Web Client, backend services use a different flow. The diagram below shows how the MCP Client (inside the Runtime) authenticates to the AgentCore Gateway:

Machine to Machine Client Auth Flow

Backend service authentication using OAuth 2.0 client credentials flow. The MCP Client makes a direct POST request to Cognito’s token endpoint with M2M credentials (client_id + client_secret), receives an access token, and uses it to call the AgentCore Gateway. The Gateway validates the JWT token before executing Lambda tools.

Infrastructure Setup with Terraform

The infrastructure uses Terraform to provision all AWS resources in a repeatable, version-controlled manner.

Key Infrastructure Components

The Terraform configuration creates:

  • AWS Cognito User Pool with web and M2M clients
  • Lambda Functions for gateway tools (warranty check, web search)
  • IAM Roles for Runtime and Gateway execution
  • SSM Parameter Store for centralized configuration
  • Lambda Layers for dependencies (DuckDuckGo search library)

Cognito User Pool Configuration

The authentication architecture consists of three key components:

1. User Pool

  • Central authentication authority for the application
  • Manages user accounts and credentials
  • Issues JWT tokens for authentication

2. Web Client (Public Client)

  • Purpose: Frontend user authentication (Streamlit app)
  • Generate Secret: false (public client, no secret required)
  • OAuth Flows: Authorization code flow
  • Scopes: openidemailprofile
  • Use Case: Users log in via the web interface

3. Machine-to-Machine (M2M) Client (Confidential Client)

  • Purpose: Backend service authentication
  • Generate Secret: true (confidential client with secret)
  • OAuth Flows: client_credentials flow
  • Scopes: Custom resource server scopes (read)
  • Use Case: MCP client authenticates to AgentCore Gateway

Resource Server

  • Identifier: default-m2m-resource-server-{account_id}
  • Scopes: read (defines API permissions for M2M clients)
  • Purpose: Enables fine-grained access control for backend services

The Terraform configuration creates these components:

# Cognito User Pool
resource "aws_cognito_user_pool" "agent_user_pool" {
  name = local.user_pool_name

  # Use standard usernames; allow email as an alias for sign-in
  alias_attributes         = ["email"]
  auto_verified_attributes = ["email"]

  password_policy {
    minimum_length    = 8
    require_lowercase = false
    require_numbers   = false
    require_symbols   = false
    require_uppercase = false
  }

  schema {
    name                = "email"
    attribute_data_type = "String"
    required            = true
    mutable             = true
  }

  admin_create_user_config {
    allow_admin_create_user_only = false
  }
}

# Web Client (Public - No Secret)
resource "aws_cognito_user_pool_client" "agent_web_client" {
  name         = local.web_client_name
  user_pool_id = aws_cognito_user_pool.agent_user_pool.id

  generate_secret = false

  explicit_auth_flows = [
    "ALLOW_USER_PASSWORD_AUTH",
    "ALLOW_USER_SRP_AUTH",
    "ALLOW_REFRESH_TOKEN_AUTH"
  ]

  supported_identity_providers = ["COGNITO"]
}

Key Points:

  • Simple password policy (8 characters minimum)
  • Email-based authentication
  • Public client (no secret) for frontend use
  • Supports password and SRP authentication flows

SSM Parameter Storage Pattern

Terraform stores all configuration in SSM Parameter Store for runtime access:

# Store Cognito Discovery URL
resource "aws_ssm_parameter" "cognito_discovery_url" {
  name  = local.cognito_discovery_url_param
  type  = "String"
  value = "https://cognito-idp.${var.aws_region}.amazonaws.com/${aws_cognito_user_pool.agent_user_pool.id}/.well-known/openid-configuration"
}

# Store Web Client ID
resource "aws_ssm_parameter" "user_pool_client_id" {
  name  = local.user_pool_client_id_param
  type  = "String"
  value = aws_cognito_user_pool_client.agent_web_client.id
}

This pattern allows the agent runtime and deployment scripts to dynamically retrieve configuration without hardcoding values.

After Terraform creates the infrastructure, the SSM Parameter Store contains all the configuration parameters:

Example SSM parameters created by Terraform, including Cognito URLs, client IDs, Lambda ARNs, and IAM role ARNs. These parameters are accessed by deployment scripts and the runtime.

Deploying Infrastructure

cd terraform
terraform init
terraform plan
terraform apply

The other Terraform files (lambda_agent_tools.tfagentcore_roles.tf) handle Lambda functions, IAM roles, and permissions. The next article explores these in detail.

After Terraform deployment completes, the Cognito User Pool appears in the AWS console:

Cognito User Pool

The Cognito User Pool created by Terraform, ready for user authentication. The pool provides OAuth 2.0 authentication with web and M2M client configurations.

Creating Test Users

After deploying infrastructure, you need to create test users for authentication.

The user creation process:

  1. Creates a Cognito user with specified credentials
  2. Automatically confirms the user (no email verification required for this demo)
  3. Generates a bearer token for API access
  4. Stores the token in SSM Parameter Store at /app/{prefix}/cognito_bearer_token

After creating users, they appear in the Cognito User Pool console:

Users

Cognito users in the User Pool showing confirmed status and enabled state. Users can later authenticate and access the AgentCore Runtime.

Authentication Flow Overview

Once users are created, the authentication flow works as follows:

  1. User Login: User enters credentials in Streamlit frontend
  2. Token Generation: Cognito returns JWT access token and ID token
  3. Runtime Invocation: Frontend sends requests with bearer token
  4. Token Validation: Runtime validates token against Cognito discovery URL
  5. Request Processing: AgentCore processes the request and returns response

Next?

In the future episodes I’ll cover:

Part 2 covers deploying the AgentCore Gateway with Lambda tools and configuring AgentCore Memory with multiple strategies for persistent, context-aware conversations.

Part 3 completes the journey by deploying the AgentCore Runtime with local and Gateway tools integration, building a Streamlit frontend, and testing the complete end-to-end solution.

If you have any questions, don’t hesitate to write in the comments!

Resources

Author

Noor Sabahi | Senior AI & Cloud Engineer | AWS Ambassador

#AWSBedrock #AgentCore #AWSAmbassador #Cognito #Terraform #AgenticAI #ServerlessAI #AgentCoreArchitecture #AWS #GenAI