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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@hashpass/connect

v3.1.13

Published

HashConnect SDK v3 - React-only authentication and wallet integration for web applications

Readme

HashConnect SDK v3

React-only authentication and wallet integration for web applications

npm version License: MIT

HashConnect SDK provides a simple and secure way to integrate HASH Pass authentication into your React applications. It offers seamless wallet connection, token management, and user authentication through QR code scanning.

🎉 What's New in v3.1.0

Enhanced Developer Experience - Four new features for better control:

  • isInitialized state - Proper loading states without setTimeout workarounds
  • Non-React token access - Use SDK in API interceptors and utility functions
  • Auth state callbacks - React to connection changes for routing and analytics
  • Consolidated logging - Integrate SDK logs with your logging system

See CHANGELOG.md for full details.

🎉 What's New in v3.0.0

React-Only Architecture - Complete rewrite for modern React applications:

  • Pure React - No more window.HASHConnect or CustomEvents
  • Single source of truth - State managed entirely in React Context
  • SSR/Next.js support - All hooks are SSR-safe with 'use client' directives
  • TypeScript-first - Full type safety with exported types
  • Smaller bundle - Removed duplicate state management code
  • Better DX - Simple Provider + Hook pattern

⚠️ Breaking Changes: v3 is React-only. See MIGRATION_GUIDE.md for upgrading from v2.

Features

Easy Integration - Add authentication to your app in minutes
🔒 Secure - Built-in JWT token management and automatic refresh
📱 QR Code Authentication - Seamless mobile wallet connection
Real-time - Powered by Pusher for instant connection updates
🎨 Customizable - Style the UI to match your brand
♻️ Session Persistence - Automatic reconnection on page refresh
🔄 Cross-tab Sync - Multiple tabs stay in sync automatically
⚛️ React Native - Built specifically for React applications
🛡️ Production Ready - Battle-tested in production environments

Requirements

  • React 17.0.0 or higher
  • Node.js 16.0.0 or higher

Installation

npm install @hashpass/connect
yarn add @hashpass/connect
pnpm add @hashpass/connect

Quick Start

1. Wrap your app with the Provider

// App.tsx
import { HashConnectProvider } from "@hashpass/connect";

function App() {
  return (
    <HashConnectProvider disclaimer="By connecting, you agree to our terms.">
      <MyApp />
    </HashConnectProvider>
  );
}

2. Use the hook in your components

// MyComponent.tsx
import { useHashConnect } from "@hashpass/connect";

function MyComponent() {
  const {
    isInitialized, // NEW in v3.1.0
    isConnected,
    userAddress,
    connect,
    disconnect,
    getToken,
    isLoading,
    error,
  } = useHashConnect();

  // Wait for SDK to check localStorage before showing UI
  if (!isInitialized) {
    return <div>Loading...</div>;
  }

  const handleApiCall = async () => {
    const token = await getToken();
    if (token) {
      const response = await fetch("https://api.example.com/data", {
        headers: { Authorization: `Bearer ${token}` },
      });
    }
  };

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

  if (isConnected) {
    return (
      <div>
        <p>Connected: {userAddress}</p>
        <button onClick={handleApiCall}>Make API Call</button>
        <button onClick={disconnect}>Disconnect</button>
      </div>
    );
  }

  return (
    <div>
      <button onClick={connect}>Connect with HASH Pass</button>
      {error && <p className="error">{error}</p>}
    </div>
  );
}

That's it! The modal, QR code, and connection management are all handled automatically.

API Reference

HashConnectProvider

The context provider that manages all authentication state.

<HashConnectProvider
  debug={false} // Enable debug logging
  disclaimer="Your terms here" // Text shown in modal
  config={{
    // Optional custom config
    pusherKey: "your-key",
    pusherCluster: "us2",
    authEndpoint: "https://api.example.com",
  }}
  onAuthStateChange={(event) => {
    // NEW in v3.1.0: React to auth changes
    if (event.type === "disconnected") {
      router.push("/login");
    }
  }}
  onLog={(event) => {
    // NEW in v3.1.0: Integrate with your logging system
    logger.debug("[HashConnect]", event.message);
  }}
