Displaying custom-styled tweets with OAuth

Published:

For a recent site build, our client wanted to display the content of a recent tweet in the the footer of their site. This isn’t a strange request—it’s a great option for clients to manage their social brand on their own website. And generally, this sort of request isn’t that much trouble. Twitter offers a variety of tools for embedding tweets on your website with next to no fuss. After all, it’s brand-building for Twitter as well (not that they need it, let’s be honest).

For that reason, Twitter has made it stupendously easy to embed a tweet on your site: in fact, there’s a special tweet embed link in the dropdown of every tweet on the site. Embedding a tweet is as simple as grabbing a bit of code from Twitter.com, slapping it into your HTML, and letting Twitter’s internal processes handle the rest.

The code that you get isn’t too bad, either. A nice <blockquote> and a bit of Javascript (presumably, to handle loading styles and event listeners and stuff):

<blockquote class="twitter-tweet" data-lang="en">
    <p lang="en" dir="ltr">
        We recently built a Charm Earring Builder for
        <a href="https://twitter.com/tadaandtoy?ref_src=twsrc%5Etfw">
            @tadaandtoy
        </a>
        , head over to their site today to build your perfect pair of charm earrings.
        <a href="https://twitter.com/hashtag/webdevelopment?src=hash&ref_src=twsrc%5Etfw">
            #webdevelopment
        </a>
        <a href="https://twitter.com/hashtag/javascript?src=hash&ref_src=twsrc%5Etfw">
            #javascript
        </a>
        <a href="https://twitter.com/hashtag/designstudio?src=hash&ref_src=twsrc%5Etfw">
            #designstudio
        </a>
        <a href="https://twitter.com/hashtag/jewelry?src=hash&ref_src=twsrc%5Etfw">
            #jewelry
        </a>
        <a href="https://t.co/tjBL36eWYV">
            https://t.co/tjBL36eWYV
        </a>
    </p>
    &mdash; Creator (@wearecreator_uk) 
    <a href="https://twitter.com/wearecreator_uk/status/1071044272869249024?ref_src=twsrc%5Etfw">
        December 7, 2018
    </a>
</blockquote>

<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

And with barely any effort at all on our part, voila:

That being said, Twitter’s standard tweet embed looks like a tweet—which means it’s not going to be on-brand for your client’s site. On top of that, you can be sure that Twitter loads a copious amount of Javascript along with their tweet to track who you are, what you’ve clicked, and how many pancakes you’ve had for breakfast (probably).

How copious? This is a little bit apples-to-oranges, but about as much Javascript as gzipped React + ReactDOM. Compare Twitter’s 27.7 KB widgets.js to 31.8 KB gzipped React + ReactDOM.

So instead, we’ve decided to hit Twitter’s Tweet JSON API to grab the raw tweet data from Twitter and just display the HTML content of the tweet. If you’ve got any experience working with APIs, you should be able to see the steps in your head: get some sort of authentication token from Twitter, hit a REST API with the token, get JSON, save it to some internal state on the site. Should be simple, right?

Simple, Step 1: Authenticate with Twitter

Authentication isn’t as easy as logging into your Twitter account and navigating over to developer.twitter.com to grab an API key. As detailed in a blog post from last summer, Twitter has had to lock down its API somewhat in response to increasing numbers of nefarious automation across the site from bad actors. Since then, Twitter has required API users to apply for a developer account to great applications (with associated keys) to access the API. This application process is actually a little involved, requiring you to justify what you’ll be using the access for, how you’ll be displaying tweets, and whether or not you’ll be using your access to undertake nationally-sponsored espionage.

Once you’re done with the application, Twitter will hand you back over to your apps dashboard, where you can generate an app (and where you’ll have to justify your usage a little further) and get those credentials you so desperately crave.

PROTIP: Remember to hide those credentials if you’re writing a blog post.

Right well, that’s a lot of different keys, but I’m sure that one of them will help us out.

Simple Step 2: Hit the API

Since we only want a given user’s latest tweet, we’re going to hit Twitter’s API for getting tweet timelines. This will return a list of recent tweets by user, rather than grabbing a tweet by tweet ID. It’s a simple GET request to https://api.twitter.com/1.1/statuses/user_timeline.json, which might lead you to believe that it’s a simple question of sticking an ?key=[key-goes-here] to the end of the request, and maybe a &count=1, since we only want the latest tweet.

No such luck.

A brief foray into OAuth

The Tweet JSON API is authenticated with OAuth, which I understand is quite secure but has also always been remarkably opaque to the uninitiated (viz. me). From what I understand, it involves receiving a pair of consumer keys to generate an access token, which access token is then used to actually hit the API. But it’s never been clear to me where this exchange is meant to take place; further confusing matters is many OAuth providers’ inclusion of callback URLs and salts and all sorts that Twitter doesn’t provide and that I couldn’t tell you off the top of my head. All of this, from what I understand, is scaffolding to help authenticate users of your app using systems built on other platforms. Think of how services let you sign up and log in using your Twitter/Facebook/GitHub credentials, rather than saving some new email/password combo in their database. This is build with OAuth.

Still, we don’t need any of this functionality to grab a single tweet from Twitter. We don’t need users to give our site access to their Twitter page; we’re not displaying their last tweet.

Twitter page on authenticating requests isn’t much help to someone with little more than a passing OAuth familiarity. It demands a series of oauth_ parameters passed in the Authorization header, which, although I spotted oauth_consumer_key and oauth_token and in the list of parameters, was mostly Greek to me. How to generate things like an oauth_nonce and oauth_signature was at first sighting beyond me (although I assumed that they were involved in the secret keys Twitter generated for me).

So how was I to get from my four keys to this Authorization header that Twitter wanted?

How to hit OAuth

Here comes npm to the rescue. A package with the catchy name of oauth-1.0a touts itself as the solution to your “headache about OAuth 1.0a’s stuff”, which were exactly my symptoms. The examples in the README were pretty straightforward, demanding only a couple of easy swaps to configure the module to send a GET and to use isomorphic-unfetch since this was a Next.js site.

A quick API call later, and we had our tweet!

Simple Step 3: Make it at least a little interactive

Unfortunately, the Tweet JSON API returns tweets in plaintext, without links, mentions, or hashtags represented as active, clickable <a> tags. So before we output our tweet to the footer, we’ve got to populate the text of the tweet with the links that we want.

Luckily, that’s as simple as adding a couple of helper functions to replace any hashtags and mentions with links to Twitter’s hashtag and mention URLs. I’ve also written a small function for replacing \n with <br/> so line breaks are persisted in HTML, and included linkifyjs to change plaintext links into proper HTML links.

Conclusion

And with that, we’ve got a viable HTML string to save to initial props in our Next.js site, meaning we can output that tweet anywhere we’d like on the page. And we’re in business.

Check out our Gist with the full code of everything I’ve described here if you’re still a little hazy on how it all works.