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

@xmcp-dev/auth0

v0.1.0

Published

Auth0 authentication integration for xmcp

Readme

@xmcp-dev/auth0

Auth0 authentication integration for xmcp.

Installation

npm install @xmcp-dev/auth0
# or
pnpm add @xmcp-dev/auth0
# or
yarn add @xmcp-dev/auth0

Quick Start

1. Configure the Auth0 Provider

Create a src/middleware.ts file:

import { auth0Provider } from "@xmcp-dev/auth0";

export default auth0Provider({
  domain: process.env.DOMAIN!,
  audience: process.env.AUDIENCE!,
  baseURL: process.env.BASE_URL!,
  clientId: process.env.CLIENT_ID!,
  clientSecret: process.env.CLIENT_SECRET!,
});

2. Access User Info in Tools

Tools are public by default - any authenticated user can access them. To make a tool private, add a tool:<tool-name> permission in your Auth0 API settings (see Permission Enforcement).

Using getAuthInfo

Use this to access the authenticated user's info in your tools.

// src/tools/whoami.ts
import { getAuthInfo } from "@xmcp-dev/auth0";
import type { ToolMetadata } from "xmcp";

export const metadata: ToolMetadata = {
  name: "whoami",
  description: "Get current user info",
};

export default async function whoami() {
  const authInfo = getAuthInfo();
  return `User ID: ${authInfo.user.sub}, Email: ${authInfo.user.email}`;
}

3. Environment Variables

Create a .env file:

DOMAIN=your-tenant.auth0.com
AUDIENCE=http://127.0.0.1:3001/
BASE_URL=http://127.0.0.1:3001
CLIENT_ID=your-client-id
CLIENT_SECRET=your-client-secret

API Reference

auth0Provider(config)

Creates the Auth0 authentication provider for xmcp.

| Option | Type | Required | Description | |--------|------|----------|-------------| | domain | string | Yes | Your Auth0 domain | | audience | string | Yes | The API identifier configured in Auth0 | | baseURL | string | Yes | The base URL of your MCP server | | clientId | string | Yes | OAuth client ID | | clientSecret | string | Yes | OAuth client secret | | scopesSupported | string[] | No | List of custom scopes for OAuth metadata | | management | object | No | Management API configuration (optional overrides) |

management options (optional)

Optional overrides for Management API configuration. The Management API is always enabled for permission checking.

