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

twittersignin

v1.2.0

Published

Straightforward implementation of Sign in with Twitter

Downloads

259

Readme

twittersignin

npm version npm

This library exists because Twitter's Sign In With Twitter flow is substantially different from the rest of its APIs. It's also terribly documented.

Here are some of the differences:

  1. The flow sends params as form data, not JSON or query params like the other APIs.
  2. The flow uses some additional OAuth parameters (callback) which must be included in the OAuth header.
  3. The success response is in query string format, not JSON.
  4. Some error responses are in XML format (yep!🤷‍♂️), others are in JSON, others are just plain strings.

It's easy to get a lot wrong. It's very likely you'll spend hours implementing Sign In With Twitter in your app. This library aims to make it simple by abstracting away the differences and problems.

Internally, this library is a wrapper around Twit (pinned at version 2.2.11). Twit provides a nice, consistent interface for accessing the Twitter APIs, but does not support these Twitter Sign In APIs. This library modifies some of Twit's internal behaviour to support them. The success responses are the same as the data object in Twit, and the errors thrown are the same as when using Twit.

Usage

Install via npm:

npm i twittersignin

Initialize with your app's default credentials:

const twitterSignIn = require('twittersignin')({
    consumerKey: process.env.TWITTER_CONSUMER_KEY,
    consumerSecret: process.env.TWITTER_CONSUMER_SECRET,
    accessToken: process.env.TWITTER_ACCESS_TOKEN,
    accessTokenSecret: process.env.TWITTER_ACCESS_TOKEN_SECRET,
});

As described by the Twitter docs, the sign in process is in 4 steps:

⚠ Make sure to go through the Twitter doc first, as this is only intended to complement that.

Step 1 — When the user clicks "Sign in with Twitter": Fetch a request token from Twitter

To start the process, your user needs to click a "Sign In With twitter" link/button. Create one and add it to your web site. This link will point to a route on your backend. In this route, your backend should fetch a request token from Twitter. Here's how to do that:

const response = await twitterSignIn.getRequestToken();
const requestToken = response.oauth_token;
const requestTokenSecret = response.oauth_token_secret;
const callbackConfirmed = response.oauth_callback_confirmed;

You can pass in optional parameters:

await twitterSignIn.getRequestToken({
    oauth_callback: "https://yourcallback.url?query=param",
    x_auth_access_type: "read",
})

The response contains three parameters:

  • oauth_callback_confirmed: You should check that this value === true before proceeding.
  • oauth_token. This is the request token. You'll use it in the next step.
  • oauth_token_secret: This is the request token secret. You'll need it in the third step.

⚠ Make sure to store the request token secret somewhere. I recommend a cache, so it can expire automatically after a few minutes (the token is short-lived).

Here's one way to store it (using Redis):redis.set(tokens-${requestToken}, requestTokenSecret, 'EX', 5 * 60);Here, we're storing it using the token as the key, so we can easily look it up in Step 3.

Step 2 — Redirect the user to Twitter

When you have the request token, the next step is to redirect the user to Twitter. You can redirect either to /oauth/authenticate for one-time auth, or /oauth/authorize if you want the user to always have to authorize your app.

⚠ Make sure it's a 302 (temporary) redirect, so browsers don't cache it!

res.redirect(`https://api.twitter.com/oauth/authorize?oauth_token=${requestToken}`, 302);

The user's browser will then take them to Twitter where they can sign in to Twitter (if needed) and authorize your app.

When the authorization is successful, Twitter will redirect to your provided callback URL with two query parameters (in addition to any you added when calling getRequestToken):

  • oauth_token: Same value as the oauth_token in Step 1 (the request token).
  • oauth_verifier: some random string

Step 3 — When Twitter redirects to your app: Get an access token

Next, your callback route needs to handle the redirect from Twitter. You want to get an access token. This will allow you to access the user's twitter account (get their account details, read their timeline, post tweets and so on—depending on your earlier requested permissions).

Here's how to get an access token:

// Get the oauth_verifier query parameter
const oauthVerifier = req.query.oauth_verifier;
// Get the oauth_token query parameter. 
// It's the same as the request token from step 1
const requestToken = req.query.oauth_token;
// Get the request token secret from whjere we stored it (Step 1)
const requestTokenSecret = await redis.get(`tokens-${requestToken}`);

const response = await twitterSignIn.getAccessToken(requestToken, requestTokenSecret, oauthVerifier);

We're done! The response should contain four values:

  • oauth_token: The access token for the user
  • oauth_token_secret: The access token secret for the user
  • screen_name: user's Twitter username
  • user_id

Step 4 (Optional) — Fetch the user

Once you have the access token and access token secret, you can interact with the Twitter API as you would normally, but with the user's tokens to act as that user. For instance:

const Twit = require("twit");
const t = new Twit({
    consumerKey: process.env.TWITTER_CONSUMER_KEY,
    consumerSecret: process.env.TWITTER_CONSUMER_SECRET,
    accessToken,
    accessTokenSecret,
});
// Fetch the user's mentions
await t.get('statuses/mentions_timeline');

If you just want to fetch the user's profile, this package includes a convenience method to help with that:

const user = twitterSignIn.getUser(accessToken, accessTokenSecret);
if (user.followers_count > 1000) {
 // ...
}

A few notes

Responses

This package returns the data section from Twit responses, so you can get directly to the data you need.

Error handling

Error handling in this package is designed to be the same as Twit. Anything other than success responses will reject with an error. The errors are in this format:

{
    // HTTP status code
    statusCode: number,

    // Simplified error message
    message: string,

    // Twitter API error code
    code: number,
    
    // List of errors. Usually these errors are of the form {code: string, message: string}
    // But they may also be strings
    allErrors: [], 

    // Full response from Twitter. JSON-parsed where possible.
    twitterReply: object|string, 
}

Doing more work with the Twitter API?

Check out some of my other libraries: