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

@fjordid/react

v0.2.1

Published

React integration for FjordID — <FjordIDProvider> and useAuth() with StrictMode support and automatic redirectUri normalization.

Readme

@fjordid/react

React integration for FjordID — EU-first OIDC/OAuth2 identity platform.

Provides <FjordIDProvider> and useAuth() with first-class support for:

  • React 18 / 19 StrictMode — safe double-invoke guard, no "can only be initialized once" errors
  • Automatic redirectUri normalization — defaults to window.location.origin, avoiding the keycloak-js footgun where ?code=…&state=… callback params end up in the redirect URI
  • Silent token refresh — handled automatically via FjordAuth
  • TypeScript — full type inference, zero anys

Install

npm install @fjordid/react
# or
pnpm add @fjordid/react

Quick start

1. Wrap your app

// main.tsx
import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import { FjordIDProvider } from "@fjordid/react";
import App from "./App";

createRoot(document.getElementById("root")!).render(
  <StrictMode>
    <FjordIDProvider
      options={{ clientId: import.meta.env.VITE_KEYCLOAK_CLIENT_ID }}
      loadingFallback={<div>Loading…</div>}
    >
      <App />
    </FjordIDProvider>
  </StrictMode>,
);

2. Add silent-check-sso.html

Create public/silent-check-sso.html:

<html>
  <body>
    <script>
      parent.postMessage(location.href, location.origin);
    </script>
  </body>
</html>

Register it as a redirect URI in the FjordID console: http://localhost:5173/silent-check-sso.html

3. Use auth in any component

import { useAuth } from "@fjordid/react";

export function UserMenu() {
  const { user, authenticated, loading, login, logout } = useAuth();

  if (loading) return null;

  if (!authenticated) {
    return <button onClick={() => login()}>Sign in with FjordID</button>;
  }

  return (
    <div>
      <span>Hello, {user?.email}</span>
      <button onClick={() => logout()}>Sign out</button>
    </div>
  );
}

API

<FjordIDProvider>

| Prop | Type | Default | Description | | ----------------- | ------------------ | ----------- | ---------------------------------------------------------------------------- | | options | FjordAuthOptions | required | FjordID configuration | | children | ReactNode | required | Your app tree | | loadingFallback | ReactNode | undefined | Shown while the initial SSO check runs (omit to use loading state instead) |

options.redirectUri defaults to window.location.origin — do not set it to window.location.href, which may include OIDC callback query params after a login redirect.

useAuth()

Returns an AuthContextValue object:

| Property | Type | Description | | ------------------------ | ------------------------------------ | ------------------------------------- | | authenticated | boolean | Whether the user is logged in | | loading | boolean | True during the initial SSO check | | user | FjordUser \| null | Authenticated user profile | | login(redirectUri?) | () => void | Redirect to FjordID login | | logout(redirectUri?) | () => void | Redirect to FjordID logout | | register(redirectUri?) | () => void | Redirect to FjordID registration | | getToken() | () => Promise<string \| undefined> | Get a valid Bearer token | | auth | FjordAuth | Underlying @fjordid/client instance |


Environment variables

VITE_KEYCLOAK_URL=https://auth.fjordid.eu
VITE_KEYCLOAK_REALM=fjordid
VITE_KEYCLOAK_CLIENT_ID=fjid_your_client_id

React StrictMode details

React 18 and 19 run useEffect twice in development to surface side-effect bugs. Raw keycloak-js throws "can only be initialized once" on the second call. @fjordid/react avoids this by:

  1. Creating the FjordAuth instance in a useRef (not useMemo or useState) so it is never recreated.
  2. Tracking the init call with a separate useRef(false) that persists across the StrictMode unmount → remount cycle, so auth.init() is called exactly once.
  3. Re-subscribing to auth events on every mount/remount (cleanup is properly hooked up in the effect return).

redirectUri mismatch — the callback URL footgun

A common integration mistake with raw keycloak-js:

// ❌ Wrong — window.location.href contains ?code=…&state=… after a login callback.
//    On a second login() call (StrictMode re-render, page reload, etc.) Keycloak
//    rejects it because the registered URI is just the origin.
keycloak.login({ redirectUri: window.location.href });

// ✅ Correct — always redirect back to the clean origin.
keycloak.login({ redirectUri: window.location.origin });

@fjordid/react (and @fjordid/client) default to window.location.origin for you. If you override options.redirectUri, use the clean form without query parameters.


Protected route example

import { Navigate, Outlet } from "react-router-dom";
import { useAuth } from "@fjordid/react";

export function ProtectedRoute() {
  const { authenticated, loading, login } = useAuth();

  if (loading) return <div>Loading…</div>;
  if (!authenticated) {
    login();
    return null;
  }
  return <Outlet />;
}

License

MIT © FjordID