Cognito user authentication on ALB vs API Gateway
By: Porsche Digital
Tags: Tech, DevOps, Software Development, Aws Cognito, Authentication

Authentication is one of the most complicated topics for developers. It is needed to implement many features, from forgot password to SMS verification or Two-Factor-Authentification (2FA). However, with the latest technologies and services, a secure authentication system is simpler to implement than ever before. AWS Cognito is an authentication as a service just like Auth0 or others —but its main advantage is its integration with other AWS services.

Authentication is one of the most complicated topics for developers. Photo by Markus Spiske on Unsplash

In this article, I will introduce two different services that AWS Cognito can integrate: Application Load Balancer (ALB) and API Gateway. For both methods, we first need to create a Cognito User Pool. As there are many resources for Cognito and User Pool creation, this article assumes a good familiarity with Cognito and focuses on integration with other services.

Both the methods and implementation will be discussed, showing step by step instructions and representations in Terraform.

ALB and API Gateway

An Application Load Balancer distributes the incoming request to targets and instances. The load balancer uses listeners to execute specific actions.

API Gateway is a management tool that stands between a client and backend services to intercept all incoming requests and send them with different functions. API Gateway is not enough to connect directly to containers — because of this, we used Network load balancer and Vpclink to connect to the container instance.

Authentication at Infrastructure

“Authentication at Infrastructure” is a term we can use for the setup which combines an identity provider like AWS Cognito and ALB or API Gateway. Because the authentication/authorization process is being handled at the infrastructure step with proven components, our software becomes simpler, easier to maintain and less error-prone.

Implementing authentication at infrastructure also gives the opportunity to implement authentication in IaC systems like CloudFormation or Terraform, which makes it a pluggable component. Whether if it’s implementing a new monolith with a completely different domain, or another microservice that we will attach to our fleet, the authentication service development can be mostly skipped in the application layer (with some exceptions) and implemented completely on IaC. This pluggable component also enables us to share user pools among different services/domains/monoliths.

Of course, using AWS Cognito as an authentication layer also has more advantages like but not limited to

Not having to re-invent the wheel: from sign-up forms to forgot password flows, batteries included

Very adaptive, customizable login/authentication system

AI-based fraud detection

SMS-based login

easy integration with other OAUTH providers, Google login, Facebook login, etc

and many more…

Implementing AWS Cognito at the infrastructure layer takes away lots of developers/hours spent on mundane and repeating tasks and makes it very easy to implement with a few lines of IaC.

Cognito implementation at ALB

Authentication flow follows a generic OAUTH flow, a token generated by AWS Cognito is via a redirect, and this token is exchanged for a Session Cookie as the last step. After this process is completed, on subsequent requests, ALB will verify the information in the cookie and transform it into the user’s information written into X-Amzn-Oidc-* headers. The application then can use said headers to operate on a logged-in user account.

ALB provides authentication through social Identity Providers (IdP) like Google, Facebook login to allow the user sign-in.

Cognito implementation at ALB

How to authenticate in ALB with Terraform

resource "aws_cognito_user_pool" "user_pool" { name = var.pool_name ... } resource "aws_cognito_user_pool_client" "client" { name = var.client_name user_pool_id = aws_cognito_user_pool.user_pool.id } resource "aws_cognito_user_pool_domain" "domain" { domain = var.domain user_pool_id = aws_cognito_user_pool.user_pool.id } resource "aws_alb_listener" "listener" { ... default_action{ type = "authenticate-cognito" authenticate_cognito { user_pool_arn = aws_cognito_user_pool.user_pool.arn user_pool_client_id = aws_cognito_user_pool_client.client.id user_pool_domain = aws_cognito_user_pool_domain.domain.domain } } ... }

How to authenticate in ALB with manual steps

Open EC2 page on AWS and Click Load Balancers.

Choose the load balancer you want to authenticate.

Click the Listeners tab and Click Add listener button.

tab and Click button. Choose HTTPS under Protocol:port and be sure port is set to 443.

under and be sure port is set to Click Add action and choose Forward to…

and choose Choose the Target group you created and click the ✓ (tick) symbol.

you created and click the (tick) symbol. Choose Default SSL certificate on the drop down list.

on the drop down list. Click Save button.

