npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@modern-innovations/cognito-auth

v1.1.1

Published

Reusable AWS Cognito authentication library with React Query hooks and AuthProvider

Downloads

19

Readme

@modern-innovations/cognito-auth

Reusable AWS Cognito authentication library for React apps. Direct REST calls (no SDK dependency), React Query hooks, and a full AuthProvider with token management.

Features

  • Email + password authentication (signup, login, forgot password)
  • Social login (Google, Facebook, Apple, Amazon) via Cognito Hosted UI — optional
  • Email verification (OTP)
  • MFA support (TOTP authenticator app + email)
  • Auto token refresh with 60-second buffer
  • localStorage session persistence with configurable prefix
  • React Query mutations for loading/error state
  • Extensible via callbacks and generics
  • Zero AWS SDK dependencies — direct REST calls only
  • TypeScript-first with full type exports

Installation

npm install @modern-innovations/cognito-auth

Peer dependencies:

npm install react @tanstack/react-query

API Reference

AuthProvider

Wrap your app with AuthProvider to enable all auth hooks.

import { QueryClientProvider, QueryClient } from "@tanstack/react-query";
import { AuthProvider } from "@modern-innovations/cognito-auth";

const queryClient = new QueryClient();

function App() {
  return (
    <QueryClientProvider client={queryClient}>
      <AuthProvider
        config={{
          region: "us-east-1",
          userPoolId: "us-east-1_XXXXXX",
          clientId: "your-app-client-id",
        }}
        storagePrefix="myapp.auth"
        onLoginSuccess={async (tokens, user) => {
          const profile = await fetchProfile(tokens.accessToken);
          return { ...user, ...profile };
        }}
        onLogout={() => {
          queryClient.clear();
        }}
      >
        <YourApp />
      </AuthProvider>
    </QueryClientProvider>
  );
}

Props

| Prop | Type | Required | Default | Description | | ----------------- | ------------------------------------------------- | -------- | ---------------- | ------------------------------------------------------------------------------ | | config | CognitoAuthConfig | Yes | — | Cognito pool connection config | | oauthConfig | OAuthConfig | No | — | OAuth / Hosted UI config for social logins (see Social Login) | | storagePrefix | string | No | "cognito.auth" | Prefix for localStorage keys ({prefix}.user, {prefix}.tokens) | | onLoginSuccess | (tokens, user) => Promise<AuthUser> \| AuthUser | No | — | Callback after login — extend user with custom data from your backend | | onSignupSuccess | (userSub, email) => Promise<void> \| void | No | — | Callback after successful signup | | onLogout | () => void | No | — | Callback on logout — useful for clearing caches |

CognitoAuthConfig

| Property | Type | Description | | ------------ | -------- | ------------------------------------------------ | | region | string | AWS region (e.g. "us-east-1") | | userPoolId | string | Cognito User Pool ID (e.g. "us-east-1_XXXXXX") | | clientId | string | Cognito App Client ID |

OAuthConfig

| Property | Type | Required | Default | Description | | ------------------- | ------------------- | -------- | -------------------------------- | -------------------------------------------------------------------------- | | domain | string | Yes | — | Cognito Hosted UI domain (e.g. "myapp.auth.us-east-1.amazoncognito.com") | | redirectUri | string | Yes | — | Redirect URI after social login (must match Cognito app client) | | logoutRedirectUri | string | No | Same as redirectUri | Redirect URI after sign-out | | scopes | string[] | No | ["openid", "email", "profile"] | OAuth scopes | | responseType | "code" \| "token" | No | "code" | OAuth response type |


useAuth()

Access the auth state and actions. Must be used within AuthProvider.

const {
  user,
  tokens,
  isAuthenticated,
  isHydrated,
  loginWithTokens,
  setUser,
  logout,
} = useAuth();

Returns: AuthState

| Property | Type | Description | | ----------------- | ------------------------------ | -------------------------------------------------------------------------- | | user | AuthUser \| null | Current authenticated user | | tokens | AuthTokens \| null | Current JWT tokens (id, access, refresh) | | isAuthenticated | boolean | true if user and tokens are present | | isHydrated | boolean | true after localStorage rehydration is complete (use for loading states) | | loginWithTokens | (tokens: AuthTokens) => void | Store tokens, decode user from ID token, trigger onLoginSuccess | | setUser | (user: AuthUser) => void | Update user profile data in state and storage | | logout | () => void | Clear tokens/user, call global sign-out, trigger onLogout |


useAuthService()

Access the raw AuthService instance for advanced or custom flows.

const authService = useAuthService();

// Example: manually refresh session
const refreshed = await authService.refreshSession(refreshToken);

useOAuth()

Access the OAuthService for social login. Only available when oauthConfig is passed to AuthProvider.

