DEV Community

Cover image for Understanding AWS Cognito: How User Authentication Works Without Storing Passwords Yourself
Micheal Angelo
Micheal Angelo

Posted on

Understanding AWS Cognito: How User Authentication Works Without Storing Passwords Yourself

Authentication is one of the first challenges developers encounter when building an application.

Initially, it seems straightforward: ask users for an email and password, verify the credentials, and allow access.

However, implementing authentication securely is much more involved than it first appears.

Questions quickly begin to arise:

  • Where should passwords be stored?
  • How should passwords be hashed?
  • How are password resets implemented?
  • How should Multi-Factor Authentication (MFA) be handled?
  • How are secure authentication tokens generated?
  • How can those tokens be trusted by the backend?

These responsibilities are exactly what AWS Cognito is designed to solve.

Rather than being just a JWT generator, Cognito is a fully managed identity and authentication service that handles the entire authentication lifecycle.


Why Use AWS Cognito?

Imagine building authentication entirely from scratch.

The authentication flow might look like this:

User
   │
Email + Password
   │
   ▼
Backend
   │
Query Database
   │
Retrieve Password Hash
   │
Compare Password
   │
Generate JWT
   │
Return Access Token
Enter fullscreen mode Exit fullscreen mode

In this design, the backend becomes responsible for:

  • Storing passwords
  • Hashing passwords
  • Verifying credentials
  • Password resets
  • Email verification
  • Multi-factor authentication
  • Refresh tokens
  • JWT generation
  • JWT validation

Handling all of these securely is a significant engineering responsibility.

AWS Cognito removes much of this complexity by managing authentication on your behalf.


The User Pool

One of the central concepts in Cognito is the User Pool.

A User Pool is a managed identity database maintained by AWS.

It stores authentication-related information such as:

  • Email address
  • Username
  • Password hash
  • Phone number
  • Email verification status
  • MFA settings
  • User status
  • A unique identifier (sub)

Conceptually:

User Pool

---------------------------------------
Email                 Password Hash
---------------------------------------
alice@example.com     *************
bob@example.com       *************
john@example.com      *************
---------------------------------------
Enter fullscreen mode Exit fullscreen mode

An important detail is that developers never have access to users' passwords or password hashes.

Those are managed entirely by Cognito.


Where Does the User Pool Live?

One question that initially confused me was where the User Pool actually exists.

It is not stored in:

  • Amazon RDS
  • DynamoDB
  • An EC2 instance
  • Your application's VPC

Instead, it exists inside AWS's managed Cognito service.

This separation is intentional because authentication is infrastructure managed by AWS rather than application-specific data.


Why Isn't Cognito Inside the VPC?

Many AWS resources live inside a Virtual Private Cloud (VPC), including:

  • EC2
  • RDS
  • ECS
  • Lambda (when configured for VPC access)

Cognito works differently.

Like IAM or Route 53, Cognito is an AWS-managed service that is accessed securely over HTTPS through AWS service endpoints.

Your application communicates with Cognito—it does not host Cognito.


How Authentication Works

When a user signs in, the flow is surprisingly simple.

User
 │
 │ Email + Password
 ▼
AWS Cognito
 │
 ▼
User Pool
 │
 ▼
Verify Credentials
 │
 ▼
Generate Tokens
 │
 ▼
Browser
Enter fullscreen mode Exit fullscreen mode

Notice what does not happen.

The backend never:

  • Receives the user's password
  • Compares password hashes
  • Generates authentication tokens

Cognito performs all of those responsibilities.


Signing Up

During registration, the process is similar.

User
 │
 │ Email
 │ Password
 ▼
AWS Cognito
 │
 ▼
User Pool
Enter fullscreen mode Exit fullscreen mode

Cognito automatically:

  • Validates password policies
  • Stores passwords securely
  • Sends verification emails (if configured)
  • Creates the user identity
  • Assigns a unique identifier

Applications no longer need to implement these features manually.


Understanding the Tokens

After successful authentication, Cognito returns three JWTs.

ID Token

The ID Token identifies the authenticated user.

It commonly contains information such as:

  • User ID (sub)
  • Email
  • Username

Its purpose is identity.


Access Token

The Access Token is presented when calling protected APIs.

For example:

Authorization: Bearer <Access Token>
Enter fullscreen mode Exit fullscreen mode

The backend validates this token before allowing access.


Refresh Token

Access Tokens eventually expire.

Instead of asking users to log in again, the Refresh Token can be exchanged for a new Access Token until it too expires.

This allows users to remain signed in without repeatedly entering credentials.


How Does the Backend Trust Cognito?

Every protected request includes the Access Token.

Browser

Authorization: Bearer eyJhbGci...
Enter fullscreen mode Exit fullscreen mode

Rather than checking passwords, the backend validates the JWT.

Typical checks include:

  • Signature verification
  • Issuer validation
  • Audience validation
  • Expiration time

If the token is valid, access is granted.

Otherwise, the request is rejected with a 401 Unauthorized response.

The backend trusts the identity because the token was signed by Cognito.


Authentication Data vs Application Data

One important architectural lesson is that authentication data and business data should remain separate.

Cognito manages identity information such as:

  • Email
  • Password
  • MFA
  • Verification status

Meanwhile, application databases store business information such as:

  • Orders
  • Addresses
  • User preferences
  • Shopping carts
  • Subscription details

Applications typically store the Cognito user identifier (sub) to associate business records with authenticated users.

Conceptually:

Authentication
      │
      ▼
 AWS Cognito

Business Data
      │
      ▼
RDS / DynamoDB
Enter fullscreen mode Exit fullscreen mode

Keeping these responsibilities separate improves both security and maintainability.


What If the Application Server Is Compromised?

A question that naturally came to mind was:

What happens if someone gains access to the EC2 instance?

An attacker might obtain:

  • Application source code
  • Environment variables
  • Business database access (depending on IAM permissions)
  • Access to other AWS services (depending on IAM policies)

However, they still cannot retrieve users' passwords from Cognito.

That's because:

  • Passwords are never stored on the EC2 instance.
  • Password hashes are never stored in the application database.
  • Cognito does not expose password hashes through its APIs.

Separating authentication from application infrastructure significantly reduces the impact of a server compromise.


Can AWS Administrators See Passwords?

Another common misconception is that AWS administrators can retrieve user passwords.

They cannot.

Administrators can perform management operations such as:

  • Creating users
  • Disabling users
  • Resetting passwords
  • Viewing permitted user attributes

But neither plaintext passwords nor password hashes are exposed.

Those remain protected inside Cognito.


Why Use Cognito?

Beyond simplifying development, Cognito also provides several security advantages.

It offers:

  • Secure password storage
  • Built-in password policies
  • Multi-Factor Authentication (MFA)
  • Email verification
  • Secure JWT generation
  • Refresh token management
  • Reduced attack surface
  • Standards-based authentication

Rather than building these capabilities from scratch, applications can rely on a managed service designed specifically for identity management.


Final Thoughts

Before learning AWS Cognito, I viewed authentication mainly as checking usernames and passwords.

Working through Cognito changed that perspective.

Authentication is much more than credential verification—it involves securely managing identities, issuing trusted tokens, protecting user credentials, and separating authentication concerns from application logic.

Perhaps the biggest takeaway was realizing that good authentication systems don't simply authenticate users.

They minimize how much sensitive information an application is responsible for handling in the first place.

That separation is one of the strongest security advantages of using a managed identity service like AWS Cognito.

Top comments (0)