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

@bandf/framework-identity

v1.7.0

Published

Identity & authentication (MetaMask/SIWE, email) for the bandf framework.

Readme

@bandf/framework-identity

@bandf/framework-identity gives BandF apps one session model with two ways to prove identity: MetaMask Sign-In with Ethereum and email magic links. It provides React controls, vanilla custom elements, and imperative adapters over the same browser session.

Contents

Choose an interface

| App code | Interface | | ---------------------- | -------------------------------------------------------------------------- | | React | MetamaskLogin and EmailLogin from @bandf/framework-identity | | Compiled HTML/Markdown | <metamask-login> and <email-login> injected by the framework when used | | Custom UI or workflow | createMetamaskAuth from /core or createEmailAuth from /email |

All interfaces use the framework's /bandf/token/* routes and persist the same bearer session.

React controls

import { EmailLogin, MetamaskLogin } from "@bandf/framework-identity";

export function LoginControls() {
  return (
    <nav>
      <MetamaskLogin onLogin={(address) => console.log(address)} />
      <EmailLogin onLogin={() => console.log("signed in")} />
    </nav>
  );
}

Both controls derive the API base from @bandf/framework-state unless apiBase is supplied. They restore a valid stored session on mount and expose onLogin, onLogout, and onError callbacks. className styles the trigger; ariaLabel overrides its accessible name. EmailLogin also accepts an input placeholder.

The trigger is a closed red lock when signed out and an open green lock when signed in. The package stylesheet is imported by the React entry point.

HTML custom elements

The HTML compiler supplies the browser entry when a view uses the identity elements:

<metamask-login button-class="login-button"></metamask-login>
<email-login
  button-class="login-button"
  placeholder="[email protected]"
></email-login>

<script>
  document
    .querySelector("metamask-login")
    .addEventListener("login", (event) => {
      console.log(event.detail.address);
    });
</script>

Both elements accept api-base and button-class. The email element also accepts placeholder. They dispatch login, logout, and autherror; the error event carries event.detail.message, and the MetaMask login event carries event.detail.address.

The browser entry also exposes:

globalThis.BandfIdentity = { createMetamaskAuth, createEmailAuth };

Imperative adapters

Use the cores when the built-in controls do not fit the interface.

import { createMetamaskAuth } from "@bandf/framework-identity/core";

const auth = createMetamaskAuth({ apiBase: "http://localhost:3000/dev" });
const address = await auth.login();

await fetch("/dev/private", {
  headers: auth.authorizedHeaders({ Accept: "application/json" }),
});

The MetaMask handle exposes hasProvider, getAddress, login, logout, onChange, getToken, authorizedHeaders, and checkSession. onChange() returns an unsubscribe function for its EIP-1193 listeners.

import { createEmailAuth } from "@bandf/framework-identity/email";

const auth = createEmailAuth({ apiBase: "http://localhost:3000/dev" });
await auth.requestLink({ email: "[email protected]" });

// Call during page boot. It exchanges ?lt= when present and removes it from the URL.
const completed = await auth.completeFromUrl();

The email handle exposes requestLink, completeFromUrl, getToken, logout, authorizedHeaders, and checkSession. Both factories accept a custom Web Storage-compatible storage; the default is localStorage.

Session contract

A successful login stores:

  • bandf-jwt: the bearer JWT;
  • bandf-fetch-config: a serialized no-cache fetch configuration carrying the bearer header.

authorizedHeaders() reads the current token and merges Authorization into caller headers. checkSession() asks /bandf/token/check whether the stored token remains valid without prompting the wallet or sending email. logout() removes both entries.

MetaMask and email sessions are interchangeable at the bearer-token layer. A valid stored JWT is the browser's session authority. Switching from one non-empty MetaMask account to another does not rebind or invalidate that JWT automatically; use explicit logout when an application needs wallet-account switching to end the session.

Server requirements and security

The built-in routes implement these flows:

sequenceDiagram
    participant B as Browser
    participant I as BandF identity routes
    participant W as Wallet or inbox
    participant D as Supabase identities

    B->>I: request challenge or magic link
    I->>W: wallet signature request or email link
    W-->>B: signed proof
    B->>I: exchange proof
    I->>D: resolve allowlisted principal
    D-->>I: identity or deny
    I-->>B: shared bearer JWT
  • MetaMask signs a SIWE message bound to the request origin, domain, and a five-minute signed nonce.
  • Email links are same-origin and carry a fifteen-minute signed token.
  • Identity JWTs use HS512, audience bandf-identity, and a configurable lifetime that defaults to seven days.
  • JWT_SIGNING_KEY must be configured and at least 86 characters.
  • Supabase identity lookup fails closed: without the configured Service, no principal can log in.
  • Email requests return the same public response for known and unknown addresses to avoid identity enumeration.

Nonce and magic-link tokens are stateless. They are not consumed in a server-side one-time store, so their short expiry bounds replay. Protected app routes still need the correct OAS bearer security declaration; rendering a login control does not secure an endpoint.

Related links