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

verdaccio-github-oauth-verifier

v1.1.1

Published

Plugin that ensures we can verify the generated JWT oauth tokens and add optional black listing for security reasonss

Readme

verdaccio-github-oauth-verifier

npm version

A Verdaccio auth plugin that verifies JWT tokens issued by verdaccio-github-oauth-ui (or compatible OAuth UI) against GitHub organization membership, with optional JWT tracking and blacklisting for security.

Features

  • Organization membership check: Validates that the user in the JWT is still a member of a configured GitHub organization via the GitHub API.
  • In-memory cache: Caches verification results to reduce GitHub API calls (configurable TTL).
  • Optional JWT tracking: When enabled, only the most recent JWT per user is accepted; older tokens are rejected (e.g. after re-login or token rotation).
  • Revocation: Admin endpoints to invalidate a user’s JWT or clear cache entries.
  • Scheduled cleanup: Cron-based cleanup of expired JWT tracking entries in the SQLite database.

Requirements

  • Verdaccio 3.x
  • An auth plugin that issues JWTs with a name claim (e.g. verdaccio-github-oauth-ui). This plugin does not issue tokens; it only verifies them.

Installation

npm install verdaccio-github-oauth-verifier

or

yarn install verdaccio-github-oauth-verifier

Configuration

Add the plugin to your Verdaccio config (e.g. config.yaml):

middlewares:
  github-oauth-verifier:
    enabled: true
    org: your-github-org-name
    # Option A: use a Personal Access Token (or GitHub App token) with read:org
    token: your-github-token
    # Option B: use a GitHub App (clientId + pem); if both are set, GitHub App is used for org checks
    # githubApp:
    #   clientId: "123456"
    #   pem: "-----BEGIN RSA PRIVATE KEY-----\n...\n-----END RSA PRIVATE KEY-----"
    #   installationId: 12345  # optional; resolved from org if omitted
    # adminToken: "optional-token-for-admin-endpoints-when-using-github-app-only"
    adminToken: "super-secret-token-for-admin-endpoints"
    cacheTTLMinutes: 480
    jwtTrackingEnabled: true
    jwtCleanupSchedule: "0 0 * * *"

Configuration options

| Option | Type | Required | Description | | ---------------------------- | ------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | enabled | boolean | No | Enable the plugin. Default: true if the plugin block is present. | | org | string | Yes | GitHub organization name. Users must be members of this org. | | token | string | Yes* | GitHub token (PAT or GitHub App token) with read:org. Required unless githubApp is configured. | | githubApp | object | Yes* | GitHub App credentials. Required unless auth.github-oauth-ui.token is set. If both are set, GitHub App is used for org membership checks. | | githubApp.clientId | string | Yes** | GitHub App ID (numeric, from app settings). Required when using githubApp. | | githubApp.pem | string | Yes** | Private key: PEM content (multi-line string) or path to a .pem file. Required when using githubApp. | | githubApp.installationId | number | No | Installation ID for the org. If omitted, the plugin resolves it via GET /orgs/{org}/installation. | | adminToken | string | No | Token for admin endpoints. When using GitHub App only (no auth.github-oauth-ui.token), set this to protect admin routes. Otherwise admin uses the same token. | | cacheTTLMinutes | number | No | How long to cache verification results (minutes). Default: 480 (8 hours). | | jwtTrackingEnabled | boolean | No | When true, enable JWT tracking (only the most recent JWT per user). DB is stored at ~/.verdaccio/jwt-tracking.db. | | jwtCleanupSchedule | string | No | Cron expression for cleanup of expired JWT tracking rows. Default: 0 0 * * * (daily at midnight). Format: 5 fields minute hour day month weekday or 6 with seconds. |

* At least one of auth.github-oauth-ui.token or githubApp (with clientId and pem) is required when the plugin is enabled.
** Required when githubApp is used.

Token (Personal Access Token or GitHub App token)

Create a Personal Access Token (or use a GitHub App token) with read:org and configure it under auth.github-oauth-ui.token. The same token is often shared with the OAuth UI plugin for consistency. Keep it secret and restrict scope.

GitHub App

