Building a cloud application with a load balancer and authorization means routing traffic through a managed balancer (like AWS ALB) that offloads authentication to an identity provider before requests reach your backend. This pattern is the backbone of most production web apps on AWS, and getting the wiring right — listener rules, target groups, OIDC callbacks, health checks — is where most teams stumble.
This guide walks through a concrete, reproducible example: a containerized web app running on ECS Fargate, fronted by an Application Load Balancer (ALB), with authentication handled by Amazon Cognito using the ALB's native OIDC integration. We'll also cover the alternatives (API Gateway + Lambda, Network Load Balancer for TCP workloads, and self-managed auth) so you can decide what fits your situation, and point out where a diagram-generation tool (a "cloud application with load balancer and authorization maker") can save you hours of whiteboarding.
What "Load Balancer + Authorization" Actually Means in AWS
An Application Load Balancer with authorization is a Layer 7 load balancer that validates user identity via OIDC or Cognito before forwarding requests to your compute layer, rather than leaving auth entirely to application code. This shifts a chunk of security logic out of your app and into managed infrastructure, which reduces code but adds a dependency on ALB's auth-action configuration.
Concretely, three AWS building blocks combine to deliver this:
- Application Load Balancer (ALB) — Layer 7, listens on ports 443/80, routes by host/path, supports
authenticate-cognitoandauthenticate-oidclistener actions. - Identity provider — Amazon Cognito User Pools (managed) or any external OIDC provider (Okta, Auth0, Azure AD / Entra ID, Google Workspace).
- Compute target — ECS/Fargate tasks, EC2 instances, or Lambda functions (via ALB target type
lambda), registered in a target group that the ALB health-checks and routes to.
The ALB itself doesn't store user data. It redirects unauthenticated users to the identity provider's hosted login page, receives the OIDC authorization code, exchanges it for tokens, and passes an encoded x-amzn-oidc-data JWT header downstream. Your application still needs to validate that header (or trust the ALB, which is common but worth an explicit security decision) — it does not need to build a login page.
Step 1: Define the Architecture Before You Touch the Console
A clear architecture sketch prevents half the misconfigurations people hit with ALB auth. At minimum you need: a VPC with public and private subnets across at least two Availability Zones, an internet-facing ALB in the public subnets, an internal target (ECS service or EC2 Auto Scaling group) in private subnets, a NAT gateway for egress, and Cognito or an external OIDC provider.
Here's the reference topology used throughout this example:
Internet
|
Route 53 (app.example.com)
|
ALB (public subnets, 2 AZs) --- listener :443 (ACM cert)
| authenticate-cognito action
|
Target Group (HTTP :8080) --> ECS Fargate tasks (private subnets)
|
Cognito User Pool + Hosted UI (OIDC)
If you're documenting this for a team or a client, this is exactly the kind of diagram that a cloud application with load balancer and authorization example should include before any Terraform or CDK is written — reviewers catch missing NAT gateways and open security groups far faster on a diagram than in 200 lines of YAML. Tools like draft1.ai exist specifically to generate this diagram-plus-documentation pair from a plain-English prompt, which is useful when you need a reviewable artifact quickly rather than starting from a blank canvas.
Step 2: Provision Networking and Certificates
You need a VPC, subnets, an ACM certificate, and Route 53 records before the load balancer can do anything useful. Skipping TLS is not an option here — Cognito and most OIDC providers refuse plaintext redirect URIs for production apps.
Minimum checklist:
- VPC with CIDR (e.g.,
10.0.0.0/16), two public subnets (10.0.0.0/24,10.0.1.0/24), two private subnets (10.0.10.0/24,10.0.11.0/24). - Internet Gateway attached to the VPC; NAT Gateway in one public subnet for private-subnet egress.
- ACM certificate for
app.example.com, validated via DNS in Route 53. - Security groups: ALB SG allows inbound 443 from
0.0.0.0/0; target SG allows inbound 8080 (or your app port) only from the ALB SG.
This is also the point to decide whether you want an internet-facing or internal ALB. Internal ALBs (no public IPs, resolved only inside the VPC or via VPN/Direct Connect) are common for internal admin tools that still need SSO.
Step 3: [[Create](https://www.draft1.ai/blog/how-to-create-an-entity-relationship-diagram-step-by-step-guide)](https://www.draft1.ai/blog/how-to-create-a-pharmacy-website-data-flow-diagram-step-by-step-guide) the Cognito User Pool and App Client
Amazon Cognito gives you a hosted login UI and OIDC-compliant token issuance without writing a single line of authentication code. Configure it correctly on the first pass because changing the callback URL later requires touching both Cognito and the ALB listener rule.
Key settings:
- User Pool: enable email as a sign-in alias, set password policy, optionally enable MFA (SMS or TOTP).
- App client: generate a client secret (ALB integration requires a confidential client, unlike SPA flows which typically use public clients).
- Hosted UI domain: either a Cognito-provided domain (
your-app.auth.us-east-1.amazoncognito.com) or a custom domain mapped via ACM. - Callback URL:
https://app.example.com/oauth2/idpresponse— this exact path is required by the ALB, not configurable. - Allowed OAuth flows: Authorization code grant, scopes
openid,email,profile.
Step 4: Configure the ALB with an Authentication Action
The ALB listener rule is where authorization actually gets enforced. You attach an authenticate-cognito (or authenticate-oidc for third-party providers) action ahead of the forward action on your HTTPS listener.
In Terraform, the relevant piece looks like this:
resource "aws_lb_listener_rule" "auth_rule" {
listener_arn = aws_lb_listener.https.arn
priority = 10
action {
type = "authenticate-cognito"
authenticate_cognito {
user_pool_arn = aws_cognito_user_pool.pool.arn
user_pool_client_id = aws_cognito_user_pool_client.client.id
user_pool_domain = aws_cognito_user_pool_domain.domain.domain
session_cookie_name = "AWSELBAuthSessionCookie"
session_timeout = 3600
on_unauthenticated_request = "authenticate"
}
}
action {
type = "forward"
target_group_arn = aws_lb_target_group.app.arn
}
condition {
path_pattern {
values = ["/*"]
}
}
}
Two settings deserve attention:
on_unauthenticated_request— set toauthenticateto force login, orallowif you want mixed public/private paths (common for a marketing page plus an authenticated app section, handled via separate listener rules with differentpath_patternconditions).session_timeout— controls how long the ALB session cookie is valid before re-authentication; this is independent of the Cognito token expiry, and mismatches between the two are a frequent source of confusing "randomly logged out" bug reports.
Step 5: Deploy the Application Behind a Target Group
Register your compute — ECS Fargate tasks in this example — as ALB targets, and make sure health checks match your actual app behavior. A common failure mode: the health check path returns a 302 redirect to Cognito's login page because the ALB's auth action applies to all paths, including the health check path, causing the target group to report every task as unhealthy.
Fix this by excluding the health-check path from the auth rule:
condition {
path_pattern {
values = ["/health"]
}
}
action {
type = "forward"
target_group_arn = aws_lb_target_group.app.arn
}
Give this rule a lower priority number (evaluated first) than the general authenticated rule so /health bypasses Cognito entirely, while everything else still requires login.
Target group settings for an ECS Fargate service:
- Target type:
ip(required for Fargate'sawsvpcnetworking mode). - Protocol/port: HTTP:8080 (internal traffic between ALB and tasks; TLS termination happens at the ALB).
- Health check path:
/health, healthy threshold 2, interval 15s, timeout 5s. - Deregistration delay: 30s (lower than the 300s default speeds up deployments but risks dropping in-flight requests during scale-in).
Load Balancer Type Comparison
Not every workload needs an ALB with OIDC. Here's how the main AWS options compare for this pattern:
| Load Balancer | Layer | Native Auth Support | Best For |
|---|---|---|---|
| Application LB (ALB) | L7 (HTTP/HTTPS) | Cognito + OIDC actions | Web apps, REST APIs, host/path routing |
| Network LB (NLB) | L4 (TCP/UDP/TLS) | None (pass-through) | High-throughput, low-latency, gRPC, static IPs |
| Gateway LB (GWLB) | L3/L4 | None | Third-party firewalls, traffic inspection |
| API Gateway + Lambda | L7 (managed) | Cognito, IAM, Lambda authorizers | Serverless APIs, per-method authorization |
If your workload is TCP-based (databases, custom binary protocols, gRPC without an HTTP/2-aware proxy in front), an NLB is the right tool, but you'll need to implement authorization in the application layer since NLB doesn't inspect payloads. For serverless-first teams, API Gateway with a Cognito authorizer or Lambda authorizer is often simpler than standing up an ALB, at the cost of some flexibility in routing rules and slightly different latency characteristics (API Gateway adds a small fixed overhead per request, generally low single-digit milliseconds, though actual figures vary by region and payload).
Step 6: Validate Tokens in Your Application
The ALB forwards two headers after successful authentication: x-amzn-oidc-data (a signed JWT with user claims) and x-amzn-oidc-accesstoken. Your application should still validate the signature rather than blindly trusting the header, because in a misconfigured security group a client could theoretically reach the target directly if the target group is exposed elsewhere.
A minimal validation flow:
- Fetch the ALB's public key from the regional endpoint
https://public-keys.auth.elb.<region>.amazonaws.com/<kid>(thekidcomes from the JWT header). - Verify the JWT signature using ES256.
- Check
exp,iss, and audience claims. - Extract
email,sub, and any custom claims for your application's session.
AWS's own guidance (AWS documentation on ALB authentication, 2023) explicitly recommends this signature check for zero-trust setups rather than relying on network isolation alone.
Common Mistakes and How to Avoid Them
Most production incidents in this pattern trace back to a handful of repeatable errors:
- Wrong callback URL — Cognito requires an exact match (path, scheme, trailing slash) or it silently rejects the redirect. Copy it verbatim from the ALB console's OIDC callback field.
- Health check path caught by auth rule — as covered in Step 5; always carve out an unauthenticated health-check exception.
- Session timeout shorter than token expiry (or vice versa) — leads to confusing partial-logout states; align both intentionally.
- Missing
HTTPSlistener — Cognito refuses non-TLS redirect URIs for anything beyondlocalhosttesting. - Target group protocol mismatch — forwarding HTTPS to a target listening only on HTTP (or vice versa) causes 502s that look like app bugs.
- No least-privilege security group on targets — the target's security group should allow inbound only from the ALB security group, not
0.0.0.0/0, even though the ALB is already public-facing.
Using a Diagramming Tool to Prototype Faster
Sketching the architecture — VPC, subnets, ALB, Cognito, target group, ECS service — before writing Terraform catches structural mistakes cheaply. A cloud application with load balancer and authorization maker that accepts a plain-English prompt ("ECS Fargate app behind an ALB with Cognito auth, private subnets, NAT gateway") and produces both a diagram and accompanying documentation can shortcut the design-review loop, especially for teams that need to hand a reviewable artifact to a security or platform team before infrastructure gets provisioned. This isn't a replacement for infrastructure-as-code, but it front-loads the architectural conversation — VPC boundaries, which subnets are public vs. private, where TLS terminates — before anyone commits code.
Key Takeaways
- An ALB with
authenticate-cognitoorauthenticate-oidclistener actions offloads login redirects and token exchange to managed infrastructure, but your app should still validate the forwarded JWT rather than trusting it implicitly. - The callback URL
/oauth2/idpresponseis fixed by the ALB and must match exactly in your Cognito or OIDC provider configuration. - Always create a separate, unauthenticated listener rule for health-check paths — the auth action applies to every path by default, which breaks target group health checks.
- Choose NLB for raw TCP/UDP performance without payload-level auth, ALB for HTTP(S) apps needing host/path routing plus OIDC, and API Gateway for serverless APIs with per-method Cognito or Lambda authorizers.
- Align ALB
session_timeoutwith your identity provider's token expiry to avoid inconsistent logout behavior. - Diagramming the VPC, subnet, and auth flow before writing IaC — manually or with a generator tool — catches missing NAT gateways, open security groups, and routing gaps early.
- Security groups should restrict target traffic to the ALB's security group only, even behind a public-facing load balancer.
Frequently Asked Questions
What is the simplest way to add authorization to a load-balanced AWS app?
The simplest approach is attaching an authenticate-cognito action to your ALB's HTTPS listener rule, pointing at an Amazon Cognito User Pool with hosted UI enabled. This requires no custom login code — Cognito handles the sign-in page, and the ALB handles the OIDC handshake and session cookie.
Does the ALB store user passwords or credentials?
No, the ALB never stores credentials; it only orchestrates the OIDC redirect and validates tokens issued by Cognito or your external identity provider. Passwords and user records live in the identity provider (Cognito User Pool, Okta, Azure AD, etc.), not in the load balancer.
Can I use a Network Load Balancer instead of an Application Load Balancer for authorization?
Not for the built-in ALB authentication actions — NLB operates at Layer 4 and has no concept of HTTP, cookies, or OIDC redirects. If you need NLB (for raw TCP performance or static IPs), you must implement authorization inside your application or via a sidecar proxy instead.
How do I stop health checks from getting redirected to the login page?
Add a listener rule with higher priority (lower priority number) than your auth rule that matches your health-check path (e.g., /health) and forwards directly to the target group without an authenticate-cognito action. Without this exception, the ALB's default 302 redirect to the identity provider causes every health check to fail.
Is API Gateway a better choice than ALB for authorization?
It depends on your architecture: API Gateway with Cognito or Lambda authorizers suits serverless, per-endpoint authorization models, while ALB suits container- or EC2-based apps needing host/path-based routing with session-cookie-based auth. Both are valid; teams already running Lambda-heavy stacks often prefer API Gateway, while container-based teams generally default to ALB.
What happens if the ALB session cookie expires but the Cognito token hasn't?
The ALB will re-initiate the OIDC flow and redirect the user to Cognito, which may issue a new session silently (if the Cognito/IdP session is still valid) without requiring the user to re-enter credentials. This is why aligning session_timeout on the ALB with your Cognito token expiry settings matters — mismatches create inconsistent "randomly logged out" experiences.
Can I test this setup locally before deploying to AWS?
Not the ALB auth action itself — it's a managed AWS feature with no local emulator — but you can test your application's JWT validation logic locally using a sample signed token and mocked public keys. For end-to-end testing, deploy to a low-cost staging environment (a single Fargate task, minimal NAT usage) rather than trying to fully replicate ALB behavior offline.
Draw this in seconds with draft1. Describe your architecture in plain English and draft1 generates an editable AWS/cloud diagram plus documentation — no dragging boxes around. Try it free.
Draw this in ~20 seconds
Describe your own version of this architecture and draft1 generates an editable draw.io diagram — boxes, arrows, labels, the lot.
Generate this diagram free ➔Free demo — no signup. Then 3 free diagrams with an account, no card.