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

@smarthivelabs-devs/auth-react

v1.4.0

Published

SmartHive Auth React provider, hooks, and components for web applications

Readme

@smarthivelabs-devs/auth-react

React provider, hooks, and components for SmartHive Auth. Works with any React 18+ app including Next.js (App Router and Pages Router), Vite, and Create React App.


Installation

npm install @smarthivelabs-devs/auth-react @smarthivelabs-devs/auth-sdk
# or
pnpm add @smarthivelabs-devs/auth-react @smarthivelabs-devs/auth-sdk
# or
yarn add @smarthivelabs-devs/auth-react @smarthivelabs-devs/auth-sdk

@smarthivelabs-devs/auth-sdk is a required peer dependency.


Prerequisites

From your SmartHive dashboard, get:

  • projectId
  • publishableKey
  • baseUrl — the URL of your SmartHive Auth service

Setup

Wrap your app with SmartHiveAuthProvider. This provides auth state to every component in the tree.

Next.js App Router

Create a client-side provider wrapper (the SDK uses React context, which requires "use client"):

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

import { SmartHiveAuthProvider } from "@smarthivelabs-devs/auth-react";

export function Providers({ children }: { children: React.ReactNode }) {
  return (
    <SmartHiveAuthProvider
      projectId={process.env.NEXT_PUBLIC_AUTH_PROJECT_ID!}
      publishableKey={process.env.NEXT_PUBLIC_AUTH_PUBLISHABLE_KEY!}
      baseUrl={process.env.NEXT_PUBLIC_AUTH_BASE_URL!}
      redirectUri={`${process.env.NEXT_PUBLIC_APP_URL}/auth/callback`}
    >
      {children}
    </SmartHiveAuthProvider>
  );
}
// app/layout.tsx
import { Providers } from "./providers";

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

Vite / Create React App

// src/main.tsx
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import { SmartHiveAuthProvider } from "@smarthivelabs-devs/auth-react";
import App from "./App";

createRoot(document.getElementById("root")!).render(
  <StrictMode>
    <SmartHiveAuthProvider
      projectId={import.meta.env.VITE_AUTH_PROJECT_ID}
      publishableKey={import.meta.env.VITE_AUTH_PUBLISHABLE_KEY}
      baseUrl={import.meta.env.VITE_AUTH_BASE_URL}
      redirectUri={`${window.location.origin}/auth/callback`}
    >
      <App />
    </SmartHiveAuthProvider>
  </StrictMode>
);

Headless Sign-in (Custom Login Form)

No browser redirect. Call the method, get tokens. Full control of your UI.

Email + Password

import { useAuth } from "@smarthivelabs-devs/auth-react";
import { useState } from "react";

export default function LoginPage() {
  const { signIn } = useAuth();
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");
  const [error, setError] = useState("");

  async function handleSubmit(e: React.FormEvent) {
    e.preventDefault();
    try {
      await signIn.email({ email, password });
      // Session saved automatically — user is now signed in
    } catch (e: any) {
      setError(e.message);
    }
  }

  return (
    <form onSubmit={handleSubmit}>
      <input value={email} onChange={(e) => setEmail(e.target.value)} placeholder="Email" type="email" />
      <input value={password} onChange={(e) => setPassword(e.target.value)} placeholder="Password" type="password" />
      {error && <p style={{ color: "red" }}>{error}</p>}
      <button type="submit">Sign in</button>
    </form>
  );
}

Phone OTP

const { signIn } = useAuth();

// Step 1 — send the code
await signIn.phone.sendOtp({ phoneNumber: "+1234567890" });

// Step 2 — verify (returns session, user is now signed in)
await signIn.phone.verify({ phoneNumber: "+1234567890", code: "123456" });

Email OTP

const { signIn } = useAuth();

// Step 1 — send the code
await signIn.emailOtp.send({ email: "[email protected]" });

// Step 2 — verify (returns session, user is now signed in)
await signIn.emailOtp.verify({ email: "[email protected]", code: "123456" });

Magic Link

const { signIn } = useAuth();

// Sends an email — user clicks the link to sign in (no token returned here)
await signIn.magicLink.send({ email: "[email protected]" });

Headless Sign-up

const { signUp } = useAuth();

const result = await signUp.email({
  email: "[email protected]",
  password: "secret123",
  name: "Jane Doe",       // optional
});

if (result.requiresVerification) {
  // Email verification required — show "check your inbox" screen
} else {
  // Account created and signed in immediately
}

Social OAuth Sign-in (Google, Apple, GitHub, etc.)