button. Come back to Listeners and click View/edit rules.

and click Click + tab and + Insert Rule.

tab and Click Add Condition and c hoose Path… .

hoose . Enter the value and click the ✓ (tick) symbol.

(tick) symbol. Click Add action and choose Authenticate… .

and choose . Choose Cognito user pool on the dropdown list or Create new.

on the dropdown list or Choose your client on the drop down list under App client.

Click the ✓ (tick) symbol.

(tick) symbol. Click Add action and choose Forward to…

and choose Choose the Target group you created and click the ✓ (tick) symbol.

you created and click the (tick) symbol. Click Save button.

Cognito implementation at API Gateway

API Gateway is another service that can work with AWS Cognito. While the purpose of API Gateway and ALB seems similar(routing requests to defined targets), API Gateway is a serverless service while ALB is not. According to my experience, Cognito integration with API Gateway is designed differently than ALB integration. Modern web applications can utilize API Gateways’s integration easily, especially with the combination of AWS Amplify SDK, the entire setup is really straightforward and powerful. It is also self-contained. There is no need to keep tokens on the backend. The token keeps all the data itself.

The setup is made by adding Cognito as an authorizer to a path. This makes incoming requests verified before getting sent to the application layer. AWS Gateway checks the incoming token, verifies it and if the token is valid, the requests are routed to targets.

Cognito implementation at API Gateway

How to authenticate in API Gateway with Terraform

variable "cognito_user_pool_name" {} data "aws_cognito_user_pools" "user_pools" { name = var.cognito_user_pool_name } resource "aws_api_gateway_rest_api" "rest_api" { name = var.api_name ... } resource "aws_api_gateway_resource" "resource" { rest_api_id = aws_api_gateway_rest_api.rest_api.id parent_id = aws_api_gateway_rest_api.rest_api.root_resource_id path_part = "{proxy+}" } resource "aws_api_gateway_authorizer" "authorizer" { name = "Cognito-Authorizer" type = "COGNITO_USER_POOLS" rest_api_id = aws_api_gateway_rest_api.rest_api.id provider_arns = data.aws_cognito_user_pools.user_pools.arns } resource "aws_api_gateway_method" "any" { rest_api_id = aws_api_gateway_rest_api.rest_api.id resource_id = aws_api_gateway_resource.resource.id http_method = "ANY" authorization = "COGNITO_USER_POOLS" authorizer_id = aws_api_gateway_authorizer.authorizer.id request_parameters = { "method.request.path.proxy" = true } }

How to authenticate in API Gateway with manual steps

Open API Gateway console.

console. Choose your API to work on.

Choose Authorizers .

. Chose Create New Authorizer .

. Write a Name for the Authorizer.

for the Authorizer. Select type as Cognito .

. Choose your Cognito User Pool under drop down list.

under drop down list. Enter Authorization for Token Source.

for Token Source. Leave Token validation blank and choose Create .

blank and choose . Choose Resources on the main list under API .

on the main list under . Choose the method you want to authenticate.

Click Method Execution .

. Choose authorizer with as Authorization under Settings.

How to choose between API Gateway and ALB?

Instead of talking about the advantages and disadvantages of both integrations, let’s talk about when to use what.

API Gateway is a serverless component, it has also many extra features compared to ALB. If starting a new project where a web application or mobile application needs authentication, then API Gateway is the better choice for most. If we have a dockerized application that’s just server-side rendered which we need to globally put behind an authentication mechanism, then ALB is the easy winner.

Summary

In this article, we compared authentication on ALB and API Gateway. Both tools have different roles in a complicated application landscape. Both implementations have similar features, but API Gateway gives us more flexibility in the implementation style. API Gateway is also incredibly powerful in serverless setup. For sustained heavy loads (IoT sensor data, streaming, etc), ALB has good uses. Being able to use both components in our projects with the same user pool is a really nice way of integrating domain-specific services.

For further reading about cookie-based (ALB) and token-based (API Gateway) authentication, I can recommend this guide: Cookies vs. Tokens: The Definitive Guide — DZone Integration

References:

https://aws.amazon.com/blogs/aws/built-in-authentication-in-alb/

https://docs.aws.amazon.com/cognito/latest/developerguide/cognito-scenarios.html#scenario-api-gateway