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

@userspace-auth/react

v1.10.7

Published

React SDK for Userspace Auth, session state, tokens, and auth guards

Downloads

1,495

Readme

Userspace React SDK (@userspace-auth/react)

Session state, tokens, and auth guards for a React app backed by Userspace.

Sign-in itself happens on your Userspace deployment's hosted pages. This package tells your app who is signed in and hands you a token to call your own backend with.

Install

npm i @userspace-auth/react

Requires React 18 or 19, declared as peer dependencies. The package has no runtime dependencies of its own.

ESM only. It works in Vite, Next.js, Remix, Parcel, esbuild, webpack 5, and anything else that resolves import. A CommonJS-only setup, for example an older Jest config without ESM support, cannot require() it.

Quick start

Wrap your app once:

import { UserspaceProvider } from '@userspace-auth/react'

export function App() {
  return (
    <UserspaceProvider baseUrl="https://acme.userspace.tech" clientId="your-client-id">
      <Dashboard />
    </UserspaceProvider>
  )
}

Then read the session anywhere beneath it:

import { useSession, SignedIn, SignedOut } from '@userspace-auth/react'

function Dashboard() {
  const { session, isLoading } = useSession()

  if (isLoading) return <p>Loading…</p>

  return (
    <>
      <SignedIn>
        <p>Signed in as {session?.identity?.email}</p>
      </SignedIn>
      <SignedOut>
        <a href="https://acme.userspace.tech/sign-in">Sign in</a>
      </SignedOut>
    </>
  )
}

Calling your backend

getToken() returns a JWT your backend can verify locally. Send it as a bearer token:

function Profile() {
  const { getToken } = useSession()

  const load = async () => {
    const token = await getToken()
    if (!token) return // signed out

    const res = await fetch('https://api.example.com/me', {
      headers: { Authorization: `Bearer ${token}` },
    })
    return res.json()
  }

  // …
}

From your api layer, outside React

If your data layer is a plain module of functions over one shared fetcher, import getToken directly instead of threading a hook through it. It is the same function useSession() returns, so the two cannot drift:

import { getToken } from '@userspace-auth/react'

async function authorized(path: string, init: RequestInit = {}) {
  const token = await getToken()
  const headers = new Headers(init.headers)
  if (token) headers.set('Authorization', `Bearer ${token}`)
  return fetch(`https://api.example.com${path}`, { ...init, headers })
}

export const fetchUsers = () => authorized('/users').then((r) => r.json())

Called before <UserspaceProvider> has rendered, it waits for the provider to configure the SDK rather than firing at a half-configured base URL. The provider stays the only place configuration happens. If the provider never mounts, the call warns after a few seconds instead of hanging silently.

On the backend, verify it with the Userspace SDK for your stack, for Go that is github.com/userspace-auth/sdk-go. Any JOSE library works too: the token is a standard RS256 JWT signed by keys published at https://<your-deployment>/.well-known/jwks.json.

Never send this token anywhere but your own backend. It also authenticates against the Userspace API as that user.

API

<UserspaceProvider>

| Prop | Type | Meaning | | --------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------ | | baseUrl | string | Your deployment's base URL, e.g. https://acme.userspace.tech. | | clientId | string | Your client ID. The same one your backend is configured with. | | webcomponents | boolean | Registers the x-* custom elements (<x-signed-in>, <x-trigger>, ...) so you can use them in JSX out of the box. Off by default. | | preload | boolean | Warms the settings popup bundle at browser idle time, so the first openSettings() opens without a download. Off by default. | | autoLogin | boolean | Redirects signed-out visitors to the hosted sign-in page, with redirect_uri pointing back at the current URL. Off by default. | | children | ReactNode | Your app. |

Must wrap every component that uses this package. Hooks throw a clear error outside it rather than returning an empty session.

webcomponents loads the element bundle lazily: with the flag off, none of it is downloaded. The tags are typed for TSX either way.

autoLogin probes the session once on mount, sharing the request useSession() makes, and only redirects when the probe comes back signed out. A transport error is an unknown state, not a signed-out one, and never redirects. Use it for apps with no public pages; apps with a signed-out state should render <SignedOut> instead.

