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

@frejun/oauth

v1.0.4

Published

FreJun OAuth 2.0 SDK — browser popup flow, token management, and event-driven token notifications

Readme

@frejun/oauth

FreJun OAuth 2.0 SDK for TypeScript / JavaScript. Handles the browser popup authorization flow, token management, and notifies your app of token changes via events.

Installation

npm install @frejun/oauth

Quick Start

import { FrejunOAuth } from '@frejun/oauth';

const oauth = new FrejunOAuth({
  clientId: 'YOUR_CLIENT_ID',
  clientSecret: 'YOUR_CLIENT_SECRET',
  redirectUri: 'https://yourapp.com/callback', // optional
  extraParams: { state: 'random-csrf-token' }, // optional
});

// Listen for new tokens
oauth.on('tokens', (data) => {
  console.log('Access token:', data.access_token);
  console.log('Refresh token:', data.refresh_token);
  console.log('Expires in:', data.expires_in);
});

// Listen for refreshed tokens
oauth.on('tokensRefreshed', (data) => {
  console.log('New access token:', data.access_token);
  console.log('New refresh token:', data.refresh_token);
});

// Listen for errors
oauth.on('error', (err) => {
  console.error('OAuth error:', err.message);
});

// Open the FreJun consent popup (browser only)
oauth.openAuthPopup();

API

new FrejunOAuth(config)

| Option | Type | Required | Description | |---|---|---|---| | clientId | string | Yes | Your FreJun OAuth app client ID | | clientSecret | string | Yes | Your FreJun OAuth app client secret | | redirectUri | string | No | Override the registered redirect URI | | extraParams | Record<string, string> | No | Extra query params (state, username, etc.) |

Methods

getAuthorizationUrl()

Returns the FreJun authorization URL as a string.

openAuthPopup(options?)

Opens the consent page in a popup and listens for the auth code via postMessage. By default, automatically exchanges the code for tokens. Pass { generateTokens: false } to skip token generation (useful when tokens are generated on your backend). Browser only.

createTokens(code)

Exchange an auth code for tokens. Emits 'tokens'. Returns:

{
  success: boolean;
  message: string;
  access_token: string;
  refresh_token: string;
  expires_in: number;       // seconds
  token_type: string;
  org_identifier: string;
  // On error: statusCode is also included
  statusCode?: number;
}

refreshTokens(refreshToken)

Refresh an expired access token. Emits 'tokensRefreshed'. Returns:

{
  success: boolean;
  message: string;
  access_token: string;
  refresh_token: string;
  expires_in: number;       // seconds
  org_identifier: string;
  // On error: statusCode is also included
  statusCode?: number;
}

verifyToken(token)

Check whether an access or refresh token is valid. Returns:

// Valid token
{ is_valid: true }

// Invalid token or API error
{ is_valid: false; statusCode?: number; [key: string]: unknown }

disconnect(refreshToken)

Disconnect the OAuth app from the organization. Revokes all tokens for this organization. Returns:

{
  success: boolean;
  message: string;
  // On error: statusCode is also included
  statusCode?: number;
}

destroy()

Clean up all listeners and close any open popup.

Events

| Event | Payload | When | |---|---|---| | authCode | { code, email, ...extraParams } | Auth code received from popup | | tokens | CreateTokenResponse | Tokens created from an auth code | | tokensRefreshed | RefreshTokenResponse | Tokens refreshed | | error | Error | Any error during the flow |

on(event, listener)

Subscribe to an event. The listener is called every time the event fires.

// Called on every token refresh
oauth.on('tokensRefreshed', (data) => {
  saveTokens(data.access_token, data.refresh_token);
});

once(event, listener)

Subscribe to an event, but the listener is automatically removed after it fires once.

// Only capture the first set of tokens
oauth.once('tokens', (data) => {
  console.log('Initial tokens received:', data.access_token);
});

off(event, listener)

Remove a previously registered listener.

const handler = (data) => { /* ... */ };
oauth.on('tokens', handler);
// Later, unsubscribe
oauth.off('tokens', handler);

Backend Token Generation

If you need to generate tokens on your server instead of the browser, disable automatic token exchange and listen for the authCode event:

oauth.on('authCode', async ({ code, email, ...params }) => {
  // Send the code to your backend for token generation
  await fetch('/api/auth/frejun', { // your backend endpoint
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ code, email, ...params }),
  });
});

oauth.openAuthPopup({ generateTokens: false });

Error Handling

API calls never throw for HTTP-level errors. Instead, all functions return an error object containing the API's response body merged with a statusCode field. You can detect failures by checking a success field (present on most endpoints) or is_valid for verifyToken.

const result = await oauth.verifyToken(token);
if (result.is_valid) {
  // token is valid
} else {
  // result contains { is_valid: false, statusCode, ...apiErrorFields }
  console.error('Invalid token:', result);
}

const tokens = await oauth.createTokens(code);
if (!tokens.success) {
  // tokens contains { success: false, statusCode, message, ...apiErrorFields }
  console.error('Token creation failed:', tokens.message);
}

Only network-level failures (e.g. no internet connection) will result in a thrown error or an emitted 'error' event.

Notes

  • The authorization code expires in 10 minutes.