>
  {children}
</HashConnectProvider>

useHashConnect()

The main hook for accessing authentication state and methods.

const {
  // State
  isInitialized, // boolean - Whether SDK finished initial localStorage check (v3.1.0+)
  isConnected, // boolean - Whether user is connected
  isLoading, // boolean - Whether connection is in progress
  isModalOpen, // boolean - Whether modal is visible
  userAddress, // string | null - Connected wallet address
  clubId, // string | null - User's club ID
  clubName, // string | null - User's club name
  error, // string | null - Current error message
  connectionState, // string - Pusher connection state

  // Methods
  connect, // () => Promise<void> - Start connection flow
  disconnect, // () => void - Disconnect and clear session
  getToken, // () => Promise<string | null> - Get valid access token
  getClubId, // () => string | null - Get club ID
  getClubName, // () => string | null - Get club name
  makeAuthRequest, // <T>(url, options?) => Promise<T> - Make authenticated request
} = useHashConnect();

makeAuthRequest

Helper for making authenticated API calls:

const { makeAuthRequest } = useHashConnect();

// Token is automatically included in Authorization header
const data = await makeAuthRequest<{ items: Item[] }>(
  "https://api.example.com/items"
);

// With custom options
const result = await makeAuthRequest<{ success: boolean }>(
  "https://api.example.com/action",
  {
    method: "POST",
    body: JSON.stringify({ action: "do-something" }),
  }
);

Next.js Integration

The SDK is fully compatible with Next.js (both Pages Router and App Router).

App Router (Next.js 13+)

// app/providers.tsx
"use client";

import { HashConnectProvider } from "@hashpass/connect";

export function Providers({ children }: { children: React.ReactNode }) {
  return (
    <HashConnectProvider disclaimer="By connecting...">
      {children}
    </HashConnectProvider>
  );
}

// app/layout.tsx
import { Providers } from "./providers";

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html>
      <body>
        <Providers>{children}</Providers>
      </body>
    </html>
  );
}

Pages Router

// pages/_app.tsx
import { HashConnectProvider } from "@hashpass/connect";

export default function App({ Component, pageProps }) {
  return (
    <HashConnectProvider disclaimer="By connecting...">
      <Component {...pageProps} />
    </HashConnectProvider>
  );
}

Advanced Usage

New in v3.1.0

Proper Initialization Handling

function App() {
  const { isInitialized, isConnected } = useHashConnect();

  // Show spinner while SDK checks for existing session
  if (!isInitialized) {
    return <LoadingSpinner />;
  }

  // Now we know for sure if user is connected or not
  if (!isConnected) {
    return <LoginScreen />;
  }

  return <Dashboard />;
}

Non-React Token Access

Use SDK functions in API interceptors and utility code:

// api.ts (non-React file)
import { getAccessToken, getAuthState } from "@hashpass/connect";

// In an API interceptor
api.interceptors.request.use(async (config) => {
  const token = await getAccessToken();
  if (token) {
    config.headers.Authorization = `Bearer ${token}`;
  }
  return config;
});

// Quick synchronous check
function checkAuth() {
  const { isAuthenticated, userAddress } = getAuthState();
  return isAuthenticated;
}

Auth State Change Callbacks

React to authentication events:

<HashConnectProvider
  onAuthStateChange={(event) => {
    console.log("Auth event:", event.type);

    if (event.type === "connected") {
      analytics.track("user_connected", { address: event.userAddress });
      router.push("/dashboard");
    }

    if (event.type === "disconnected") {
      analytics.track("user_disconnected");
      router.push("/login");
    }

    if (event.type === "refreshed") {
      console.log("Token refreshed silently");
    }
  }}
