[What to know]Introduction

Authentication is the backbone of any modern application. Many developers start with Firebase Authentication because it’s simple, quick to set up, and beginner-friendly. But as applications grow, requirements often outpace Firebase’s capabilities — cost, scalability, flexibility, and integration with enterprise systems become pain points.

That’s where Amazon Cognito comes in — offering serverless, highly scalable, and secure identity management designed for production-grade apps.

This post will cover:

  1. A comparison of Firebase Auth vs. Cognito
  2. Why teams migrate to Cognito
  3. Pricing differences
  4. Feature differences
  5. A high-level migration approach

[Side by Side]Firebase Authentication vs Amazon Cognito

FeatureFirebase AuthenticationAmazon Cognito
Ease of SetupVery quick, minimal config, great for MVPsSetup requires more steps (User Pools, Identity Pools), but more control
Identity ProvidersEmail/Password, Social (Google, Apple, FB), PhoneSame + SAML, OIDC, Active Directory, enterprise SSO
ScalabilityScales well but better suited for mobile/web appsBuilt for large-scale enterprise workloads (millions of users)
Custom LogicLimited custom flows, extensions via Cloud FunctionsLambda triggers allow full customization (signup, login, token issuance)
Multi-Tenant AppsNot natively supportedFlexible with custom attributes, groups, roles
SecurityGood, but mostly Google Cloud centricDeep integration with AWS IAM, security compliance (HIPAA, GDPR, FedRAMP)
Data LocationManaged by Google, less region choiceFull region selection in AWS
AnalyticsStrong integration with Firebase/Google AnalyticsIntegrated with AWS CloudWatch & third-party tools
Vendor Lock-InTight Google ecosystem tieWorks across AWS + external systems
Amazon Cognito VS Firebase

[Cost]Pricing Difference

  • Firebase Authentication

    • Free tier: 50K monthly active users (MAU) for email/password.

    • After that: ~$0.01–0.06 per MAU (varies by provider).

    • Phone auth can get expensive quickly (per-SMS charges).

  • Amazon Cognito

    • Free tier: 50K monthly active users per month for user pools.

    • After that: $0.0055 per MAU (generally cheaper at scale).

    • Federation and advanced security features add cost, but still competitive.

Bottom line: For small apps, both are affordable. At enterprise scale, Cognito is usually cheaper than Firebase Auth, especially when federating enterprise identities.

[Migrating]Why Migrate from Firebase to Cognito?

  • Need for enterprise identity support (SAML, OIDC, Active Directory).

  • More fine-grained security policies (IAM integration, region control).

  • Compliance requirements (HIPAA, GDPR, FedRAMP).

  • Avoiding vendor lock-in with Google.

  • Better cost predictability at scale.

  • Customizable flows with Lambda triggers.

[Plan]High-Level Migration Path

  • Plan

    • List current providers (Google, Apple, Email, etc.) in Firebase.

    • Export Firebase user data (UID, email, phone, tokens if possible).

  • Set Up Cognito

    • Create a User Pool (for sign-up/sign-in).

    • (Optional) Create an Identity Pool for temporary AWS credentials.

    • Configure social providers and federation as needed.

  • Migrate Users

    • Bulk import users via CSV into Cognito.

    • Handle passwords:

      • Either force password reset (simplest, most secure).

      • Or implement a “progressive migration” flow — validate old Firebase tokens during first login, then move to Cognito.

  • Update Frontend

    • Replace Firebase SDK calls with Cognito SDK / AWS Amplify (or directly Cognito APIs if avoiding Amplify).

    • Update sign-in/sign-up flows.

  • Test & Rollout

    • Run both systems in parallel during migration phase.

    • Gradually switch over traffic to Cognito.

[code block]Start Coding

STEP 1 : Plan

  1. List providers you use in Firebase (Google, Apple, Email, Phone).
  2. Export Firebase users (via Admin SDK or Firebase console).
  3. Decide: Will you migrate passwords or force resets

 

STEP 2 : Set Up Cognito