const oauth = useOAuth();

// Redirect to Google login
oauth.federatedSignIn("Google");

See Social Login section for full usage.


Hooks

All hooks return a React Query UseMutationResult with mutate, mutateAsync, isPending, isError, error, data, etc.

useLogin()

Sign in with email and password.

const loginMutation = useLogin();

loginMutation.mutate(
  { email: "[email protected]", password: "P@ssw0rd" },
  {
    onSuccess: (tokens) => {
      loginWithTokens(tokens);
    },
  },
);

Input: LoginInput

| Field | Type | Required | Description | | ---------- | -------- | -------- | --------------- | | email | string | Yes | User's email | | password | string | Yes | User's password |

Returns: AuthTokens


useSignup()

Register a new user.

const signupMutation = useSignup();

signupMutation.mutate({
  email: "[email protected]",
  password: "P@ssw0rd",
  firstName: "John",
  lastName: "Doe",
  middleName: "Michael", // optional
  customAttributes: { "custom:company": "Acme" },
});

Input: SignupInput

| Field | Type | Required | Description | | ------------------ | ------------------------ | -------- | ---------------------------------------------------------- | | email | string | Yes | User's email | | password | string | Yes | Password | | firstName | string | Yes | Given name | | lastName | string | Yes | Family name | | middleName | string | No | Middle name (stored as middle_name attribute in Cognito) | | customAttributes | Record<string, string> | No | Additional Cognito user attributes (e.g. custom:company) |

Returns: { userSub: string }


useConfirmSignup()

Confirm email verification with the OTP code.

const confirmMutation = useConfirmSignup();

confirmMutation.mutate({ email: "[email protected]", code: "123456" });

Input: ConfirmSignupInput

| Field | Type | Required | Description | | ------- | -------- | -------- | --------------------------- | | email | string | Yes | User's email | | code | string | Yes | 6-digit OTP code from email |

Returns: void


useResendCode()

Resend the signup confirmation code.

const resendMutation = useResendCode();

resendMutation.mutate({ email: "[email protected]" });

Input: ResendCodeInput

| Field | Type | Required | Description | | ------- | -------- | -------- | ------------ | | email | string | Yes | User's email |

Returns: void


useForgotPassword()

Initiate password reset — sends a code to the user's email.

const forgotMutation = useForgotPassword();

forgotMutation.mutate({ email: "[email protected]" });

Input: ForgotPasswordInput

| Field | Type | Required | Description | | ------- | -------- | -------- | ------------ | | email | string | Yes | User's email |

Returns: void


useConfirmForgotPassword()

Complete password reset with code and new password.

const resetMutation = useConfirmForgotPassword();

resetMutation.mutate({
  email: "[email protected]",
  code: "123456",
  newPassword: "NewP@ssw0rd",
});

Input: ConfirmForgotPasswordInput

| Field | Type | Required | Description | | ------------- | -------- | -------- | --------------------- | | email | string | Yes | User's email | | code | string | Yes | Reset code from email | | newPassword | string | Yes | New password |

Returns: void


useAssociateTotpToken()

Get a TOTP secret to generate a QR code for authenticator apps.

const associateMutation = useAssociateTotpToken();

associateMutation.mutate(tokens.accessToken, {
  onSuccess: ({ secretCode }) => {
    const uri = buildTotpUri(secretCode, user.email, "MyApp");
    const qrUrl = getQrCodeUrl(uri);
    // Display QR code to user
  },
});

Input: string (accessToken)

Returns: AssociateTotpResult

| Field | Type | Description | | ------------ | --------------------- | ---------------------------------- | | secretCode | string | TOTP secret for QR code generation | | session | string \| undefined | Optional session token |


useVerifyTotpToken()

Verify the TOTP code entered by the user from their authenticator app.

const verifyMutation = useVerifyTotpToken();

verifyMutation.mutate({
  accessToken: tokens.accessToken,
  code: "123456",
  friendlyDeviceName: "My Phone",
});

Input: VerifyTotpInput

| Field | Type | Required | Description | | -------------------- | -------- | -------- | --------------------------------------------- | | accessToken | string | Yes | Current access token | | code | string | Yes | 6-digit TOTP code from authenticator app | | friendlyDeviceName | string | No | Device label (default: "Authenticator App") |

Returns: void


useSetMfaPreference()

Set the user's MFA method preference.

const mfaMutation = useSetMfaPreference();

// Enable TOTP as preferred MFA
mfaMutation.mutate({
  accessToken: tokens.accessToken,
  totpEnabled: true,
  totpPreferred: true,
});

// Enable email MFA instead
mfaMutation.mutate({
  accessToken: tokens.accessToken,
  emailEnabled: true,
  emailPreferred: true,
});

