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

oauth2-cli

v1.1.4

Published

Acquire API access tokens via OAuth 2.0 / OpenID Connect within CLI tools

Readme

oauth2-cli

Acquire API access tokens via OAuth 2.0 / OpenID Connect within CLI tools

npm version Module type: ESM

Install

npm i oauth2-cli

Usage

import { Client, FileStorage } from 'oauth2-cli';

type ExpectedResponse = {
  value: string;
};

const client = new Client({
  name: 'Example API',
  reason: 'an example script',
  credentials: {
    client_id: 'm3C6dGQJPJrvgwN97mTP4pWVH9smZGrr',
    client_secret: '2XUktyxU2KQmQAoVHxQXNaHZ4G7XqJdP',
    redirect_uri: 'http://localhost:3000/example/redirect',
    authorization_endpoint: 'https://example.com/oauth2/auth',
    token_endpoint: 'https://example.com/oauth2/token'
  },
  storage: new FileStorage('/path/to/token/file.json');
});
console.log(
  client.fetchJSON<ExpectedResponse>('https://example.com/path/to/api/endpoint')
);

Broadly speaking, having provided the configuration, the client is immediately ready to accept requests. If an stored access token is available, it will be used (and transparently refreshed as necessary, if possible). If no access token is available, the authorization flow will be triggered by the request, opening a browser window for the user to sign in and provide their authoriztion.

Instantiate a Client

credentials

A Client requires some minimal information in order to interact with an OAuth 2.0 authorized API. The OAuth 2.0 base credentials set is a client_id, client_secret, authorization_endpoint, token_endpoint, and a redirect_uri. For an OpenID-authenticated API, you could provide a client_id, client_secret, issuer, and redirect_uri and the Client will query the issuer for further details regarding required connection parameters (it is built on to of openid-client).

name and reason

It is strongly recommended that you provide a human-readable name for the client that will be used in user messages explaining what is being accessed (e.g. the name of the API or service) and a human-readable reason for the user to provide this access (e.g. the name of your app or script). Messages are structured in the manner:

...to authorize access to name for reason, do this...

storage

The refresh_token can be persisted by passing an implementation of Token.Storage, such as FileStorage which expects a path to a location to store a JSON file of access token data. There are more secure ways to store your tokens, such as @oauth2-cli/qui-cli's EnvironmentStorage which can be linked to a 1Password vault.

Registering localhost redirect URLs

redirect_uri to Localhost

Since the redirect_uri is receiving the authorization code in the Authorization Code token flow, the Client needs to be able to "catch" that redirect. The easy way to do this is to register a localhost address with the API (e.g. http://localhost:3000/my/redirect/path). When such a redirect URI is given to the client, it stands up (briefly) a local web server to receive that request at the port and path provided.

Not every API accepts a localhost redirect (it creates the possibility of CORS exploits that could lead to XSS vulnerabilities). For these APIs, using gcrtl or a similar system will work as well. (In the specific case of gcrtl, oauth2-cli will trim the leading /http/localhost:<port> from provided redirect_uri and expect the remainder of the path.)

http protocol

If you would prefer an https connection to localhost, you have to roll your own SSL certificate.

Request an endpoint

request()

As noted above, oauth2-cli is built on top of openid-client. The request() method is a pass-through to the openid-client fetchProtectedResource() function, with the configuration and accessToken managed by the Client.

class Client {
  // ...

  public async request(
    url: requestish.URL.ish,
    method = 'GET',
    body?: requestish.Body.ish,
    headers: requestish.Headers.ish = {},
    dPoPOptions?: OpenIDClient.DPoPOptions
  ) {
    // ...
  }
}

requestish.URL.ish are more forgiving types accepting not just those specific types, but reasonable facsimiles of them.

base_url and issuer for relative paths

If you would prefer to make requests to relative paths, rather than absolute paths, either configure a base_url or include an issuer in the credentials when instantiating the client. A base_url will preempt an issuer, if both are defined (handy for when the issuer is a different subdomain than the API endpoints).

requestJSON<J>()

Given that many APIs return JSON-formatted responses, it is convenient to just get that JSON (optionally pre-typed based on what you expect to receive) rather than having to process the response yourself.

class Client {
  // ...

  public async requestJSON<
    J extends OpenIDClient.JsonValue = OpenIDClient.JsonValue
  >(
    url: requestish.URL.ish,
    method = 'GET',
    body?: requestish.Body.ish,
    headers: requestish.Headers.ish = {},
    dPoPOptions?: OpenIDClient.DPoPOptions
  ) {
    // ...
  }
}

fetch() and fetchJSON<J>()

Aliases for request() and requestJSON<J>() that use Fetch API-style arguments.

Examples

Refer to examples for more detailed usage.