SUPER EARLY WIP — USE AT YOUR OWN RISK
shoo
GitHubCOMING SOON
API Reference

@shoojs/react

React hooks and Convex adapter for Shoo authentication

Install

bun add @shoojs/react

Peer dependency: react >= 18.


useShooAuth(options)

The primary React hook for Shoo authentication.

import { useShooAuth } from "@shoojs/react";

function App() {
  const {
    identity,
    claims,
    loading,
    error,
    signIn,
    handleCallback,
    refreshIdentity,
    clearIdentity,
    authClient,
  } = useShooAuth();
}

Options

Accepts all ShooAuthOptions plus:

OptionTypeDefaultDescription
autoHandleCallbackbooleantrueAutomatically exchange the callback code on mount
autoSessionMonitorbooleantrueAutomatically run background session/revocation checks
sessionMonitorIntervalMsnumber60000Background check interval in milliseconds

Return value

PropertyTypeDescription
identityShooIdentityCurrent identity state (userId, token, etc.)
claimsIdentityClaims | nullDecoded (unverified) token claims for display
sessionState"unknown" | "active" | "login_required"Last known Shoo session-check status
loadingbooleantrue while initializing and handling callback
errorstring | nullError message if initialization failed
signIn(params?) => Promise<void>Start the sign-in flow. Accepts StartSignInOptions.
handleCallback(params?) => Promise<TokenResponse | null>Manually handle callback (if autoHandleCallback is false)
checkSession() => Promise<SessionCheckResult>Explicitly validate token/session against Shoo
refreshIdentity() => voidRe-read identity from localStorage
clearIdentity() => voidSign out — clears localStorage and resets state
authClientShooAuthClient | nullThe underlying @shoojs/auth client instance

Behavior

On mount, the hook:

  1. Creates a ShooAuthClient (only in the browser — SSR-safe)
  2. If autoHandleCallback is true, calls handleCallback() to exchange any pending auth code
  3. Reads the persisted identity from localStorage
  4. If autoSessionMonitor is enabled and a token is present, starts periodic checkSession() polling
  5. Sets loading to false

The hook is safe for server-side rendering — it returns { userId: null } on the server and initializes in the browser after hydration.

Example

Profile.tsx
import { useShooAuth } from "@shoojs/react";

export function Profile() {
  const { identity, claims, loading, signIn, clearIdentity } = useShooAuth();

  if (loading) return <p>Loading…</p>;

  if (!identity.userId) {
    return (
      <div>
        <button onClick={() => signIn()}>Sign in</button>
        <button onClick={() => signIn({ requestPii: true })}>
          Sign in with profile
        </button>
      </div>
    );
  }

  return (
    <div>
      <p>ID: {identity.userId}</p>
      {claims?.email && <p>Email: {claims.email}</p>}
      {claims?.name && <p>Name: {claims.name}</p>}
      <button onClick={clearIdentity}>Sign out</button>
    </div>
  );
}

createShooConvexAuth(options)

Creates a Convex-compatible auth adapter. Call this once at module scope, then pass the returned useAuth to ConvexProviderWithAuth.

shoo.ts
import { createShooConvexAuth } from "@shoojs/react";

export const { useAuth, signIn, signOut } = createShooConvexAuth({
  shooBaseUrl: "https://shoo.dev",
  callbackPath: "/shoo/callback",
});

Options

Accepts all ShooAuthOptions.

Return value

PropertyTypeDescription
useAuth() => { isLoading, isAuthenticated, fetchAccessToken }Hook for ConvexProviderWithAuth
signIn(opts?: StartSignInOptions) => Promise<void>Start sign-in flow
signOut() => voidClear identity and reload the page

useAuth() return value

PropertyTypeDescription
isLoadingbooleantrue while handling callback
isAuthenticatedbooleantrue if identity exists
fetchAccessToken(opts) => Promise<string | null>Returns the id_token for Convex

Usage with ConvexProviderWithAuth

main.tsx
import { ConvexProviderWithAuth, ConvexReactClient } from "convex/react";
import { useAuth } from "./shoo";

const convex = new ConvexReactClient(import.meta.env.VITE_CONVEX_URL);

export function Providers({ children }: { children: React.ReactNode }) {
  return (
    <ConvexProviderWithAuth client={convex} useAuth={useAuth}>
      {children}
    </ConvexProviderWithAuth>
  );
}

Re-exports

The package re-exports these from @shoojs/auth for convenience:

import {
  createShooAuth,
  decodeIdentityClaims,
} from "@shoojs/react";

import type {
  HandleCallbackOptions,
  ShooAuthClient,
  ShooAuthOptions,
  ShooIdentity,
  StartSignInOptions,
  TokenResponse,
} from "@shoojs/react";