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 🙏

© 2024 – Pkg Stats / Ryan Hefner

@twitter-api-v2/plugin-token-refresher

v1.0.0

Published

User-context OAuth2 access token auto-refresher for twitter-api-v2

Downloads

3,071

Readme

@twitter-api-v2/plugin-token-refresher

Automatic OAuth2 user-context access token refresher plugin for twitter-api-v2

Twitter API v2 introduce a new way to handle user-context with OAuth2. It gives access to simple tokens, named Bearer tokens, having a dedicated lifetime (usually 2 hours).

If your Twitter app uses user-context more than this time-range, you'll need to handle token refreshes.

A token refresh is a dedicated call to have a fresh, new couple of access+refresh tokens.

To smoothen usage of API v2, this plugin allows you to completely overpass this limitation and handles the refresh for you! When a 401 or a 403 error is received from Twitter, it will refresh token automatically and restart the pending request.

Features

  • Request retry, if a request fails because your token isn't up-to-date, plugin updates token then makes the request again!
  • Concurrency, be sure that only one token refresh is made at a time (in a single-process context only! no support for concurrency within multiple processes)
  • Preventive token refresh: When a request is about to be made, but the plugin knows that stored token is expired, token refresh is made immediately
  • Hook to detect when tokens are updated, to ensure your database is always synced with current tokens
  • Hook to log refresh errors

Usage

import { TwitterApi } from 'twitter-api-v2'
import { TwitterApiAutoTokenRefresher } from '@twitter-api-v2/plugin-token-refresher'

const credentials = { clientId: '<oauth2 client ID>', clientSecret: '<oauth2 client secret>' }
// Obtained first through OAuth2 auth flow
const tokenStore = { accessToken: '', refreshToken: '' }

const autoRefresherPlugin = new TwitterApiAutoTokenRefresher({
  refreshToken: tokenStore.refreshToken,
  refreshCredentials: credentials,
  onTokenUpdate(token) {
    tokenStore.accessToken = token.accessToken
    tokenStore.refreshToken = token.refreshToken!
    // store in DB/Redis/...
  },
  onTokenRefreshError(error) {
    console.error('Refresh error', error)
  },
})

const client = new TwitterApi(tokenStore.accessToken, { plugins: [autoRefresherPlugin] })

// use {client}, if needed, token will be refreshed with {refreshToken}

Full usage within a OAuth2 auth-flow

Requirements

  • Client ID and Client secret (if applicable), obtainable from Twitter developer portal
    • We will refer to them as simple variables, clientId and clientSecret
  • A web server, even the simpliest one like an express one, but we need one to "welcome back" the user after its redirection to Twitter
    • We suppose that you use express
    • You will need to have an absolute URL used to "welcome back" the user, we will refer to it as callbackUrl
  • A store to handle login credentials and temporary tokens, it can be a simple JS object, a SQL database, a Redis server, etc
    • In this tutorial, we will use generic function calls.
      • setLoginVerifierForState(state, verifier)
      • getLoginVerifierFromState(state): verifier
      • setLoginCredentials(twitterUserId, credentials)
      • getLoginCredentials(twitterUserId): credentials

Get user credentials with a 3-legged process

Generate a login link

First, obtain access to user credentials by redirecting the user to Twitter portal, in order to "accept" your app to be linked to their profile.

import { TwitterApi } from 'twitter-api-v2'

const loginClient = new TwitterApi({ clientId, clientSecret })

// Don't forget to specify 'offline.access' in scope list, you want to refresh your token later
const { url, codeVerifier, state } = loginClient.generateOAuth2AuthLink(callbackUrl, { scope: ['tweet.read', 'users.read', 'offline.access', ...] });

// Store {state} and {codeVerifier}
setLoginVerifierForState(state, codeVerifier)

// Redirect user to {url}

Get access token after user approval

Once user has clicked on url, approved your app, they will be redirected to callbackUrl.

This should match a route on your web server. We will suppose you use /callback here, adjust with your configuration.

import { TwitterApi } from 'twitter-api-v2'

// We still need a client with same credentials as in step 1
const loginClient = new TwitterApi({ clientId, clientSecret })

app.get('/callback', async (req, res) => {
  // Extract state and code from query string
  const { state, code } = req.query;
  // Check if a verifier is associated with given state
  const codeVerifier = getLoginVerifierFromState(state)

  if (!codeVerifier || !code) {
    return res.status(400).send('You denied the app or your session expired!')
  }

  try {
    // Get tokens
    const { client, accessToken, refreshToken } = await client.loginWithOAuth2({ code, codeVerifier, redirectUri: callbackUrl })

    // Get user ID
    const concernedUser = await client.v2.me()

    // Store credentials
    setLoginCredentials(concernedUser.data.id, { accessToken, refreshToken })
  } catch (e) {
    return res.status(403).send('Invalid verifier or access tokens!')
  }
})

Use user credentials and auto-refresh token

You now have credentials for user {id}. We will now use them.

import { TwitterApi } from 'twitter-api-v2'
import { TwitterApiAutoTokenRefresher } from '@twitter-api-v2/plugin-token-refresher'

const { accessToken, refreshToken } = getLoginCredentials(id)

const autoRefresherPlugin = new TwitterApiAutoTokenRefresher({
  refreshToken,
  refreshCredentials: { clientId, clientSecret },
  onTokenUpdate(token) {
    setLoginCredentials(id, token)
  },
})

const client = new TwitterApi(accessToken, { plugins: [autoRefresherPlugin] })

// - Now, make requests -
// If token is expired, it will automatically by renewed.

await client.v2.me()

Miscellaneous

Customize settings of client used to refresh token

If you want to change settings or apply plugins to client that is used to refresh token with your clientId and clientSecret, give an instance of TwitterApi instead of your credentials:

const autoRefresherPlugin = new TwitterApiAutoTokenRefresher({
  refreshCredentials: new TwitterApi({ clientId, clientSecret }, { plugins: [rateLimitPlugin] }),
  ...
})