>
  <App />
</HashConnectProvider>

Integrated Logging

Send SDK logs to your logging system:

import { logger } from "./logger"; // Your app's logger

<HashConnectProvider
  onLog={(event) => {
    logger.debug({
      source: "hashconnect",
      message: event.message,
      timestamp: event.timestamp,
    });
  }}
>
  <App />
</HashConnectProvider>;

Note: When onLog is provided, console logging is automatically suppressed (even if debug={true}).

Custom Components

Export individual UI components for custom layouts:

import {
  HashConnectModal,
  QRCodeDisplay,
  ConnectionStatusIndicator
} from '@hashpass/connect';

// Use components individually
<QRCodeDisplay value="hc:session123" size={200} />
<ConnectionStatusIndicator status="connected" />

Core Hooks

For advanced use cases, access the underlying hooks:

import {
  useStorage,
  usePusher,
  useTokenRefresh,
  useScriptLoader,
} from "@hashpass/connect";

// SSR-safe localStorage with fallback
const storage = useStorage({ prefix: "myapp:" });

// Pusher connection management
const { client, connectionState, subscribe } = usePusher({
  key: "your-key",
  cluster: "us2",
});

Styling

The SDK uses specific CSS class names and IDs that you can override:

/* Modal overlay */
#hash-connect-modal {
  backdrop-filter: blur(4px);
}

/* Modal content */
#hash-connect-modal-content {
  border-radius: 16px;
  box-shadow: 0 10px 40px rgba(0, 0, 0, 0.2);
}

/* QR Code container */
#hash-connect-qrcode {
  padding: 16px;
}

/* Status indicator */
#hash-connect-status-indicator {
  font-size: 14px;
}

/* Status dot colors */
.status-connected {
  background: #10b981;
}
.status-connecting {
  background: #f59e0b;
}
.status-disconnected {
  background: #ef4444;
}

Local Storage

Session data is stored with the hc: prefix:

  • hc:sessionId - Current session identifier
  • hc:address - Connected user address
  • hc:accessToken - JWT access token
  • hc:refreshToken - JWT refresh token
  • hc:signature - User signature
  • hc:clubId - User's club ID
  • hc:clubName - User's club name

TypeScript

Full TypeScript support with exported types:

import type {
  AuthState,
  HashConnectContextType,
  UseHashConnectReturn,
  ConnectionState,
} from "@hashpass/connect";

Building from Source

# Install dependencies
npm install

# Build for production
npm run build

# Type check
npm run typecheck

Browser Support

  • Chrome/Edge: Latest 2 versions
  • Firefox: Latest 2 versions
  • Safari: Latest 2 versions

Security

  • JWT tokens stored in localStorage
  • Automatic token refresh before expiration
  • Secure Pusher channel authentication
  • Session cleanup on disconnect
  • No sensitive data exposed to global scope

Troubleshooting

"useHashConnect must be used within a HashConnectProvider"

Ensure your component is wrapped with the provider:

<HashConnectProvider>
  <YourComponent /> {/* useHashConnect works here */}
</HashConnectProvider>

Connection not persisting

The SDK automatically restores sessions from localStorage. If issues persist:

// Clear session manually
localStorage.removeItem("hc:accessToken");
localStorage.removeItem("hc:refreshToken");
localStorage.removeItem("hc:address");

Pusher connection errors (Error 1006)

If you're seeing Pusher WebSocket errors, this is typically normal and recoverable. The SDK automatically handles reconnection with exponential backoff. See Pusher Error Handling Guide for detailed information about error codes and handling.

Next.js hydration errors

Ensure the provider is marked as a client component:

"use client";
import { HashConnectProvider } from "@hashpass/connect";

Documentation

Migration from v2

See MIGRATION_GUIDE.md for detailed upgrade instructions.

Contributing

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

License

MIT © BitLabs

Support