You can use a GitHub App instead of a single token for org membership checks. The plugin will:

  1. Sign a JWT with your App ID and private key (PEM).
  2. Resolve the installation ID for your org (from config or via GET /orgs/{org}/installation).
  3. Exchange the JWT for an installation access token (cached until ~5 minutes before expiry).
  4. Call GET /orgs/{org}/members/{username} with that token.

Setup: Create a GitHub App, install it on your organization, and grant Members read permission (or the scope needed for org membership). Then set githubApp.clientId (your App ID from the app settings page) and githubApp.pem (private key content or path to the .pem file). Optionally set githubApp.installationId to skip the installation lookup. If you do not set auth.github-oauth-ui.token, you must set adminToken to protect the admin endpoints (invalidate JWT, clear cache).

If you see "GitHub org installation lookup failed: 404": The app is not installed on the organization named in org, or the org name is wrong. Install the app on that org (e.g. Organization settings → GitHub Apps → Install App or the link in the error message), or set githubApp.installationId to the installation ID (see below).

Finding the installation ID (custom / developer app)

If your app was created in Developer settings (not from the marketplace) and is only for your org:

  • Organization-owned app:

    1. Go to OrganizationSettings (or https://github.com/organizations/<your-org>/settings).
    2. In the left sidebar, under Third-party access or Integrations, open GitHub Apps.
    3. Click your app, then Configure (or open the installation you use).
    4. The URL in the browser will look like:
      https://github.com/organizations/<org-name>/settings/installations/<ID>
      The number at the end is the installation ID. Use it as githubApp.installationId in config.
  • User-owned app (your personal account):
    ProfileSettingsApplications → your app → Configure. The installation ID is the number at the end of that page’s URL.

Setting installationId avoids the automatic org lookup and works even when the API lookup returns 404 (e.g. for some org-only or private setups).

JWT tracking (single token per user)

When jwtTrackingEnabled is true:

  • The plugin stores the latest JWT per user (by hash and iat) in a SQLite database at ~/.verdaccio/jwt-tracking.db.
  • Only that latest token is accepted; any older token for the same user returns 401 with “JWT token has been superseded by a newer login”.
  • Expired tokens are rejected and the user’s row is removed when the token is seen as expired.
  • You can revoke a user’s token via the admin endpoint (see below); the plugin marks them as revoked and rejects that token.
  • A cron job (or the configured jwtCleanupSchedule) deletes rows whose exp is in the past.

This helps enforce “one active session per user” and allows revoking access without waiting for token expiry.

Admin API endpoints

Both endpoints require a Bearer token in the Authorization header. The accepted token is adminToken if set, otherwise auth.github-oauth-ui.token. When using GitHub App only (no OAuth token), set adminToken to protect these routes.

Invalidate JWT

POST /-/github-oauth-verifier/invalidate-jwt?username=<username>
Authorization: Bearer <your-admin-token>
  • With username: marks that user’s token as revoked (when JWT tracking is enabled) and removes them from the in-memory cache.
  • Without username: marks all users’ tokens as revoked and clears the entire cache.

Subsequent requests with a revoked user’s JWT will receive 401 with “GitHub authorization revoked”.

Clear cache

POST /-/github-oauth-verifier/clear-cache?username=<username>
Authorization: Bearer <your-admin-token>
  • With username: clears the cache entry for that user only.
  • Without username: clears the entire verification cache.

Use this to force re-validation against GitHub on the next request (e.g. after org membership changes).

Behavior summary

  1. No Authorization header: Request passes through; no verification.
  2. Invalid or non-JWT Authorization: Request passes through (plugin only validates JWTs it can parse).
  3. Valid JWT:
  • If JWT tracking is enabled: check single-token-per-user and revocation; reject if superseded or revoked.
  • If the username is in the cache and allowed → allow request.
  • If the username is in the cache and disallowed → 401 “GitHub authorization revoked”.
  • Otherwise: call GitHub API GET /orgs/{org}/members/{username}. If 204 → allow and cache; if 404 (or other failure) → deny, cache denial, and optionally mark as revoked in JWT tracking.

Errors talking to GitHub or invalid tokens are treated as “fail closed”: access is denied.

License

MIT