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

@codecot/okta-zustand

v0.4.0

Published

A modern Okta authentication library for React using Zustand state management

Readme

@codecot/okta-zustand

A modern Okta authentication library for React using Zustand state management. This library provides a complete replacement for @okta/okta-react with better performance, simpler API, and no Context API dependencies.

Features

  • 🚀 Built with Zustand for optimal performance
  • 🔐 Full OAuth 2.0 / OIDC support with PKCE
  • 🔄 Automatic token refresh
  • 💾 Flexible token storage (localStorage, sessionStorage, cookies)
  • 🎣 React hooks for easy integration
  • 🛡️ Protected route components
  • 🔁 Retry logic with exponential backoff
  • 📦 TypeScript support
  • 🎯 No Context API - works anywhere in your app
  • 🔒 Advanced route protection with group-based authorization
  • 📡 Cross-tab synchronization
  • 🎨 Multiple UI components for different use cases

Installation

npm install @codecot/okta-zustand zustand react react-router-dom
# or
yarn add @codecot/okta-zustand zustand react react-router-dom

Quick Start

1. Initialize Okta

import { OktaProvider } from '@codecot/okta-zustand'

const oktaConfig = {
  issuer: 'https://your-okta-domain/oauth2/default',
  clientId: 'your-client-id',
  redirectUri: window.location.origin + '/login/callback',
  scopes: ['openid', 'profile', 'email'],
  pkce: true,
  tokenManager: {
    autoRenew: true,
    storage: 'localStorage'
  }
}

function App() {
  return (
    <OktaProvider config={oktaConfig}>
      <Router>
        {/* Your app routes */}
      </Router>
    </OktaProvider>
  )
}

2. Setup Routes

import { SecureRoute, LoginCallback } from '@codecot/okta-zustand'

function AppRoutes() {
  return (
    <Routes>
      <Route path="/login/callback" element={<LoginCallback />} />
      <Route 
        path="/protected" 
        element={
          <SecureRoute>
            <ProtectedPage />
          </SecureRoute>
        } 
      />
      <Route path="/login" element={<LoginPage />} />
    </Routes>
  )
}

3. Use Authentication

import { useOktaAuth } from '@codecot/okta-zustand'

function LoginPage() {
  const { login, isAuthenticated } = useOktaAuth()

  if (isAuthenticated) {
    return <Navigate to="/protected" />
  }

  return (
    <button onClick={() => login()}>
      Login with Okta
    </button>
  )
}

function UserProfile() {
  const { user, logout, isLoading } = useOktaAuth()

  if (isLoading) return <div>Loading...</div>

  return (
    <div>
      <h1>Welcome {user?.name}!</h1>
      <button onClick={() => logout()}>Logout</button>
    </div>
  )
}

Documentation

API Reference

Hooks

useOktaAuth()

Main hook for authentication operations.

const {
  isAuthenticated,  // boolean
  isLoading,       // boolean
  user,            // OktaUser | null
  tokens,          // OktaTokens | null
  error,           // AuthError | null
  login,           // (options?: LoginOptions) => Promise<void>
  logout,          // (options?: LogoutOptions) => Promise<void>
  handleRedirectCallback, // () => Promise<void>
  refreshToken     // () => Promise<void>
} = useOktaAuth()

useAccessToken()

Get the current access token.

const accessToken = useAccessToken() // string | null

useIdToken()

Get the current ID token.

const idToken = useIdToken() // string | null

useOktaUser()

Get the current user information.

const user = useOktaUser() // OktaUser | null

useUserInfo()

Fetch detailed user information from the userinfo endpoint.

const { userInfo, loading, error } = useUserInfo()

Components

<OktaProvider>

Initializes the Okta authentication system.

<OktaProvider 
  config={oktaConfig} 
  onAuthRequired={() => console.log('Auth required')}
>
  {children}
</OktaProvider>

<SecureRoute>

Protects routes that require authentication.

<SecureRoute 
  redirectTo="/login"
  loadingComponent={<CustomLoader />}
>
  <ProtectedContent />
</SecureRoute>

<LoginCallback>

Handles the OAuth callback after login.

<LoginCallback 
  redirectTo="/dashboard"
  loadingComponent={<div>Authenticating...</div>}
  errorComponent={(error) => <ErrorPage error={error} />}
/>

<AuthGuard>

Conditionally renders content based on auth state.