Input: SetMfaPreferenceInput

| Field | Type | Required | Description | | ---------------- | --------- | -------- | ----------------------------- | | accessToken | string | Yes | Current access token | | totpEnabled | boolean | No | Enable/disable TOTP MFA | | totpPreferred | boolean | No | Set TOTP as preferred method | | emailEnabled | boolean | No | Enable/disable email MFA | | emailPreferred | boolean | No | Set email as preferred method |

Returns: void


Social Login

Social login is optional. If you don't pass oauthConfig to AuthProvider, all social login features are simply not available — no extra bundle cost.

Setup

<AuthProvider
  config={{
    region: "us-east-1",
    userPoolId: "us-east-1_XXXXXX",
    clientId: "your-app-client-id",
  }}
  oauthConfig={{
    domain: "myapp.auth.us-east-1.amazoncognito.com",
    redirectUri: "http://localhost:3000/auth/callback",
    logoutRedirectUri: "http://localhost:3000",
    scopes: ["openid", "email", "profile"],
  }}
>

Supported Providers

| Provider | Value | | -------- | ------------ | | Google | "Google" | | Apple | "Apple" | | LinkedIn | "LinkedIn" |

Redirecting to Social Login

import { useOAuth } from "@modern-innovations/cognito-auth";

function LoginPage() {
  const oauth = useOAuth();

  return (
    <div>
      <button onClick={() => oauth.federatedSignIn("Google")}>
        Continue with Google
      </button>
      <button onClick={() => oauth.federatedSignIn("LinkedIn")}>
        Continue with LinkedIn
      </button>
      <button onClick={() => oauth.federatedSignIn("Apple")}>
        Continue with Apple
      </button>
    </div>
  );
}

Handling the Callback

After the user signs in with their social provider, they're redirected back to your redirectUri with a ?code= parameter. Exchange it for tokens:

import { useEffect } from "react";
import {
  useAuth,
  useOAuth,
  OAuthService,
} from "@modern-innovations/cognito-auth";

function AuthCallbackPage() {
  const { loginWithTokens } = useAuth();
  const oauth = useOAuth();

  useEffect(() => {
    const code = OAuthService.parseCodeFromUrl();
    if (code) {
      oauth.exchangeCodeForTokens(code).then((tokens) => {
        loginWithTokens(tokens);
        // Navigate to dashboard
        window.history.replaceState({}, "", "/dashboard");
      });
    }
  }, []);

  return <p>Signing you in...</p>;
}

OAuthService Methods

| Method | Description | | --------------------------------------- | ----------------------------------------------------- | | federatedSignIn(provider, state?) | Redirect user to the social provider login page | | getAuthorizationUrl(provider, state?) | Get the authorization URL without redirecting | | exchangeCodeForTokens(code) | Exchange auth code for tokens (call on callback page) | | getLogoutUrl() | Get the Hosted UI logout URL | | OAuthService.parseCodeFromUrl(url?) | Static — extract ?code= from URL | | OAuthService.parseStateFromUrl(url?) | Static — extract ?state= from URL |

Cognito Setup for Social Login

  1. In Cognito Console → Sign-in experience → Federated identity provider sign-in, add your providers (Google, Facebook, etc.)
  2. In App integration → App client → Hosted UI:
    • Set Allowed callback URLs (must match redirectUri)
    • Set Allowed sign-out URLs (must match logoutRedirectUri)
    • Enable the identity providers you want
    • Set OAuth grant type to "Authorization code grant"
    • Set OpenID Connect scopes to openid, email, profile
  3. Configure a Cognito domain (or custom domain) under App integration

TOTP Utilities

Helper functions for building TOTP authenticator flows.

buildTotpUri(secret, email, issuer?)

Generate an otpauth:// URI for authenticator apps.

import { buildTotpUri } from "@modern-innovations/cognito-auth";

const uri = buildTotpUri("JBSWY3DPEHPK3PXP", "[email protected]", "MyApp");
// → "otpauth://totp/MyApp:user%40example.com?secret=JBSWY3DPEHPK3PXP&issuer=MyApp&algorithm=SHA1&digits=6&period=30"

| Param | Type | Default | Description | | -------- | -------- | ------- | ---------------------------------------- | | secret | string | — | TOTP secret from useAssociateTotpToken | | email | string | — | User's email | | issuer | string | "App" | App name shown in authenticator |

formatSecret(secret)

Format a secret into groups of 4 for manual entry display.

import { formatSecret } from "@modern-innovations/cognito-auth";

formatSecret("JBSWY3DPEHPK3PXP");
// → "JBSW Y3DP EHPK 3PXP"

getQrCodeUrl(data, size?)

Generate a QR code image URL using a public API.

import { getQrCodeUrl } from "@modern-innovations/cognito-auth";

