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/userspace-js

v1.10.8

Published

Readme

Userspace JS SDK (@userspace-auth/userspace-js)

Auth elements and session tokens for any web page, with no framework required.

Sign-in itself happens on your Userspace deployment's hosted pages. This package drops auth UI into a page and hands you a token to call your own backend with.

Using React? Reach for @userspace-auth/react instead. It publishes the same token contract with hooks and guards on top.

Install

Embed it directly, and configure it from the script tag:

<script
  type="module"
  src="https://unpkg.com/@userspace-auth/userspace-js"
  data-base-url="https://acme.userspace.tech"
></script>

Or install and configure it yourself:

npm i @userspace-auth/userspace-js
import { configureUserspace } from '@userspace-auth/userspace-js'

await configureUserspace({
  baseUrl: 'https://acme.userspace.tech',
})

Configuring is what registers the custom elements, so nothing renders until it has run. Both forms also expose the API on window.Userspace, for a page that cannot use modules.

The script tag reads data-base-url and data-auto-login. The boolean attribute counts true, on, and 1 as on.

Type declarations ship with the package (userspace.d.ts), so an editor sees the full surface from a plain npm install, including the strike-through on the deprecated fetchToken.

Calling your backend

getToken() returns a JWT your backend can verify locally, or null when nobody is signed in. Send it as a bearer token:

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

async function loadProfile() {
  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()
}

Being signed out is a value, not an error. getToken() rejects only when something actually failed, such as the network or a broken response, so a catch here means a real problem rather than an anonymous visitor. Tokens refresh themselves: each call returns a cached token until it expires and fetches a new one after that.

One gap to know about: nothing evicts a cached token when a user signs out, so a token issued before sign-out keeps resolving here until it expires.

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

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.

fetchToken() is deprecated

fetchToken() still works and is removed in 2.0.0. It returns the raw { token, ... } response and throws on a 401, so being signed out arrives as an error rather than as a value. That disagreed with the React SDK, which has always returned null, and code written against one mishandled the other in exactly that case.

// before
try {
  const { token } = await fetchToken()
} catch (err) {
  /* signed out, or a real failure, indistinguishable without inspecting err */
}

// after
const token = await getToken() // null when signed out

Elements

Configuring registers fourteen custom elements, including <x-signed-in> and <x-signed-out> to show content by auth state, <x-signin-button> and <x-signout-button>, and <x-profile-settings>. Every element accepts theme and primary attributes.

<x-signed-in>
  <p>You are signed in.</p>
  <x-signout-button></x-signout-button>
</x-signed-in>

<x-signed-out>
  <x-signin-button primary="emerald"></x-signin-button>
</x-signed-out>

<x-signin-button> returns the visitor to the page they clicked it on. Give it a redirect-uri to send them somewhere else instead, which is what a marketing page handing off to your app wants:

<x-signin-button redirect-uri="https://app.example.com/"></x-signin-button>

The target must be an absolute URL whose origin is on the tenant's allowlist. The server validates it and falls back to the app URL, so a value it does not trust is ignored rather than honored.

<x-authorized> and <x-non-authorized> are older spellings of <x-signed-in> and <x-signed-out>. Both are supported, and neither is preferred.

Triggering Userspace from your own markup

<x-trigger> wraps your own element, rendering nothing of its own, and fires a Userspace action when it is clicked (a tap counts as a click). The actions are settings, which opens the settings popup, sign-in, which leaves for the hosted sign-in page, and sign-out, which signs the user out. Wrap a real interactive element, like a button or your design system's menu item, so keyboard activation comes for free, and place the trigger inside <x-signed-in>: without a session settings logs a console warning and opens nothing.

sign-in and sign-out take the same redirect-uri attribute as <x-signin-button>, naming where to land afterwards.

<x-signed-out>
  <x-trigger action="sign-in" redirect-uri="https://app.example.com/">
    <button class="your-cta">Get started</button>
  </x-trigger>
</x-signed-out>

<x-signed-in>
  <x-trigger action="settings">
    <button class="your-menu-item">Account settings</button>
  </x-trigger>
  <x-trigger action="sign-out">
    <button class="your-menu-item">Sign out</button>
  </x-trigger>
</x-signed-in>

Every action is available imperatively. All settings triggers and callers share one popup instance.

await Userspace.openSettings()
await Userspace.signOut()

signIn() leaves for the hosted sign-in page, carrying redirect_uri back to the current URL so the user returns where they were — the same navigation the autoLogin option performs, on a click instead of on every signed-out visit. Pass redirectUri to land somewhere else, under the same allowlist rule as signOut:

Userspace.signIn()
Userspace.signIn({ redirectUri: 'https://app.example.com/' })

signOut() 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. It POSTs to the sign-out endpoint, then navigates to the hosted sign-in page — or to redirectUri, an absolute URL whose origin must be on the tenant's allowlist (the server validates it; untrusted targets fall back to sign-in):

await Userspace.signOut({ redirectUri: 'https://app.example.com/logged-out' })

registerElements() registers the custom elements without configuring the SDK, for hosts that configure another way. configureUserspace already calls it; most pages never need it directly.

License

MIT.