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

@gdnaio/cognito-auth

v1.2.1

Published

Reusable AWS Cognito auth library for React and Next.js

Downloads

44

Readme

@gdnaio/cognito-auth

Reusable AWS Cognito auth library for React and Next.js using Hosted UI + PKCE.

Core project overview

  • Security-first: Authorization Code + PKCE via Cognito Hosted UI
  • Token lifecycle: access/id tokens + refresh support, auto-refresh scheduling
  • Storage modes: memory, localStorage, and cookie-first (when using Next.js routes)
  • Next.js support: Edge middleware, route handlers for login/callback/logout, server session util
  • Lightweight: framework-agnostic core, no Amplify; uses jose and cross-fetch

Public API

  • Provider: CognitoAuthProvider({ config })
    • region, userPoolId, clientId, domain, redirectUri, signOutRedirectUri, id?
    • scopes? (default: ['openid','email','profile']), storage? ('cookie'|'localStorage'|'memory')
    • cookieNames?, clockSkewSec?, onAuthStateChange?
  • Hook: useAuth(){ isAuthenticated, user, id, signIn, signOut, handleRedirectCallback, getAccessToken, getIdToken }
    • handleRedirectCallback(authCode?, callbackUrl?): If authCode is provided, exchanges the code directly without PKCE and skips reading params from the URL. When provided, callbackUrl overrides the redirect_uri used for token exchange.
  • Component: RequireAuth – guards children with fallback
  • Next.js helpers (subpath @gdnaio/cognito-auth/next):
    • createCognitoMiddleware(cfg)
    • getServerSession(cfg)
    • createLoginRoute(cfg), createAuthCallbackRoute(cfg), createLogoutRoute(cfg)

Notes:

  • config.id is captured once on provider mount and exposed as id from useAuth. Subsequent changes to config.id are ignored (a warning is logged).

Install

npm i @gdnaio/cognito-auth jose cross-fetch

Peer deps:

  • react >=18
  • next >=13 (optional)

Configuration notes

  • Hosted UI (redirect-based) requires domain and redirectUri.
  • SRP (username/password) does not require domain or redirectUri; only region, userPoolId, clientId are needed.
  • If you use both flows, keep all fields.
  • In Next.js, cookie TTLs set in the callback route are configurable via cookieMaxAgeSeconds (access/id) and refreshCookieMaxAgeSeconds (refresh).
  • Client auto-refresh (based on token expiry) is available via autoRefreshToken: true (default false). Supported for storage='localStorage' (and memory if a refresh token is present). For HTTP-only cookie setups, prefer server refresh.

Auto-logout (SPA)

  • For storage='localStorage' (and memory), the provider schedules at access-token expiry. Behavior:
    • When autoRefreshToken: true, it tries a refresh at that moment; if refresh succeeds, the session continues; if it fails, it signs out (clears tokens and redirects to signOutRedirectUri).
    • When autoRefreshToken: false, it signs out immediately at access-token expiry (clears tokens and redirects).
    • Cookie/HTTP-only flows should rely on server/middleware expiry handling instead.

Subscribe to token updates (including auto-refresh) using useAuth():

const { onTokensUpdated } = useAuth()
useEffect(() => {
  const unsubscribe = onTokensUpdated((tokens, { reason }) => {
    if (reason === 'refresh') {
      console.log('tokens refreshed', tokens)
    }
  })
  return unsubscribe
}, [onTokensUpdated])

Usage in React (SPA)

  1. Wrap your app with the provider
import { CognitoAuthProvider } from '@gdnaio/cognito-auth'

export function Root() {
  return (
    <CognitoAuthProvider
      config={{
        region: 'us-east-1',
        userPoolId: 'us-east-1_XXXX',
        clientId: 'xxxxxxxx',
        domain: 'https://your-domain.auth.us-east-1.amazoncognito.com',
        redirectUri: 'http://localhost:5173/auth/callback',
        signOutRedirectUri: 'http://localhost:5173/',
        storage: 'localStorage',
      }}
    >
      <App />
    </CognitoAuthProvider>
  )
}
  1. Handle the OAuth callback once after redirect