Each provider uses your project's own credentials — the consent screen shows your app name. Configure credentials in your SmartHive dashboard under Project → OAuth Providers, then use loginSocial:

import { useAuth } from "@smarthivelabs-devs/auth-react";

export function SocialLoginButtons() {
  const { loginSocial } = useAuth();
  return (
    <div>
      <button onClick={() => loginSocial("google")}>Continue with Google</button>
      <button onClick={() => loginSocial("apple")}>Continue with Apple</button>
      <button onClick={() => loginSocial("github")}>Continue with GitHub</button>
    </div>
  );
}

Set up a callback page that your redirectUri points to. It reads access_token + refresh_token from the URL and saves the session:

// app/auth/social/callback/page.tsx
"use client";
import { useRouter } from "next/navigation";
import { SocialAuthCallback } from "@smarthivelabs-devs/auth-react";

export default function SocialCallback() {
  const router = useRouter();
  return (
    <SocialAuthCallback
      onSuccess={() => router.replace("/dashboard")}
      onError={(err) => router.replace(`/login?error=${err.message}`)}
      fallback={<p>Signing you in...</p>}
    />
  );
}

Pass the callback URL when initiating:

loginSocial("google", { redirectUri: "https://myapp.com/auth/social/callback" });

Supported providers: google · apple · github · facebook · twitter · linkedin · microsoft · discord · spotify · twitch · reddit · gitlab · slack · notion · zoom · figma


OAuth Redirect Sign-in (SmartHive hosted page)

The original PKCE flow — redirects to the SmartHive hosted login page and back.

import { useAuth } from "@smarthivelabs-devs/auth-react";

export function LoginButton() {
  const { login } = useAuth();
  return <button onClick={() => login()}>Sign in with SmartHive</button>;
}

Set up a callback page to handle the redirect back:

// app/auth/callback/page.tsx
"use client";
import { useRouter } from "next/navigation";
import { AuthCallback } from "@smarthivelabs-devs/auth-react";

export default function Callback() {
  const router = useRouter();
  return (
    <AuthCallback
      onSuccess={() => router.replace("/dashboard")}
      onError={() => router.replace("/login")}
      fallback={<div>Signing you in...</div>}
    />
  );
}

Provider Props

SmartHiveAuthProvider accepts all SmartHiveAuthConfig fields as props:

| Prop | Type | Required | Description | |---|---|---|---| | projectId | string | Yes | Your SmartHive project ID | | publishableKey | string | Yes | Your publishable (public) key | | baseUrl | string | Yes | URL of your SmartHive Auth service | | authDomain | string | No | Custom branded auth domain for login flows | | redirectUri | string | No | Default OAuth callback URL | | children | ReactNode | Yes | Your app tree |


Hooks

useAuth()

Returns the full auth context. Use this when you need multiple values at once.

import { useAuth } from "@smarthivelabs-devs/auth-react";

function MyComponent() {
  const {
    client,        // SmartHiveAuthClient — the raw SDK client
    session,       // AuthSession | null
    isLoaded,      // true once the initial session check is done
    isSignedIn,    // boolean
    login,         // PKCE redirect sign-in (SmartHive hosted page)
    loginSocial,   // social OAuth redirect (Google, Apple, GitHub, etc.)
    logout,        // () => Promise<void>
    refreshSession, // () => Promise<void>
    getAuthorizationHeader, // () => Promise<Record<string, string>>
    authFetch,     // fetch wrapper that adds the Bearer token
    signIn,        // headless sign-in methods (no redirect)
    signUp,        // headless sign-up methods (no redirect)
  } = useAuth();

  if (!isLoaded) return <p>Loading...</p>;

  return isSignedIn ? (
    <button onClick={logout}>Sign out</button>
  ) : (
    <button onClick={() => login()}>Sign in</button>
  );
}

useSession()

Returns the current AuthSession or null.

import { useSession } from "@smarthivelabs-devs/auth-react";

function TokenDisplay() {
  const session = useSession();
  if (!session) return null;
  return <pre>{session.accessToken}</pre>;
}

useUser()

Returns the current user object from the session, or null.

import { useUser } from "@smarthivelabs-devs/auth-react";

function UserGreeting() {
  const user = useUser();
  if (!user) return null;
  return <p>Welcome, {(user as any).email}</p>;
}

useIsLoaded()

Returns true once the initial session check has finished. Use this to avoid flash of unauthenticated content.

import { useIsLoaded } from "@smarthivelabs-devs/auth-react";

function App() {
  const isLoaded = useIsLoaded();
  if (!isLoaded) return <FullPageSpinner />;
  return <Router />;
}

useIsSignedIn()

Returns true if signed in, false if signed out, or null while still loading.