useSession()

const { session, getToken, isLoading, error } = useSession()

| Field | Type | Meaning | | ----------- | ------------------------------- | ----------------------------------------------------------------------------------------------- | | session | SessionData \| null | The session, or null while loading or signed out. | | getToken | () => Promise<string \| null> | A JWT for your backend, or null if signed out. Rejects on transport errors. | | isLoading | boolean | True until the first load settles. | | error | unknown | A real failure. Being signed out is not an error, it is session: null with error: null. |

session.identity.id is the stable user id. Key your own data on it, never on session.session.id, which changes on every sign-in.

getToken()

import { getToken } from '@userspace-auth/react'

() => Promise<string | null>, the same function useSession() returns, importable without a hook so a module-scope fetcher can use it. Resolves null when signed out, rejects on transport errors, and waits for <UserspaceProvider> to configure the SDK if it is called first. Client-side only, see Next.js for why.

openSettings()

import { openSettings } from '@userspace-auth/react'

;<MenuItem onClick={() => openSettings()}>Account settings</MenuItem>

Opens the Userspace settings popup from your own components — a profile menu item, a toolbar button, anything clickable. One popup instance serves every caller. Works with or without the webcomponents flag: the popup code loads lazily on first call. Pass preload to the provider to move that download (and the SDK's config load) to idle time, so the first click opens instantly. The popup opens immediately and loads its content in place; without an active session it closes again with a console warning, so keep the control inside <SignedIn>.

signIn()

import { signIn } from '@userspace-auth/react'

;<Button onClick={() => signIn()}>Sign in</Button>

Leaves for the hosted sign-in page, carrying redirect_uri back to the current URL so the user returns where they were after signing in. The imperative counterpart of the autoLogin flag: same navigation, on a click instead of on every signed-out visit. Waits for <UserspaceProvider> to configure the SDK if it is called first, like getToken().

signOut()

import { signOut } from '@userspace-auth/react'

;<MenuItem onClick={() => signOut()}>Sign out</MenuItem>

Signs the user out and navigates to the hosted sign-in page — or, with signOut({ redirectUri }), to an absolute URL whose origin is on the tenant's allowlist; the server validates it and untrusted targets fall back to sign-in. Sign-out ends every session in this browser, not only the current one: the server terminates the whole cookie-scoped session, so other tabs sign out too. Waits for <UserspaceProvider> to configure the SDK if it is called first, like getToken().

<SignedIn> / <SignedOut>

Render their children only in the matching state, and nothing at all while loading, so neither flashes before the session is known. An errored session counts as signed out: SignedIn never renders on an unknown state.

Types

SessionData, SessionInfo, UserspaceUser, EmailAddress, UseSessionResult, UserspaceProviderProps, GuardProps, and UserspaceTagName are exported. The package ships its own declarations, so strict: true works with no @types/* package and no any.

Caching behaviour

The session is fetched once per page load and held. Every component calling useSession() shares that one request, including several mounting at once on a cold cache.

Deliberately not included: revalidation on window focus or reconnect, polling, and manual mutation. If you need the session re-read after an action that changes it, reload the page or lift that state into your own store. This is a smaller contract than a general data-fetching library on purpose, it keeps the package free of runtime dependencies, which is why installing it cannot conflict with whatever data layer you already use.

Next.js

The bundle carries a 'use client' directive, so importing it from an App Router server component works without your adding one. Components using useSession are client components like any other hook consumer.

Server rendering is unaffected: client components are prerendered and hydrated as usual, and this package renders a defined loading state on the server.

What the directive does rule out is calling getToken from a server component, a server action, or a route handler, and that is deliberate rather than an oversight. The token cache and the configured base URL are module singletons, so in a long-lived server process one request's token would sit in the same cache the next request reads. Serving tokens server-side needs per-request identity threaded through the call, which is a different contract, not a second build of this one. Use this package from the client, and have your own server read whatever session your backend already trusts.

License

MIT, see LICENSE.