import { useEffect } from 'react'
import { useAuth } from '@gdnaio/cognito-auth'

export default function CallbackPage() {
  const { handleRedirectCallback } = useAuth()
  useEffect(() => {
    handleRedirectCallback().finally(() => {
      window.history.replaceState({}, '', '/')
    })
  }, [handleRedirectCallback])
  return null
}

Alternate: supply an explicit authorization code and optional callback URL override

import { useEffect } from 'react'
import { useAuth } from '@gdnaio/cognito-auth'

export default function CallbackPage() {
  const { handleRedirectCallback } = useAuth()
  useEffect(() => {
    const url = new URL(window.location.href)
    const authCode = url.searchParams.get('code') || undefined
    const callbackUrl = 'https://your-app.example.com/auth/callback' // optional override

    if (authCode) {
      handleRedirectCallback(authCode, callbackUrl).finally(() => {
        window.history.replaceState({}, '', '/')
      })
    } else {
      handleRedirectCallback().finally(() => {
        window.history.replaceState({}, '', '/')
      })
    }
  }, [handleRedirectCallback])
  return null
}

Notes:

  • When authCode is provided, the library exchanges the code without a PKCE verifier and skips URL param parsing.
  • callbackUrl, when provided, overrides the redirect_uri used in the token exchange.
  • Exchanging a code without PKCE works only if your Cognito App Client allows it (PKCE not enforced for your flow).
  1. Use auth state and actions
import { useAuth, RequireAuth } from '@gdnaio/cognito-auth'

export function Page() {
  const { isAuthenticated, user, signIn, signOut } = useAuth()
  return (
    <main>
      {!isAuthenticated ? (
        <button onClick={() => signIn()}>Sign in</button>
      ) : (
        <>
          <pre>{JSON.stringify(user, null, 2)}</pre>
          <button onClick={() => signOut()}>Sign out</button>
        </>
      )}
      <RequireAuth fallback={<p>Please sign in</p>}>
        <p>Protected content</p>
      </RequireAuth>
    </main>
  )
}

Tokens auto-refresh automatically just before expiry when using storage='localStorage'.

Notes:

  • Client auto-refresh runs automatically based on token expiry. For HTTP-only cookie setups, prefer server refresh (Next.js callback/cookie flow).

Optional: attach an Axios interceptor

import axios from 'axios'
import { createAxiosInterceptor, useAuth } from '@gdnaio/cognito-auth'

const api = axios.create()
const { getAccessToken } = useAuth()
createAxiosInterceptor(api, getAccessToken)

Optional: Embedded username/password (SRP) login

If you prefer an in-app form instead of the Hosted UI, enable SRP by calling signInWithPassword provided by the context. Your app must have the Cognito App Client configured to allow SRP (no client secret) and the password-based flow enabled.

import { useState } from 'react'
import { useAuth } from '@gdnaio/cognito-auth'

export function PasswordLogin() {
  const { signInWithPassword, isAuthenticated, user, signOut } = useAuth()
  const [username, setUsername] = useState('')
  const [password, setPassword] = useState('')
  return (
    <div>
      {!isAuthenticated ? (
        <form
          onSubmit={e => {
            e.preventDefault()
            signInWithPassword?.(username, password)
          }}
        >
          <input value={username} onChange={e => setUsername(e.target.value)} placeholder='email or username' />
          <input value={password} onChange={e => setPassword(e.target.value)} type='password' placeholder='password' />
          <button type='submit'>Sign in</button>
        </form>
      ) : (
        <>
          <pre>{JSON.stringify(user, null, 2)}</pre>
          <button onClick={() => signOut()}>Sign out</button>
        </>
      )}
    </div>
  )
}

Notes:

  • SRP happens fully in the browser via amazon-cognito-identity-js.
  • If MFA, new password, or custom challenges are required, the method throws codes like MFA_REQUIRED or NEW_PASSWORD_REQUIRED. Extend the flow to handle those as needed.

Usage in Next.js (App Router)

  1. Add route handlers
