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

@mantlejs/auth-twitter

v0.2.0

Published

Sign in with X (Twitter) strategy for Mantle JS

Readme

@mantlejs/auth-twitter

Sign in with X (Twitter) OAuth 2.0 strategy for Mantle JS. Implements the authorization code flow with PKCE — no Passport.js dependency. Registers GET /auth/twitter and GET /auth/twitter/callback on the HTTP transport, then finds or creates a user record and returns a Mantle JWT pair.


Installation

npm install @mantlejs/auth-twitter

Concepts

PKCE

Unlike auth-github/auth-facebook/auth-linkedin, X's OAuth 2.0 implementation requires PKCE (Proof Key for Code Exchange) — same posture as auth-google/auth-microsoft. On each redirect request the plugin generates a fresh code_verifier (via Arctic, which also derives the SHA-256 / base64url code_challenge — see ADR-002). The verifier is stored server-side against a random state token and passed to the token exchange on callback.

Scope

Defaults to ["users.read", "tweet.read"]. X's own API reference lists users.read and tweet.read as alternative scopes for GET /2/users/me, but X's developer community has repeatedly reported 403 Forbidden from that endpoint with users.read alone — both are requested by default to match what's actually been confirmed working, not just what the reference documents.

No email

X's /2/users/me endpoint only returns an email address via the confirmed_email field, gated behind an app-level email access grant that most apps don't have, and never includes it by default. This strategy doesn't request user.fields=confirmed_email (an unapproved field risks the whole call failing rather than being silently omitted), so a user record created via twitterStrategy never has an email — plan your users schema accordingly if X is one of several strategies you support.

Find-or-create

On callback the plugin searches the configured user service for a record where twitterId (configurable) matches the id field from X's /2/users/me response. If no record is found, it creates one with { twitterId, name } from the profile (no email — see above). The same user is returned on every subsequent sign-in.


Quick start

import { mantle } from "@mantlejs/mantle";
import { express } from "@mantlejs/express";
import { auth } from "@mantlejs/auth";
import { twitterStrategy } from "@mantlejs/auth-twitter";

const app = mantle()
  .configure(express())
  .configure(auth({ secret: process.env.JWT_SECRET! }))
  .configure(
    twitterStrategy({
      clientId: process.env.TWITTER_CLIENT_ID!,
      clientSecret: process.env.TWITTER_CLIENT_SECRET!,
    }),
  );

app.listen(3030);

Sign-in flow:

  1. Redirect the browser to GET /auth/twitter
  2. User authenticates on X and consents
  3. X redirects to GET /auth/twitter/callback?code=...&state=...
  4. The plugin exchanges the code, fetches the profile, finds or creates the user, and responds:
{
  "accessToken": "eyJhbGciOiJIUzI1NiJ9...",
  "refreshToken": "eyJhbGciOiJIUzI1NiJ9...",
  "user": { "id": "1", "twitterId": "1234567890", "name": "Alice" }
}

API

twitterStrategy(config)

function twitterStrategy(config: TwitterStrategyConfig): MantlePlugin;

type TwitterStrategyConfig = OAuthPluginConfig;

| Field | Type | Default | Description | | --------------- | ---------- | ------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- | | clientId | string | — | X app's OAuth 2.0 Client ID (required) | | clientSecret | string | — | X app's OAuth 2.0 Client Secret (required) | | callbackUrl | string | '/auth/twitter/callback' | Callback path — must match a redirect URI registered in the X app's settings | | scope | string[] | ['users.read', 'tweet.read'] | X OAuth 2.0 scopes | | entity | string | 'users' | Mantle service used to find or create users | | entityIdField | string | 'twitterId' | Field on the user record matched against X's id field | | redirectUrl | string | none — returns JSON | Frontend URL to redirect to on completion, with tokens (or an error) in the URL fragment — see @mantlejs/auth-oauth |

Routes registered:

| Method | Path | Description | | ------ | ------------------------ | --------------------------------------- | | GET | /auth/twitter | Redirect to X sign-in | | GET | /auth/twitter/callback | Handle callback, issue Mantle JWT pair |

Must be configured after the transport (e.g. express()) and auth().


Types

import type { TwitterStrategyConfig } from "@mantlejs/auth-twitter";

TwitterStrategyConfig is a plain alias of OAuthPluginConfig from @mantlejs/auth-oauth — X needs no strategy-specific fields (unlike auth-microsoft's tenant or auth-apple's Sign in with Apple key fields).


X Developer Portal setup

  1. Create a project and app at developer.x.com → Developer Portal
  2. Under your app's User authentication settings, enable OAuth 2.0 and set the app type to Web App
  3. Add a callback URI: https://your-domain.com/auth/twitter/callback
  4. Under App permissions, request at least Read access
  5. Copy the OAuth 2.0 Client ID and generate a Client Secret into your environment

Development

npx nx build auth-twitter   # compile
npx nx test auth-twitter    # run tests
npx nx lint auth-twitter    # lint

Publishing

npx nx build auth-twitter
cd packages/auth-twitter
npm publish --access public