<AuthGuard 
  fallback={<LoginPrompt />}
  loadingComponent={<Spinner />}
>
  <ProtectedContent />
</AuthGuard>

Higher-Order Components

withOktaAuth()

Injects auth props into components.

const EnhancedComponent = withOktaAuth(MyComponent, {
  requireAuth: true,
  redirectTo: '/login'
})

Advanced Usage

Custom Token Storage

import { TokenStorage } from '@codecot/okta-zustand'

class CustomStorage extends TokenStorage {
  constructor() {
    super('cookie', 'my-app-tokens')
  }
}

const oktaConfig = {
  // ... other config
  tokenManager: {
    storage: new CustomStorage()
  }
}

Error Handling

import { useOktaAuth, isAuthError, OktaAuthError } from '@codecot/okta-zustand'

function LoginForm() {
  const { login, error } = useOktaAuth()

  const handleLogin = async () => {
    try {
      await login()
    } catch (err) {
      if (isAuthError(err)) {
        console.error('Auth error:', err.errorCode, err.errorSummary)
      }
    }
  }

  return (
    <>
      {error && <div className="error">{error.errorSummary}</div>}
      <button onClick={handleLogin}>Login</button>
    </>
  )
}

Manual Token Management

import { useAuthStore } from '@codecot/okta-zustand'

function TokenManager() {
  const { tokens, refreshToken, setTokens } = useAuthStore()

  const handleRefresh = async () => {
    try {
      await refreshToken()
    } catch (error) {
      console.error('Failed to refresh token:', error)
    }
  }

  return (
    <div>
      <p>Access Token expires at: {new Date(tokens?.accessToken?.expiresAt * 1000).toLocaleString()}</p>
      <button onClick={handleRefresh}>Refresh Token</button>
    </div>
  )
}

Using with Next.js

// pages/_app.tsx
import { OktaProvider } from '@codecot/okta-zustand'
import { useRouter } from 'next/router'

function MyApp({ Component, pageProps }) {
  const router = useRouter()

  const oktaConfig = {
    issuer: process.env.NEXT_PUBLIC_OKTA_ISSUER,
    clientId: process.env.NEXT_PUBLIC_OKTA_CLIENT_ID,
    redirectUri: `${process.env.NEXT_PUBLIC_BASE_URL}/api/auth/callback`,
  }

  return (
    <OktaProvider 
      config={oktaConfig}
      onAuthRequired={() => router.push('/login')}
    >
      <Component {...pageProps} />
    </OktaProvider>
  )
}

Configuration Options

interface OktaConfig {
  // Required
  issuer: string
  clientId: string
  redirectUri: string

  // Optional
  scopes?: string[]              // Default: ['openid', 'profile', 'email']
  pkce?: boolean                 // Default: true
  responseType?: string          // Default: 'code'
  responseMode?: string          // Default: 'query'
  postLogoutRedirectUri?: string
  prompts?: string[]
  display?: string
  maxAge?: number
  acrValues?: string

  tokenManager?: {
    autoRenew?: boolean          // Default: true
    expireEarlySeconds?: number  // Default: 30
    storage?: 'localStorage' | 'sessionStorage' | 'cookie'
    storageKey?: string          // Default: 'okta-token-storage'
  }
}

Migration from @okta/okta-react

1. Replace the Security component:

// Old
import { Security } from '@okta/okta-react'
<Security oktaAuth={oktaAuth}>

// New
import { OktaProvider } from '@codecot/okta-zustand'
<OktaProvider config={oktaConfig}>

2. Replace SecureRoute:

// Old
import { SecureRoute } from '@okta/okta-react'
<SecureRoute path="/protected" component={ProtectedComponent} />

// New
import { SecureRoute } from '@codecot/okta-zustand'
<Route path="/protected" element={<SecureRoute><ProtectedComponent /></SecureRoute>} />

3. Replace useOktaAuth hook:

// Old
import { useOktaAuth } from '@okta/okta-react'
const { oktaAuth, authState } = useOktaAuth()

// New
import { useOktaAuth } from '@codecot/okta-zustand'
const { isAuthenticated, user, login, logout } = useOktaAuth()

Browser Support

  • Chrome (latest)
  • Firefox (latest)
  • Safari (latest)
  • Edge (latest)

License

MIT

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Support

For issues and feature requests, please use the GitHub issue tracker.