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

@gsarthak783/accesskit-react

v1.2.6

Published

React SDK for AccessKit Authentication System

Readme

@gsarthak783/accesskit-react

React SDK for AccessKit Authentication System - Ready-to-use hooks and components for React applications.

npm version License: MIT

🚀 Quick Start

Installation

npm install @gsarthak783/accesskit-react @gsarthak783/accesskit-auth

Basic Usage

Wrap your app with the AuthProvider:

import { AuthProvider } from '@gsarthak783/accesskit-react';

function App() {
  const authConfig = {
    projectId: 'your-project-id',
    apiKey: 'your-api-key'
  };

  return (
    <AuthProvider config={authConfig}>
      {/* Your app components */}
    </AuthProvider>
  );
}

Using Auth in Components

import { useAuth } from '@gsarthak783/accesskit-react';

function MyComponent() {
  const { user, isAuthenticated, isLoading, login, logout } = useAuth();

  if (isLoading) {
    return <div>Loading...</div>;
  }

  if (!isAuthenticated) {
    return (
      <button onClick={() => login('[email protected]', 'password')}>
        Login
      </button>
    );
  }

  return (
    <div>
      <h1>Welcome, {user.firstName}!</h1>
      <button onClick={logout}>Logout</button>
    </div>
  );
}

Persistent Authentication

The SDK automatically maintains authentication state across page refreshes, similar to Firebase Auth.

function App() {
  const { user, isAuthenticated, isLoading } = useAuth();

  // On initial load and page refresh:
  // 1. isLoading is true while checking stored tokens
  // 2. If valid tokens exist, user is automatically logged in
  // 3. isLoading becomes false once check is complete

  if (isLoading) {
    return <div>Checking authentication...</div>;
  }

  return (
    <div>
      {isAuthenticated ? (
        <div>
          Welcome back, {user.firstName}!
          {/* User stays logged in even after page refresh */}
        </div>
      ) : (
        <div>Please log in</div>
      )}
    </div>
  );
}

How Persistence Works

  1. Token Storage: Access and refresh tokens are stored in localStorage by default
  2. Automatic Verification: On app initialization, stored tokens are verified
  3. Seamless Experience: Valid tokens = user stays logged in across sessions
  4. Token Refresh: Expired access tokens are automatically refreshed using the refresh token

Example: Protected Routes with Persistence

function ProtectedRoute({ children }) {
  const { isAuthenticated, isLoading } = useAuth();
  
  if (isLoading) {
    // Important: Show loading while checking auth state
    return <LoadingSpinner />;
  }
  
  if (!isAuthenticated) {
    return <Navigate to="/login" />;
  }
  
  return children;
}

// Usage
function App() {
  return (
    <AuthProvider config={config}>
      <Routes>
        <Route path="/login" element={<Login />} />
        <Route
          path="/dashboard"
          element={
            <ProtectedRoute>
              <Dashboard />
            </ProtectedRoute>
          }
        />
      </Routes>
    </AuthProvider>
  );
}

Handling Different Scenarios

function AuthStatus() {
  const { user, isAuthenticated, isLoading, logout } = useAuth();

  useEffect(() => {
    if (isAuthenticated && user) {
      console.log('User restored from previous session:', user.email);
    }
  }, [isAuthenticated, user]);

  if (isLoading) {
    return <div>Loading...</div>;
  }

  if (!isAuthenticated) {
    return <div>Not logged in</div>;
  }

  return (
    <div>
      <p>Logged in as: {user.email}</p>
      <p>Session persists across refreshes</p>
      <button onClick={logout}>Logout</button>
    </div>
  );
}

🎯 Get Your API Keys

  1. Visit the AccessKit Dashboard
  2. Create an account or login
  3. Create a new project
  4. Copy your Project ID and API Key from the project settings

🪝 useAuth Hook

The useAuth hook provides all authentication functionality:

interface AuthContextType {
  // State
  user: User | null;
  isLoading: boolean;
  isAuthenticated: boolean;
  