const qrUrl = getQrCodeUrl(totpUri, 250);
// → "https://api.qrserver.com/v1/create-qr-code/?size=250x250&data=..."

| Param | Type | Default | Description | | ------ | -------- | ------- | --------------------------------------- | | data | string | — | Data to encode (typically the TOTP URI) | | size | number | 200 | QR image size in pixels |

For production, consider using a local QR library (e.g. qrcode) instead of the public API.


Error Handling

All hooks throw CognitoAuthError on Cognito-specific failures.

import { CognitoAuthError } from "@modern-innovations/cognito-auth";

loginMutation.mutate(credentials, {
  onError: (error) => {
    if (error instanceof CognitoAuthError) {
      console.log(error.code); // e.g. "NotAuthorizedException"
      console.log(error.message); // e.g. "Incorrect username or password."
    }
  },
});

Common Cognito error codes:

| Code | Meaning | | -------------------------- | ---------------------------- | | NotAuthorizedException | Incorrect email or password | | UserNotFoundException | User does not exist | | UsernameExistsException | Email already registered | | CodeMismatchException | Invalid verification code | | ExpiredCodeException | Verification code expired | | InvalidPasswordException | Password doesn't meet policy | | LimitExceededException | Too many attempts, try later |


Types

All types are exported for use in your application:

import type {
  CognitoAuthConfig,
  AuthProviderOptions,
  AuthTokens,
  AuthUser,
  AuthState,
  SignupInput,
  ConfirmSignupInput,
  LoginInput,
  ForgotPasswordInput,
  ConfirmForgotPasswordInput,
  ResendCodeInput,
  AssociateTotpResult,
  VerifyTotpInput,
  SetMfaPreferenceInput,
  MfaMethod,
  OAuthConfig,
  SocialProvider,
  ExchangeCodeInput,
} from "@modern-innovations/cognito-auth";

AuthTokens

| Field | Type | Description | | -------------- | -------- | -------------------------------------- | | idToken | string | JWT ID token (contains user claims) | | accessToken | string | JWT access token (for API calls) | | refreshToken | string | Refresh token (for getting new tokens) | | expiresIn | number | Token lifetime in seconds |

AuthUser

| Field | Type | Description | | --------------- | --------------------- | ------------------------------ | | email | string | User's email | | firstName | string | Given name | | lastName | string | Family name | | middleName | string \| undefined | Middle name (optional) | | sub | string | Cognito user ID | | [key: string] | unknown | Extensible — add custom fields |


Extending the User Type

import type { AuthUser } from "@modern-innovations/cognito-auth";

interface MyAppUser extends AuthUser {
  organisation: string;
  role: "admin" | "member";
}

Route Protection Example

import { useAuth } from "@modern-innovations/cognito-auth";

function ProtectedLayout() {
  const { isAuthenticated, isHydrated } = useAuth();

  if (!isHydrated) return <Loading />;
  if (!isAuthenticated) return <Navigate to="/login" />;
  return <Outlet />;
}

Full MFA Setup Flow

import {
  useAuth,
  useAssociateTotpToken,
  useVerifyTotpToken,
  useSetMfaPreference,
  buildTotpUri,
  getQrCodeUrl,
  formatSecret,
} from "@modern-innovations/cognito-auth";

function MfaSetupPage() {
  const { tokens } = useAuth();
  const associate = useAssociateTotpToken();
  const verify = useVerifyTotpToken();
  const setPreference = useSetMfaPreference();

  // Step 1: Get the secret
  const handleSetup = () => {
    associate.mutate(tokens!.accessToken, {
      onSuccess: ({ secretCode }) => {
        const uri = buildTotpUri(secretCode, user.email, "MyApp");
        setQrUrl(getQrCodeUrl(uri));
        setManualCode(formatSecret(secretCode));
      },
    });
  };

  // Step 2: Verify the code from the authenticator app
  const handleVerify = (code: string) => {
    verify.mutate(
      { accessToken: tokens!.accessToken, code },
      {
        onSuccess: () => {
          // Step 3: Set TOTP as preferred MFA
          setPreference.mutate({
            accessToken: tokens!.accessToken,
            totpEnabled: true,
            totpPreferred: true,
          });
        },
      },
    );
  };
}

Cognito Setup Requirements

Your AWS Cognito User Pool must be configured with:

  • Sign-in attribute: Email
  • App Client auth flows: ALLOW_USER_PASSWORD_AUTH and ALLOW_REFRESH_TOKEN_AUTH
  • MFA: Set to "Optional" with TOTP and/or Email enabled
  • Email verification: Enabled
  • App Client: No client secret (required for browser-based auth)
  • User attributes: given_name, family_name required; middle_name optional

License

UNLICENSED