1. Create a User Pool (for sign-up/sign-in).

aws cognito-idp create-user-pool --pool-name MyAppUserPool

2. Create an Identity Pool for temporary AWS credentials.

aws cognito-idp create-user-pool-client \
  --user-pool-id <your-pool-id> \
  --client-name MyAppClient \
  --no-generate-secret

Enable federated providers (Google, Apple, etc.) if needed.

Amazon console

Below is the overview of Cognito User Pool configuration. The most critical values for your app are the User Pool ID, App Client ID (from App clients menu), and the JWKS URL (for token validation).Find below image is from the Amazon Cognito console, specifically the User Pool for a pool named AuthAppUserPool

Left Sidebar

  • Current user pool: Dropdown shows which User Pool you’re managing (AuthAppUserPool).
  • Applications: Section to configure App clients (like your web app, mobile app).
  • User management: Manage Users and Groups inside this pool.
  • Authentication: Configure authentication methods (MFA, password policies, federated identity providers).

Main Panel (User Pool Information)

  1. User pool name: AuthAppUserPool — the name you gave this pool.
  2. User pool ID: A unique identifier. You’ll use this in your backend/frontend config.
  3. ARN (Amazon Resource Name): Globally unique identifier for this user pool. Helpful for IAM policies and automation.
  4. Token signing key URL: URL that exposes the JSON Web Key Set (JWKS). Your backend fetches this to validate JWT tokens issued by Cognito.
  5. Estimated number of users: Shows how many users are currently registered (here it’s 0).
  6. Feature plan: Shows whether the pool is on the Essentials or Premium feature tier. 
  7. Created time / Last updated time: Timestamp of when the pool was created/last modified 

 Step 3: Migrate Users

Bulk Import (This is to forces password reset)

  • Export Firebase users to CSV.
  • Import into Cognito using AWS CLI.

 Step 4: Update frontend (React, React Native, Angular, Vue, etc.)

Key Responsibilities:

  • Handle user sign-up, login, logout
  • Manage tokens (ID token, Access token, Refresh token)
  • Redirect authenticated users to dashboard
  • Call backend APIs with a valid JWT in headers

Flow:

  1. User signs in using embedded Cognito SDK. (Not Hosted UI)
  2. Cognito returns JWT tokens.
  3. Tokens are stored in browser local storage/session storage (secure, httpOnly cookies recommended).
  4. Every API request → sends Authorization: Bearer <JWT> header to backend.

Frontend Stack Example:

  • React App with amazon-cognito-identity-js SDK
  • React Router for redirecting users after login
  • Optional Amplify UI Components for faster integration (But I am not using amplify here. This is without amplify)
import {
  CognitoUserPool,
  CognitoUser,
  AuthenticationDetails
} from 'amazon-cognito-identity-js';

const poolData = {
  UserPoolId: 'us-east-1_XXXXXX', // from AWS console
  ClientId: 'XXXXXXXX'           // app client id
};
const userPool = new CognitoUserPool(poolData);

function login(username, password) {
  const authDetails = new AuthenticationDetails({
    Username: username,
    Password: password
  });

  const user = new CognitoUser({
    Username: username,
    Pool: userPool
  });

  user.authenticateUser(authDetails, {
    onSuccess: (session) => {
      console.log('Login success, JWT:', session.getIdToken().getJwtToken());
      // redirect to dashboard
      window.location.href = "/dashboard";
    },
    onFailure: (err) => {
      console.error('Login failed:', err);
    }
  });
}

 Step 5: Backend (Node.js, Python, Java, etc.)

Key Responsibilities:

  • Validate Cognito JWT tokens
  • Enforce authorization rules via claims (roles, groups)
  • Provide protected APIs (user profile, app data, etc.)

Flow:

  1. Receives requests from frontend with JWT in headers.
  2. Verifies JWT against Cognito’s public JWK endpoint.
  3. Authorizes access based on claims (e.g., role = admin).
  4. Processes request and returns response.

Backend Stack Example:

  • REST API built with Express.js (Node.js)
  • Token verification middleware using Cognito JWKS
  • Role-based access control (RBAC) with Cognito Groups
  • Optional API Gateway + Lambda (for fully serverless apps)
import jwt from 'jsonwebtoken';
import jwkToPem from 'jwk-to-pem';
import axios from 'axios';

const poolRegion = "us-east-1";
const userPoolId = "us-east-1_XXXXXX";

let pems;

async function init() {
  const url = `https://cognito-idp.${poolRegion}.amazonaws.com/${userPoolId}/.well-known/jwks.json`;
  const response = await axios.get(url);
  pems = {};
  response.data.keys.forEach(key => {
    const pem = jwkToPem(key);
    pems[key.kid] = pem;
  });
}

export async function verifyToken(req, res, next) {
  const token = req.headers['authorization']?.split(" ")[1];
  if (!token) return res.status(401).send("Unauthorized");

  const decoded = jwt.decode(token, { complete: true });
  if (!decoded || !pems[decoded.header.kid]) {
    return res.status(401).send("Invalid token");
  }

  jwt.verify(token, pems[decoded.header.kid], (err, payload) => {
    if (err) return res.status(401).send("Unauthorized");
    req.user = payload;
    next();
  });
}

init();

Below image shows the list of all users in your Cognito User Pool, their email verification, confirmation status, and whether their accounts are enabled.

Header

  • Users (33) → There are 33 users in this Cognito User Pool.
  • You can view, edit, or create users here.
  • Top-right buttons: Delete user to Remove selected users and Create user will Manually add a new user into the pool.

Table Columns

  • User name : This is the unique identifier Cognito assigns each user (a UUID-like string). Clicking one opens the details of that specific user.
  • Email address : The email associated with the user.
  • Email verified : Shows whether the email address has been verified: Yes (Verified). No (Not verified)
  • Confirmation status : Indicates if the user has completed the sign-up confirmation process. Confirmed (green) User finished verification (via email/SMS). Unconfirmed (grey) → User signed up but did not confirm email/SMS yet.
  • Status : Account status: Enabled (green check) means User can log in. Disabled (would appear red) User cannot log in.
User list

Diagram – Cognito Auth with Frontend & Backend

Here’s how the whole flow looks:

        +-------------------+           +---------------------+
        |    User (Client)  |           |     Cognito User    |
        |   (Web/Mobile)    |           |       Pool          |
        +-------------------+           +---------------------+
                 |                               |
     [Login / Signup Request] ------------------>|
                 |                               |
                 |<--------- JWT Tokens ---------|
                 |    (ID, Access, Refresh)      |
                 v
        +-------------------+       Authorization: Bearer <JWT>
        |   Frontend App    |------------------------------------+
        | (React / Native)  |                                    |
        +-------------------+                                    |
                 |                                               v
                 |                                   +----------------------+
                 |                                   |    Backend API       |
                 |                                   | (Node/Express/Lambda)|
                 |                                   +----------------------+
                 |                                               |
                 |                               [JWT Verification + RBAC] 
                 |                                               |
                 v                                               v
        +-------------------+                       +----------------------+
        |   User Dashboard  |<------ Protected -----|   Application Logic  |
        |                   |       Data/API        |   + Database Layer   |
        +-------------------+                       +----------------------+

Challenges and Best practices:

Password migration: Firebase doesn’t give raw passwords, so you must choose between resets or progressive migration.
MFA differences: Cognito supports SMS/Authenticator MFA, configure carefully.
Frontend SDK choice: Amplify makes it easier but can feel heavy. Direct Cognito SDK works fine.

Conclusion

Firebase Authentication is an excellent starting point, but as apps scale into enterprise territory, Amazon Cognito wins on pricing, compliance, and customization. Migrating takes planning, especially with passwords, but the long-term benefits are worth it.

By following this step-by-step migration approach — from setup to frontend/backend changes — you can confidently move your app from Firebase to Cognito and unlock enterprise-grade identity management.