Integrating with twitter API to send tweets via oauth 1.0 with kotlin and springboot social

Published Jun 26, 2022

Recently I’ve been working on a side project called “Social publisher”, the goal is to allow developers to schedule posts and then having a tool to publish the scheduled content automatically.

Some of the tools already in the market does that, but they require paid subscription whenever a limit of scheduled posts has been reached (talking about hootsuite). The idea with social publisher is to avoid such limitations and offer seamlessly sharing tools.

To get going with social publisher, tweeter was the first social network that was chosen to be integrated, mostly because this is the social media I use the most. With that decision, some challenges came in order to send tweets via tweeter api, those challenges and learnings are shared here.

Tweeter API

Tweeter offers an API to share content and strongly encourages developers to use Oauth 2 instead of Oauth 1 [1]. Oauth 2 has improvements compared to the version 1, nevertheless the integration is a bit more complex, it requires more calls and tokens exchange. Therefore, Oauth 1 require some logic to build up the request and make it valid.

In order to progress “fast” and see if Social Publisher would work, the decision taken was to implement Oauth 1 instead of 2, as it requires less steps to authenticate and send a tweet.

Setting up permissions

In order to use Oauth 1, you will need elevated access in the twitter application, otherwise the following warnings is shown:

WARNING: POST request for "https://api.twitter.com/1.1/statuses/update.json" resulted in 403 (Forbidden); invoking error handler
org.springframework.social.OperationNotPermittedException: You currently have Essential access which includes access to Twitter API v2 endpoints only. If you need access to this endpoint, you’ll need to apply for Elevated access via the Developer Portal. You can learn more here: https://developer.twitter.com/en/docs/twitter-api/getting-started/about-twitter-api

To set up the correct permission for the app to be able to post things on behalf of the user, the first step is to go over the twitter developer portal and:

  1. Go to Products
  2. Go to Twitter API v2
  3. In the right side, under the page tabs click on “Elevated”
  4. Follow up the instructions to elevate the permission

Twitter portal asks about different things and the purpose of the app and the reasons why it needs elevated permissions. If the data is filled, the elevated permissions happens automagically.

Custom Oauth 1 header

As already mentioned, building a Oauth 1.0 request is no trivial task, many attempt to build its own, but even twitter documentation advises that it is difficult and there are some tools such as postman that make this part easier. To build the integration on Social publisher, at first, it was tried the custom way, but it didn’t work.

While in the making of the custom header to build up the Oauth 1.0 request a gist was found from robotdan that needed to do the same, the only key difference is that the code is in java instead of kotlin.

Using Spring boot social

The alternative found was to use a Spring Boot package (that can also be used in projects that are not only spring boot), the package has been discontinued, but it still works.

The easy part is that it requires just the credentials used to generate the valid request and everything else is hidden under the package’s implementation, it requires the keys to exchange and sign the request and nothing more, apart of the tweet text. The following code was extracted from the social publisher repository:

package adapters.outbound.social

import application.entities.SocialConfiguration
import application.entities.SocialPosts
import application.socialnetwork.TwitterClient
import org.springframework.social.twitter.api.impl.TwitterTemplate // <----

class SocialSpringTwitterClient(
    private val configuration: SocialConfiguration,
): TwitterClient {
    override fun sendTweet(text: String): SocialPosts {
        val twitter = TwitterTemplate(
            configuration.twitter!!.consumerKey,
            configuration.twitter!!.consumerSecret,
            configuration.twitter!!.accessToken,
            configuration.twitter!!.accessTokenSecret,
        )

        val tweet = twitter.timelineOperations().updateStatus(text)
        return SocialPosts(
            id = null,
            text = text,
            socialMediaId = tweet.id.toString()
        )
    }
}

It is worth to mention that the handling of the errors that the package does is seamless, so for example, exceptions are thrown when the tweet is greater than the allowed characters and also if the limit of requests is reached.

References

  1. [1]E. E. Hammer-Lahav, “The OAuth 1.0 Protocol,” 2010 [Online]. Available at: https://datatracker.ietf.org/doc/html/rfc5849. [Accessed: 03-Jul-2022]