| Option | Type | Required | Description | |--------|------|----------|-------------| | audience | string | No | Management API audience (default: https://<domain>/api/v2/) | | resourceServerIdentifier | string | No | API identifier to use for Management operations |

Note: Your M2M application needs read:resource_servers and read:users permissions on the Auth0 Management API to check defined permissions and verify user access.

Permission Enforcement

Tools are public by default. Any authenticated user can access them.

To make a tool private, add a tool:<tool-name> permission in your Auth0 API settings:

  1. Go to Auth0 DashboardApplicationsAPIs → Your API
  2. Go to Permissions tab
  3. Add permission: tool:greet (for a tool named "greet")
  4. Assign the permission to users who should have access

The plugin queries Auth0 Management API on each request:

  1. Check if permission exists → queries read:resource_servers to see if tool:<name> is defined
  2. If permission exists → queries read:users to verify the user has it assigned
  3. If permission does not exist → tool is public, any authenticated user can access

Note: If Management API calls fail, the secure default is to deny access. This ensures real-time permission verification rather than relying on potentially stale token claims.

getAuthInfo()

Gets the current user's authentication info from context.

const authInfo = getAuthInfo();
console.log(authInfo.user.sub);    // User ID
console.log(authInfo.user.email);  // Email
console.log(authInfo.scopes);      // Granted scopes
console.log(authInfo.permissions); // RBAC permissions

Getting User Info

From token claims (recommended):

const authInfo = getAuthInfo();
console.log(authInfo.user.sub);   // User ID
console.log(authInfo.user.email); // Email (if in token)
console.log(authInfo.user.name);  // Name (if in token)

From /userinfo endpoint:

const authInfo = getAuthInfo();
const response = await fetch(`https://${process.env.AUTH0_DOMAIN}/userinfo`, {
  headers: { Authorization: `Bearer ${authInfo.token}` }
});
const userInfo = await response.json();

getClient()

Returns the Auth0 API client for advanced operations like token exchange.

import { getClient, getAuthInfo } from "@xmcp-dev/auth0";

// Exchange tokens to call external APIs on user's behalf
async function exchangeCustomToken(subjectToken: string) {
  const client = getClient();
  return await client.getTokenByExchangeProfile(subjectToken, {
    subjectTokenType: "urn:ietf:params:oauth:token-type:access_token",
    audience: process.env.EXTERNAL_API_AUDIENCE!,
    ...(process.env.EXCHANGE_SCOPE && { scope: process.env.EXCHANGE_SCOPE }),
  });
}

export default async function callExternalApi() {
  const authInfo = getAuthInfo();
  const { access_token } = await exchangeCustomToken(authInfo.token);

  // Use the exchanged token to call your external API
  const response = await fetch(process.env.EXTERNAL_API_URL!, {
    headers: { Authorization: `Bearer ${access_token}` },
  });
  return await response.text();
}

getManagement()

Returns the Auth0 Management API client for admin operations.

import { getManagement, getAuthInfo } from "@xmcp-dev/auth0";

export default async function updateUserMetadata() {
  const authInfo = getAuthInfo();
  const client = getManagement();

  await client.users.update(authInfo.user.sub, {
    user_metadata: { theme: "dark" },
  });
  return "Preferences updated!";
}

Architecture

The plugin uses two internal contexts with different lifecycles:

Client Context (Static)

Set once when auth0Provider() is called at startup. Contains:

  • config - Auth0 configuration
  • apiClient - Auth0 API client for token verification
  • managementClient - Auth0 Management API client (always enabled for permission checking)

This context is shared across all requests and never changes after initialization.

Session Context (Per-Request)

Updated on every authenticated request. Contains:

  • authInfo - The authenticated user's token info, scopes, and claims

This context is set after token verification in the middleware and is unique to each request.

Auth Info Structure

interface AuthInfo {
  token: string;           // Raw access token
  clientId: string;        // OAuth client ID
  scopes: string[];        // Granted scopes
  permissions?: string[];  // RBAC permissions granted to this token
  expiresAt?: number;      // Expiration timestamp
  user: {
    sub: string;           // User ID
    client_id?: string;    // Client ID claim
    azp?: string;          // Authorized party
    name?: string;         // User's name
    email?: string;        // User's email
  };
}

OAuth Endpoints

The plugin serves two OAuth metadata endpoints:

  • GET /.well-known/oauth-protected-resource - Resource server metadata
  • GET /.well-known/oauth-authorization-server - Proxies Auth0's OIDC config

Auth0 Tenant Setup

MCP clients use Dynamic Client Registration (DCR) and the OAuth 2.0 Resource Parameter to authenticate. Your Auth0 tenant requires specific configuration for this to work.

Reference: Based on Auth0's official MCP sample

Step 1: Enable Dynamic Client Registration

MCP clients register themselves automatically with your Auth0 tenant.

  1. Go to Auth0 DashboardSettingsAdvanced
  2. Enable "OIDC Dynamic Application Registration"
  3. Save changes

Or via Auth0 CLI:

auth0 api patch tenants/settings --data '{"flags":{"enable_dynamic_client_registration":true}}'

Step 2: Enable Resource Parameter Compatibility Profile

The MCP specification requires the resource parameter (RFC 8707). Auth0 needs this compatibility profile enabled.

  1. Go to Auth0 DashboardSettingsAdvanced
  2. Enable "Resource Parameter Compatibility Profile"
  3. Save changes

See Auth0 docs for details.

Step 3: Promote Connection to Domain Level

DCR-registered clients are third-party by default and can only use domain-level connections.

  1. Go to Auth0 DashboardAuthenticationDatabase
  2. Select your connection (e.g., Username-Password-Authentication)
  3. Enable "Enable for third-party clients" (or "Promote to domain level")
  4. Save changes

Or via Auth0 CLI:

# List connections to get ID
auth0 api get connections

# Promote connection (replace YOUR_CONNECTION_ID)
auth0 api patch connections/YOUR_CONNECTION_ID --data '{"is_domain_connection":true}'

Step 4: Create the API

Important: The API identifier must match your BASE_URL exactly, including the trailing slash.

  1. Go to Auth0 DashboardApplicationsAPIs
  2. Click Create API
  3. Set:
    • Name: e.g., MCP Server API
    • Identifier: Your server URL with trailing slash (e.g., http://localhost:3001/)
    • Signing Algorithm: RS256
  4. Enable RBAC and Add Permissions in the Access Token
  5. Go to Permissions tab and add your tool permissions:
    • tool:greet - Access the greeting tool
    • tool:whoami - Access the whoami tool

Or via Auth0 CLI:

auth0 api post resource-servers --data '{
  "identifier": "http://localhost:3001/",
  "name": "MCP Server API",
  "signing_alg": "RS256",
  "scopes": [
    {"value": "tool:greet", "description": "Access the greeting tool"},
    {"value": "tool:whoami", "description": "Access the whoami tool"}
  ]
}'

Step 5: Set Default Audience

  1. Go to Auth0 DashboardSettingsGeneral
  2. Under API Authorization Settings, set Default Audience to your API identifier (e.g., http://localhost:3001/)
  3. Save changes

Step 6: Create an Application

  1. Go to Auth0 DashboardApplicationsApplications
  2. Click Create ApplicationMachine to Machine Applications
  3. Name it (e.g., MCP Server)
  4. Select your API (e.g., MCP Server API)
  5. Copy the Client ID and Client Secret to your .env

Step 7: Enable Management API

Required for dynamic permission checking. The plugin queries Auth0 to determine which tools require permissions and verify user access.

  1. In your M2M application, go to APIs tab
  2. Enable Auth0 Management API
  3. Grant the following permissions:
    • read:resource_servers - Check which tool permissions are defined
    • read:users - Verify user has the required permissions
  4. Optionally grant additional permissions for admin operations (e.g., update:users)

Important Notes

  • API Identifier must match BASE_URL: MCP clients send a resource parameter that Auth0 uses as the audience. If there's a mismatch (even a missing trailing slash), you'll get "Service not found" errors.
  • Trailing slash matters: If your BASE_URL is http://localhost:3001, the MCP client may send http://localhost:3001/ as the resource. Create your API with the trailing slash to match.
  • DCR clients are third-party: They require domain-level connections to authenticate users.
  • RBAC must be enabled: Enable "Add Permissions in the Access Token" in your API settings for permission enforcement to work.

Environment Variables

After setup, configure your .env:

AUTH0_DOMAIN=your-tenant.auth0.com
AUTH0_AUDIENCE=http://localhost:3001/
BASE_URL=http://localhost:3001
AUTH0_CLIENT_ID=your-client-id
AUTH0_CLIENT_SECRET=your-client-secret