// app/api/auth/login/route.ts
import { createLoginRoute } from '@gdnaio/cognito-auth/next'
export const GET = createLoginRoute({
  domain: process.env.NEXT_PUBLIC_COGNITO_DOMAIN!,
  clientId: process.env.NEXT_PUBLIC_COGNITO_CLIENT_ID!,
  redirectUri: process.env.NEXT_PUBLIC_COGNITO_REDIRECT_URI!,
  scopes: ['openid', 'email', 'profile'],
})
// app/api/auth/callback/route.ts
import { createAuthCallbackRoute } from '@gdnaio/cognito-auth/next'
export const GET = createAuthCallbackRoute({
  region: process.env.NEXT_PUBLIC_AWS_REGION!,
  userPoolId: process.env.NEXT_PUBLIC_USER_POOL_ID!,
  clientId: process.env.NEXT_PUBLIC_COGNITO_CLIENT_ID!,
  domain: process.env.NEXT_PUBLIC_COGNITO_DOMAIN!,
  redirectUri: process.env.NEXT_PUBLIC_COGNITO_REDIRECT_URI!,
  // Optional cookie TTL configuration (defaults: access/id 1h, refresh 30d)
  cookieMaxAgeSeconds: 60 * 30, // 30 minutes for access/id tokens
  refreshCookieMaxAgeSeconds: 7 * 24 * 3600, // 7 days for refresh token
})
// app/api/auth/logout/route.ts
import { createLogoutRoute } from '@gdnaio/cognito-auth/next'
export const GET = createLogoutRoute({
  domain: process.env.NEXT_PUBLIC_COGNITO_DOMAIN!,
  clientId: process.env.NEXT_PUBLIC_COGNITO_CLIENT_ID!,
  signOutRedirectUri: process.env.NEXT_PUBLIC_SIGNOUT_REDIRECT_URI!,
})
  1. Protect routes with middleware
// middleware.ts
import { createCognitoMiddleware } from '@gdnaio/cognito-auth/next'
export default createCognitoMiddleware({
  region: process.env.NEXT_PUBLIC_AWS_REGION!,
  userPoolId: process.env.NEXT_PUBLIC_USER_POOL_ID!,
  audience: process.env.NEXT_PUBLIC_COGNITO_CLIENT_ID!,
  publicRoutes: ['/api/auth', '/public'],
})
  1. Wrap application with provider
// app/layout.tsx
import { CognitoAuthProvider } from '@gdnaio/cognito-auth'

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html>
      <body>
        <CognitoAuthProvider
          config={{
            region: process.env.NEXT_PUBLIC_AWS_REGION!,
            userPoolId: process.env.NEXT_PUBLIC_USER_POOL_ID!,
            clientId: process.env.NEXT_PUBLIC_COGNITO_CLIENT_ID!,
            domain: process.env.NEXT_PUBLIC_COGNITO_DOMAIN!,
            redirectUri: process.env.NEXT_PUBLIC_COGNITO_REDIRECT_URI!,
            signOutRedirectUri: process.env.NEXT_PUBLIC_SIGNOUT_REDIRECT_URI!,
            scopes: ['openid', 'email', 'profile'],
            storage: 'cookie',
          }}
        >
          {children}
        </CognitoAuthProvider>
      </body>
    </html>
  )
}

SSR/API usage (optional):

import { getServerSession } from '@gdnaio/cognito-auth/next'

export async function GET() {
  const session = await getServerSession({
    region: process.env.NEXT_PUBLIC_AWS_REGION!,
    userPoolId: process.env.NEXT_PUBLIC_USER_POOL_ID!,
    audience: process.env.NEXT_PUBLIC_COGNITO_CLIENT_ID!,
  })
  // use session?.claims
}

Examples

  • Next.js (App Router): examples/next-app
  • React SPA (Vite): examples/react-spa

Each example has its own README with environment variables and run commands.

Notes

  • Hosted UI + PKCE used by default; SRP is available when you need embedded forms
  • For cookie flow in Next.js, use HTTPS in production and set correct redirect/logout URIs in Cognito