  // Actions
  login: (email: string, password: string) => Promise<void>;
  register: (userData: RegisterData) => Promise<void>;
  logout: () => Promise<void>;
  updateProfile: (userData: Partial<User>) => Promise<void>;
  requestPasswordReset: (email: string) => Promise<void>;
  resetPassword: (token: string, password: string) => Promise<void>;
  verifyEmail: (token: string) => Promise<void>;
  
  // Direct SDK access
  client: AuthClient;
}

Registration

function SignupForm() {
  const { register, isLoading } = useAuth();
  
  const handleSubmit = async (formData) => {
    try {
      await register({
        email: formData.email,
        password: formData.password,
        firstName: formData.firstName,
        lastName: formData.lastName,
        username: formData.username,
        customFields: { role: 'user' }
      });
      // User is automatically logged in after registration
    } catch (error) {
      console.error('Registration failed:', error);
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      {/* Your form fields */}
      <button type="submit" disabled={isLoading}>
        {isLoading ? 'Creating Account...' : 'Sign Up'}
      </button>
    </form>
  );
}

Profile Management

function UserProfile() {
  const { user, updateProfile } = useAuth();

  const handleUpdate = async (newData) => {
    try {
      await updateProfile(newData);
      // User state is automatically updated
    } catch (error) {
      console.error('Update failed:', error);
    }
  };

  return (
    <div>
      <h2>{user.firstName} {user.lastName}</h2>
      <p>{user.email}</p>
      <button onClick={() => handleUpdate({ firstName: 'NewName' })}>
        Update Name
      </button>
    </div>
  );
}

🧩 Ready-to-Use Components

LoginForm Component

A complete login form with validation:

import { LoginForm } from '@gsarthak783/accesskit-react';

function LoginPage() {
  return (
    <div className="login-page">
      <LoginForm
        onSuccess={() => console.log('Login successful!')}
        onError={(error) => console.error('Login failed:', error)}
        className="custom-login-form"
        buttonText="Sign In"
        showSignupLink={true}
        onSignupClick={() => navigate('/signup')}
      />
    </div>
  );
}

LoginForm Props

interface LoginFormProps {
  onSuccess?: () => void;
  onError?: (error: Error) => void;
  className?: string;
  buttonText?: string;
  showSignupLink?: boolean;
  onSignupClick?: () => void;
}

⚙️ AuthProvider Configuration

<AuthProvider 
  config={{
    projectId: 'your-project-id',
    apiKey: 'your-api-key',
    baseUrl: 'https://access-kit-server.vercel.app/api/project-users', // Optional, defaults to this
    timeout: 10000 // Optional, request timeout in ms
  }}
  storage={customStorage} // Optional, custom token storage
  autoInitialize={true}   // Optional, auto-check authentication on mount
>
  <App />
</AuthProvider>

Custom Storage

import { AuthProvider } from '@gsarthak783/accesskit-react';

// Custom storage for React Native or other environments
const customStorage = {
  getItem: (key) => AsyncStorage.getItem(key),
  setItem: (key, value) => AsyncStorage.setItem(key, value),
  removeItem: (key) => AsyncStorage.removeItem(key)
};

<AuthProvider config={config} storage={customStorage}>
  <App />
</AuthProvider>

🎨 Advanced Usage

Account Security

import { useAuth } from '@gsarthak783/accesskit-react';

function AccountSettings() {
  const { user, updatePassword, updateEmail, reauthenticateWithCredential } = useAuth();
  const [isReauthenticated, setIsReauthenticated] = useState(false);

  // Change password
  const handlePasswordChange = async (currentPassword, newPassword) => {
    try {
      await updatePassword(currentPassword, newPassword);
      alert('Password updated successfully! Please login again.');
      // User will be logged out automatically
    } catch (error) {
      alert(`Error: ${error.message}`);
    }
  };

  // Update email
  const handleEmailUpdate = async (newEmail, password) => {
    try {
      const result = await updateEmail(newEmail, password);
      alert(`Email updated to ${result.email}. Please verify your new email.`);
    } catch (error) {
      alert(`Error: ${error.message}`);
    }
  };

  // Reauthenticate before sensitive operations
  const handleReauthentication = async (password) => {
    try {
      const result = await reauthenticateWithCredential(password);
      setIsReauthenticated(true);
      console.log('Reauthenticated at:', result.authenticatedAt);
      // Now you can show sensitive settings
    } catch (error) {
      alert('Invalid password');
    }
  };

  return (
    <div>
      {!isReauthenticated ? (
        <form onSubmit={(e) => {
          e.preventDefault();
          handleReauthentication(e.target.password.value);
        }}>
          <input type="password" name="password" placeholder="Enter password to continue" />
          <button type="submit">Verify Identity</button>
        </form>
      ) : (
        <div>
          {/* Show sensitive account settings */}
        </div>
      )}
    </div>
  );
}

Protected Routes

import { useAuth } from '@gsarthak783/accesskit-react';
import { Navigate } from 'react-router-dom';

function ProtectedRoute({ children }) {
  const { isAuthenticated, isLoading } = useAuth();

  if (isLoading) {
    return <div>Loading...</div>;
  }

  return isAuthenticated ? children : <Navigate to="/login" />;
}

// Usage
<ProtectedRoute>
  <Dashboard />
</ProtectedRoute>

Role-Based Access

function AdminPanel() {
  const { user, isAuthenticated } = useAuth();

  if (!isAuthenticated || user.customFields?.role !== 'admin') {
    return <div>Access denied</div>;
  }

  return <div>Admin content</div>;
}

Form Validation

function RegisterForm() {
  const { register, isLoading } = useAuth();
  const [formData, setFormData] = useState({
    email: '',
    password: '',
    firstName: '',
    lastName: ''
  });
  const [errors, setErrors] = useState({});

  const validateForm = () => {
    const newErrors = {};
    
    if (!formData.email.includes('@')) {
      newErrors.email = 'Invalid email';
    }
    
    if (formData.password.length < 6) {
      newErrors.password = 'Password must be at least 6 characters';
    }
    
    setErrors(newErrors);
    return Object.keys(newErrors).length === 0;
  };

  const handleSubmit = async (e) => {
    e.preventDefault();
    
    if (!validateForm()) return;

    try {
      await register(formData);
    } catch (error) {
      setErrors({ submit: error.message });
    }
  };

  return (
    <form onSubmit={handleSubmit}>
      <input
        type="email"
        value={formData.email}
        onChange={(e) => setFormData({...formData, email: e.target.value})}
        placeholder="Email"
      />
      {errors.email && <span className="error">{errors.email}</span>}
      
      <input
        type="password"
        value={formData.password}
        onChange={(e) => setFormData({...formData, password: e.target.value})}
        placeholder="Password"
      />
      {errors.password && <span className="error">{errors.password}</span>}
      
      <button type="submit" disabled={isLoading}>
        {isLoading ? 'Registering...' : 'Register'}
      </button>
      
      {errors.submit && <div className="error">{errors.submit}</div>}
    </form>
  );
}

Direct SDK Access

function AdvancedComponent() {
  const { client } = useAuth();

  const handleAdminAction = async () => {
    try {
      // Direct access to the underlying AuthClient
      const users = await client.getAllUsers({
        page: 1,
        limit: 10,
        status: 'active'
      });
      console.log('Users:', users);
    } catch (error) {
      console.error('Failed to fetch users:', error);
    }
  };

  return (
    <button onClick={handleAdminAction}>
      Get All Users (Admin)
    </button>
  );
}

🎨 Styling

The components come with minimal styling. You can customize them using CSS classes:

/* Custom styles for LoginForm */
.custom-login-form {
  max-width: 400px;
  margin: 0 auto;
  padding: 2rem;
  border-radius: 8px;
  box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}

.custom-login-form input {
  width: 100%;
  padding: 0.75rem;
  margin-bottom: 1rem;
  border: 1px solid #ddd;
  border-radius: 4px;
}

.custom-login-form button {
  width: 100%;
  padding: 0.75rem;
  background-color: #007bff;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}

.custom-login-form button:disabled {
  background-color: #6c757d;
  cursor: not-allowed;
}

🔒 Security Best Practices

Environment Variables

Never expose API keys in frontend code:

// ❌ Don't do this
const config = {
  projectId: 'proj_123',
  apiKey: 'sk_live_abc123' // Never expose secret keys in frontend!
};

// ✅ Do this instead
const config = {
  projectId: process.env.REACT_APP_PROJECT_ID,
  // Use public keys only in frontend, manage auth server-side
};

Secure Token Storage

// For React Native or when you need secure storage
import * as SecureStore from 'expo-secure-store';

const secureStorage = {
  getItem: async (key) => await SecureStore.getItemAsync(key),
  setItem: async (key, value) => await SecureStore.setItemAsync(key, value),
  removeItem: async (key) => await SecureStore.deleteItemAsync(key)
};

<AuthProvider config={config} storage={secureStorage}>
  <App />
</AuthProvider>

Input Validation

Always validate user inputs:

const validateEmail = (email) => {
  const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
  return emailRegex.test(email);
};

const validatePassword = (password) => {
  return password.length >= 8 && 
         /[A-Z]/.test(password) && 
         /[a-z]/.test(password) && 
         /\d/.test(password);
};

🧪 Examples

Complete Login/Register Flow

import React, { useState } from 'react';
import { useAuth, LoginForm } from '@gsarthak783/accesskit-react';

function AuthFlow() {
  const { isAuthenticated, user, logout } = useAuth();
  const [showLogin, setShowLogin] = useState(true);

  if (isAuthenticated) {
    return (
      <div>
        <h1>Welcome, {user.firstName}!</h1>
        <button onClick={logout}>Logout</button>
      </div>
    );
  }

  return (
    <div>
      <div className="auth-tabs">
        <button 
          onClick={() => setShowLogin(true)}
          className={showLogin ? 'active' : ''}
        >
          Login
        </button>
        <button 
          onClick={() => setShowLogin(false)}
          className={!showLogin ? 'active' : ''}
        >
          Register
        </button>
      </div>

      {showLogin ? (
        <LoginForm
          onSuccess={() => console.log('Logged in!')}
          showSignupLink={true}
          onSignupClick={() => setShowLogin(false)}
        />
      ) : (
        <RegisterForm onSuccess={() => setShowLogin(true)} />
      )}
    </div>
  );
}

TypeScript Support

import { useAuth } from '@gsarthak783/accesskit-react';
import type { User } from '@gsarthak783/accesskit-auth';

interface UserProfileProps {
  onUpdate?: (user: User) => void;
}

const UserProfile: React.FC<UserProfileProps> = ({ onUpdate }) => {
  const { user, updateProfile } = useAuth();

  const handleUpdate = async (data: Partial<User>) => {
    try {
      const updatedUser = await updateProfile(data);
      onUpdate?.(updatedUser);
    } catch (error) {
      console.error('Update failed:', error);
    }
  };

  return (
    <div>
      <h2>{user?.firstName} {user?.lastName}</h2>
      <button onClick={() => handleUpdate({ firstName: 'New Name' })}>
        Update Profile
      </button>
    </div>
  );
};

📞 Support

📄 License

MIT License - see LICENSE file for details.

📝 Changelog

1.2.2 (Latest)

  • Updated to use @gsarthak783/accesskit-auth v1.2.2 with critical token storage fix
  • Tokens are now properly saved during login/register

1.2.1

  • Fixed authentication persistence across page refreshes
  • Improved integration with core SDK's initialization flow
  • Better handling of loading states during auth checks

1.2.0

  • Added support for account security methods
  • Exposed updatePassword, updateEmail, and reauthenticateWithCredential via useAuth hook

Version 1.1.0

  • Simplified AuthProvider using onAuthStateChange from core SDK
  • Removed autoInitialize prop (always auto-initializes now)
  • Automatic auth state persistence across page refreshes
  • Improved TypeScript types

Version 1.0.5

  • Updated to use @gsarthak783/accesskit-auth v1.0.5

Built with ❤️ by the AccessKit Team