import { useIsSignedIn } from "@smarthivelabs-devs/auth-react";

function NavBar() {
  const isSignedIn = useIsSignedIn();

  if (isSignedIn === null) return <NavSkeleton />;
  return isSignedIn ? <UserMenu /> : <LoginButton />;
}

useAuthFetch()

Returns an authenticated fetch function that automatically includes the Bearer token on every request.

import { useAuthFetch } from "@smarthivelabs-devs/auth-react";

function DataLoader() {
  const authFetch = useAuthFetch();

  async function loadData() {
    const res = await authFetch("/api/protected-data");
    const data = await res.json();
    console.log(data);
  }

  return <button onClick={loadData}>Load data</button>;
}

useAuthorizationHeader()

Returns a function that resolves to { authorization: "Bearer <token>" }. Useful for manually constructing requests or passing to third-party clients.

import { useAuthorizationHeader } from "@smarthivelabs-devs/auth-react";

function UploadButton() {
  const getAuthorizationHeader = useAuthorizationHeader();

  async function upload(file: File) {
    const headers = await getAuthorizationHeader();
    const formData = new FormData();
    formData.append("file", file);

    await fetch("/api/upload", { method: "POST", headers, body: formData });
  }

  return <input type="file" onChange={(e) => e.target.files && upload(e.target.files[0])} />;
}

Render Helpers

Conditional rendering components based on auth state. These are ergonomic wrappers that also wait for isLoaded.

<SignedIn>

Renders children only when auth has loaded and a session exists.

import { SignedIn } from "@smarthivelabs-devs/auth-react";

<SignedIn>
  <UserDashboard />
</SignedIn>

<SignedOut>

Renders children only when auth has loaded and there is no session.

import { SignedOut } from "@smarthivelabs-devs/auth-react";

<SignedOut>
  <LandingPage />
</SignedOut>

<AuthLoading>

Renders children while the initial session check is in progress.

import { AuthLoading } from "@smarthivelabs-devs/auth-react";

<AuthLoading>
  <FullPageSpinner />
</AuthLoading>

Combined Example

import { SignedIn, SignedOut, AuthLoading } from "@smarthivelabs-devs/auth-react";

export default function HomePage() {
  return (
    <>
      <AuthLoading>
        <p>Checking authentication...</p>
      </AuthLoading>
      <SignedIn>
        <Dashboard />
      </SignedIn>
      <SignedOut>
        <LandingPage />
      </SignedOut>
    </>
  );
}

<AuthCallback> Component

Handles the OAuth redirect on your callback page. Automatically exchanges the code for tokens and calls onSuccess when done.

// app/auth/callback/page.tsx  (Next.js App Router)
"use client";

import { useRouter } from "next/navigation";
import { AuthCallback } from "@smarthivelabs-devs/auth-react";

export default function CallbackPage() {
  const router = useRouter();

  return (
    <AuthCallback
      onSuccess={() => router.replace("/dashboard")}
      onError={(err) => {
        console.error("Auth error:", err.message);
        router.replace("/login?error=auth_failed");
      }}
      fallback={<p>Completing sign in...</p>}
    />
  );
}

AuthCallback Props

| Prop | Type | Required | Description | |---|---|---|---| | onSuccess | (session: AuthSession) => void | Yes | Called after successful token exchange | | onError | (error: Error) => void | No | Called if the exchange fails | | fallback | ReactNode | No | Shown while the exchange is in progress |


<SocialAuthCallback> Component

Handles the social OAuth redirect on your callback page. Reads access_token + refresh_token from the URL, saves the session, and calls onSuccess. Use this on whatever page your social redirectUri points to.

// app/auth/social/callback/page.tsx  (Next.js App Router)
"use client";

import { useRouter } from "next/navigation";
import { SocialAuthCallback } from "@smarthivelabs-devs/auth-react";

export default function SocialCallbackPage() {
  const router = useRouter();

  return (
    <SocialAuthCallback
      onSuccess={() => router.replace("/dashboard")}
      onError={(err) => {
        console.error("Social auth error:", err.message);
        router.replace("/login?error=social_auth_failed");
      }}
      fallback={<p>Completing sign in...</p>}
    />
  );
}

SocialAuthCallback Props

| Prop | Type | Required | Description | |---|---|---|---| | onSuccess | (session: AuthSession) => void | Yes | Called after tokens are parsed and session saved | | onError | (error: Error) => void | No | Called if the provider returned an error or token is missing | | fallback | ReactNode | No | Shown while parsing the callback URL |


Route Protection

Next.js Middleware (App Router)

