Architecture Overview
Deployment Architecture
flowchart TB
subgraph Internet
User[User Browser]
end
subgraph AWS["AWS Cloud"]
subgraph CDN["Content Delivery"]
CF[CloudFront]
S3[S3 Bucket<br/>Frontend Assets]
end
subgraph Compute["Backend Services"]
AppRunner[App Runner<br/>Backend Flask API]
end
subgraph AI["AI Services"]
Runtime[AgentCore Runtime<br/>Strands Agent]
Gateway[AgentCore Gateway<br/>MCP Protocol]
end
subgraph API["API Layer"]
APIGW[API Gateway<br/>HTTP API]
Lambda[Lambda<br/>Secured API]
end
subgraph Auth["Authentication"]
Okta[Okta<br/>OIDC Provider]
end
end
User --> CF
CF --> S3
User --> AppRunner
AppRunner --> Runtime
Runtime --> Gateway
Gateway --> APIGW
APIGW --> Lambda
User <--> Okta
CDK Stacks
| Stack | Resources | Description |
three-tier-chat-api-dev | API Gateway, Lambda | Secured REST API |
three-tier-chat-agentcore-dev | Runtime, Gateway, Interceptor Lambda | AI Agent with MCP |
three-tier-chat-backend-dev | App Runner Service | Flask API proxy |
three-tier-chat-app-dev | S3, CloudFront | Frontend static site |
User Flow Sequence Diagram
sequenceDiagram
autonumber
participant User as User (Browser)
participant Frontend as Frontend<br/>(React)
participant Okta as Okta<br/>(IdP)
participant Backend as Backend<br/>(Flask)
participant Runtime as AgentCore<br/>Runtime
participant Gateway as AgentCore<br/>Gateway
participant Interceptor as Interceptor<br/>Lambda
participant API as Secured API<br/>Lambda
%% Authentication Flow
rect rgb(240, 248, 255)
Note over User,Okta: Authentication Phase
User->>Frontend: 1. Access App
Frontend->>Okta: 2. Redirect to Login
Okta->>User: 3. Login Form
User->>Okta: 4. Credentials
Okta->>Frontend: 5. Authorization Code
Frontend->>Okta: 6. Exchange Code
Okta->>Frontend: 7. JWT Tokens (id_token, access_token)
Note right of Frontend: Stores tokens in memory
end
%% Chat Request Flow
rect rgb(255, 248, 240)
Note over User,API: Chat Request Phase
User->>Frontend: 8. Send Message
Frontend->>Backend: 9. POST /api/agent/invoke
Note right of Frontend: Headers:<br/>Authorization: Bearer {access_token}<br/>X-ID-Token: {id_token}
Backend->>Runtime: 10. Invoke Agent
Note right of Backend: Headers:<br/>Authorization: Bearer {access_token}<br/>X-Amzn-Trace-Id: {trace_id}
Runtime->>Runtime: 11. Validate JWT (Okta JWKS)
Runtime->>Gateway: 12. MCP Tool Call
Note right of Runtime: Headers:<br/>Authorization: Bearer {access_token}
end
%% Gateway & Tool Execution
rect rgb(240, 255, 240)
Note over Gateway,API: Tool Execution Phase
Gateway->>Gateway: 13. Validate JWT (CUSTOM_JWT)
Gateway->>Interceptor: 14. REQUEST Interception
Note right of Gateway: Passes:<br/>Authorization header<br/>Request context
Interceptor->>Interceptor: 15. Extract user from JWT
Interceptor->>Gateway: 16. Return enriched context
Gateway->>API: 17. HTTP Request
Note right of Gateway: Headers:<br/>Authorization: Bearer {access_token}<br/>X-Amzn-Trace-Id: {trace_id}
API->>API: 18. Validate JWT
API->>API: 19. Get User Profile
API->>Gateway: 20. User Data Response
end
%% Response Flow
rect rgb(248, 240, 255)
Note over User,API: Response Phase
Gateway->>Runtime: 21. Tool Result
Runtime->>Runtime: 22. Agent Processes
Runtime->>Backend: 23. Agent Response
Backend->>Frontend: 24. JSON Response
Frontend->>User: 25. Display Message
end
Frontend → Backend
| Header | Value | Purpose |
Authorization | Bearer {access_token} | OAuth2 access token for API authorization |
X-ID-Token | {id_token} | OpenID Connect ID token with user claims |
Content-Type | application/json | Request body format |
Backend → AgentCore Runtime
| Header | Value | Purpose |
Authorization | Bearer {access_token} | Forwarded user token for federation |
X-Amzn-Trace-Id | Root=1-xxx;Parent=yyy | X-Ray distributed tracing |
Content-Type | application/json | Request body format |
AgentCore Gateway → Secured API
| Header | Value | Purpose |
Authorization | Bearer {access_token} | Federated user token (USER_FEDERATION) |
X-Amzn-Trace-Id | Root=1-xxx;Parent=yyy | Propagated trace context |
X-Gateway-Request-Id | {request_id} | Gateway request tracking |
JWT Token Flow
flowchart LR
subgraph Issuance["Token Issuance"]
Okta[Okta<br/>Issuer] --> Frontend[Frontend<br/>Stores] --> Backend[Backend<br/>Forwards]
end
subgraph Validation["Token Validation"]
Runtime[AgentCore Runtime<br/>Validates] --> Gateway[AgentCore Gateway<br/>Validates] --> API[Secured API<br/>Validates]
end
Backend --> Runtime
Key Points:
- JWT is validated at each boundary (Runtime, Gateway, API)
- Token is never modified, only forwarded
- USER_FEDERATION pattern ensures user context preserved
- Each service validates against Okta JWKS endpoint
Component Responsibilities
| Component | Auth Responsibility |
| Frontend | Obtain & store tokens from Okta |
| Backend | Forward tokens, no validation |
| Runtime | Validate JWT, pass to agent context |
| Gateway | Validate JWT (CUSTOM_JWT authorizer) |
| Interceptor | Extract user claims, enrich context |
| Secured API | Final JWT validation, return user data |
Traceability and Observability
Distributed Tracing
flowchart LR
subgraph Request["Request Flow with Trace Context"]
FE[Frontend] -->|X-Amzn-Trace-Id| BE[Backend]
BE -->|X-Amzn-Trace-Id| RT[AgentCore Runtime]
RT -->|X-Amzn-Trace-Id| GW[Gateway]
GW -->|X-Amzn-Trace-Id| API[Secured API]
end
subgraph Observability["AWS Observability"]
XRay[AWS X-Ray]
CW[CloudWatch Logs]
end
BE -.-> XRay
RT -.-> XRay
GW -.-> CW
API -.-> CW
| Component | Action | Header |
| Frontend | Generate trace ID | X-Amzn-Trace-Id: Root=1-xxx |
| Backend | Propagate trace | X-Amzn-Trace-Id: Root=1-xxx;Parent=yyy |
| AgentCore Runtime | Auto-instrumented (ADOT) | Propagates trace context |
| AgentCore Gateway | Log with trace | X-Gateway-Request-Id |
| Secured API | Log with trace | Correlates with trace ID |
Observability Stack
- AWS X-Ray: End-to-end request tracing
- CloudWatch Logs: Centralized logging with trace correlation
- ADOT: OpenTelemetry auto-instrumentation on AgentCore Runtime
Best Practices