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

ai-passport-signin

v0.1.1

Published

Sign in with AI Passport buttons and an OpenID Connect server helper.

Readme

ai-passport-signin

Add an AI Passport sign-in button to a browser page, React app, or server. The browser entry has no dependencies. The server helper uses Node built-ins.

Install

npm install ai-passport-signin

Browser button

Load the browser entry as a module. The custom element renders a real link inside its shadow root.

<ai-passport-button
  href="/sign-in/ai-passport"
  theme="light"
  label="signin">
</ai-passport-button>

<script type="module">
  import "ai-passport-signin";
</script>

Set theme to light or dark. Set label to signin or continue. Use full-bleed when the button should fill its container.

buttonHTML() returns a server-rendered HTML fragment. It needs no browser runtime.

import { buttonHTML } from "ai-passport-signin";

const html = buttonHTML({
  href: "/sign-in/ai-passport",
  theme: "dark",
  label: "continue",
});

React

The React export uses the same custom element and requires React 18 or later.

import React from "react";
import { AIPassportButton } from "ai-passport-signin/react";

export function SignIn() {
  return React.createElement(AIPassportButton, {
    href: "/sign-in/ai-passport",
    theme: "light",
    label: "signin",
  });
}

Server helper

Use the server export in routes that start and finish sign-in. Keep the returned state object in the user's server-side session. Do not send it to the browser outside the authorization request.

Use an HTTPS issuer. The helper accepts HTTP only for loopback development issuers.

import { createPassportSignIn } from "ai-passport-signin/server";

const signIn = createPassportSignIn({
  issuer: "https://passport.ego.ist",
  clientId: "https://notes.example/ai-passport-client.json",
  redirectUri: "https://notes.example/auth/ai-passport/callback",
  scopes: ["openid", "profile", "email"],
});

// In the route that starts sign-in
const started = await signIn.begin();
session.aiPassportState = started.state;
return redirect(started.url);

// In the callback route
const result = await signIn.complete({
  code: request.query.code,
  state: request.query.state,
  iss: request.query.iss,
  storedState: session.aiPassportState,
});
delete session.aiPassportState;

begin() reads OpenID Connect discovery, creates PKCE S256 values, and adds the RFC 8707 MCP resource when you request memory. complete() checks the RFC 9207 iss response parameter, exchanges the code, verifies the RS256 ID token against JWKS, and checks issuer, audience, expiry, issued-at time, and nonce.

The returned object has claims, tokens, and passport. passport is the top-level ID token claim when the issuer sends it. passport.memory_access only says the token may ask to read memory. Category passes still govern each memory read.

Register your client

Use a Client Identifier Metadata Document (CIMD) first. Set clientId to the HTTPS URL where you host the document. The URL must include a path. It cannot include user information, a query, a fragment, or a non-default port.

Host this JSON at https://<your-host>/ai-passport-client.json.

import { clientMetadataDocument } from "ai-passport-signin/server";

export default clientMetadataDocument({
  clientId: "https://notes.example/ai-passport-client.json",
  clientName: "Acme Notes",
  redirectUris: ["https://notes.example/auth/ai-passport/callback"],
});

The document contains the exact client_id, a non-empty client_name, its redirect URIs, authorization-code and refresh-token grants, code response type, and public client authentication with none.

For automatic admission, every redirect host must equal the document host or be its strict subdomain. Sibling hosts, HTTP redirects, loopback hosts, IP literals, and mixed host trees use the manual admission path.

Registration is self-serve. Production authorization requires client admission. With CIMD, hosts consistent with the document host can be admitted automatically where auto-admission is enabled. Otherwise admission is a manual review step described in the docs at https://ego.ist/docs/sign-in.

For an older integration, use Dynamic Client Registration (DCR). DCR remains compatible but is deprecated for new integrations.

import { registerClient } from "ai-passport-signin/server";

const registration = await registerClient({
  issuer: "https://passport.ego.ist",
  clientName: "Acme Notes",
  redirectUris: ["https://notes.example/auth/ai-passport/callback"],
});

Store registration.client_id as durable configuration. DCR registration does not grant production authorization.

Button rules

Use exactly Sign in with AI Passport or Continue with AI Passport. The visible label is the accessible name.

Use the light variant on light surfaces. It uses a #11100E background and white text. Use the dark variant on dark surfaces. It uses a white background, near-black text, and a subtle border.

Both variants have a 44 pixel minimum height, 220 pixel minimum width, 16 pixel horizontal padding, 8 pixel radius, the official 22 pixel mark, and a 12 pixel gap before the label. Do not use the mark alone as a sign-in control.

API

| Export | Use | | --- | --- | | ai-passport-signin | buttonHTML(), button labels, and SVG assets | | ai-passport-signin/react | AIPassportButton React wrapper | | ai-passport-signin/server | OIDC sign-in and registration helpers |

createPassportSignIn({ issuer, clientId, redirectUri, scopes, fetch }) creates a helper. Supply fetch only for tests or a controlled transport.

clientMetadataDocument({ clientId, clientName, redirectUris }) returns the CIMD JSON document.

registerClient({ issuer, clientName, redirectUris, fetch }) uses the deprecated DCR fallback.