Protect routes server-side using @smarthivelabs-devs/auth-server:

// middleware.ts
import { createNextAuthMiddleware } from "@smarthivelabs-devs/auth-server";

const { nextAuthMiddleware } = createNextAuthMiddleware({
  issuer: process.env.AUTH_ISSUER!,
  projectId: process.env.AUTH_PROJECT_ID,
});

export async function middleware(request: Request) {
  const { auth, error } = await nextAuthMiddleware(request);
  if (error) {
    return Response.redirect(new URL("/login", request.url));
  }
  // auth.userId is available
}

export const config = {
  matcher: ["/dashboard/:path*", "/api/protected/:path*"],
};

Client-side Guard (React)

"use client";

import { useIsSignedIn, useIsLoaded } from "@smarthivelabs-devs/auth-react";
import { useRouter } from "next/navigation";
import { useEffect } from "react";

export function ProtectedPage({ children }: { children: React.ReactNode }) {
  const isLoaded = useIsLoaded();
  const isSignedIn = useIsSignedIn();
  const router = useRouter();

  useEffect(() => {
    if (isLoaded && !isSignedIn) {
      router.replace("/login");
    }
  }, [isLoaded, isSignedIn, router]);

  if (!isLoaded) return <FullPageSpinner />;
  if (!isSignedIn) return null;
  return <>{children}</>;
}

Sign-out

const { logout } = useAuth();

// Clears localStorage + invalidates session on the server
await logout();

Full Next.js App Router Example

app/
├── layout.tsx              ← SmartHiveAuthProvider here
├── page.tsx                ← uses SignedIn / SignedOut
├── login/
│   └── page.tsx            ← custom login form using signIn.*
├── auth/
│   └── callback/
│       └── page.tsx        ← AuthCallback (OAuth redirect only)
└── dashboard/
    └── page.tsx            ← protected page
// app/login/page.tsx — custom form, no redirect
"use client";
import { useAuth } from "@smarthivelabs-devs/auth-react";
import { useState } from "react";

export default function LoginPage() {
  const { signIn } = useAuth();
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");
  const [error, setError] = useState("");

  async function handleSubmit(e: React.FormEvent) {
    e.preventDefault();
    try {
      await signIn.email({ email, password });
    } catch (e: any) {
      setError(e.message ?? "Sign in failed.");
    }
  }

  return (
    <form onSubmit={handleSubmit}>
      <input value={email} onChange={(e) => setEmail(e.target.value)} type="email" placeholder="Email" />
      <input value={password} onChange={(e) => setPassword(e.target.value)} type="password" placeholder="Password" />
      {error && <p style={{ color: "red" }}>{error}</p>}
      <button type="submit">Sign in</button>
    </form>
  );
}
// app/dashboard/page.tsx
"use client";
import { useAuth, SignedIn } from "@smarthivelabs-devs/auth-react";

export default function Dashboard() {
  const { logout, authFetch } = useAuth();

  async function fetchProfile() {
    const res = await authFetch("/api/profile");
    console.log(await res.json());
  }

  return (
    <SignedIn>
      <h1>Dashboard</h1>
      <button onClick={fetchProfile}>Load profile</button>
      <button onClick={logout}>Sign out</button>
    </SignedIn>
  );
}

Environment Variables

# .env.local (Next.js)
NEXT_PUBLIC_AUTH_PROJECT_ID=proj_abc123
NEXT_PUBLIC_AUTH_PUBLISHABLE_KEY=pk_live_abc123
NEXT_PUBLIC_AUTH_BASE_URL=https://auth.myapp.com
NEXT_PUBLIC_APP_URL=https://myapp.com
# .env (Vite)
VITE_AUTH_PROJECT_ID=proj_abc123
VITE_AUTH_PUBLISHABLE_KEY=pk_live_abc123
VITE_AUTH_BASE_URL=https://auth.myapp.com

TypeScript Types

import type {
  SmartHiveAuthProviderProps,
  SocialProvider,          // "google" | "apple" | "github" | ...
} from "@smarthivelabs-devs/auth-react";

import type {
  AuthSession,
  HeadlessClient,
  HeadlessSignInResult,
  HeadlessSignUpResult,
  SmartHiveAuthClient,
  SmartHiveAuthConfig,
} from "@smarthivelabs-devs/auth-sdk";

Related Packages

| Package | Use case | |---|---| | @smarthivelabs-devs/auth-sdk | Core SDK — framework-agnostic | | @smarthivelabs-devs/auth-expo | React Native / Expo apps | | @smarthivelabs-devs/auth-server | Express / Next.js server-side JWT verification |


License

MIT © SmartHive Labs