twittersignin
v1.2.0
Published
Straightforward implementation of Sign in with Twitter
Downloads
126
Maintainers
Readme
twittersignin
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:
- The flow sends params as form data, not JSON or query params like the other APIs.
- The flow uses some additional OAuth parameters (
callback
) which must be included in the OAuth header. - The success response is in query string format, not JSON.
- 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 theoauth_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 useroauth_token_secret
: The access token secret for the userscreen_name
: user's Twitter usernameuser_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: