redouane59 / twittered

Twitter API client for Java developers
Apache License 2.0
235 stars 64 forks source link

"oauth_token can't be null" when requesting request token #358

Open ghost opened 2 years ago

ghost commented 2 years ago

Hi there,

I try to build a login flow. For this I need to create a url to authenticate. I tried it with the following code:

val twittered = TwitterClient(
   TwitterCredentials.builder()
      .apiKey("my_key")
      .apiSecretKey("my_secret")
      .build()
)

val token = twittered.getOauth1Token("my_callback")
println("https://twitter.com/oauth/authenticate?oauth_token=${token.oauthToken}")

But then I get this expection:

Exception in thread "main" java.lang.IllegalArgumentException: oauth_token can't be null
    at com.github.scribejava.core.utils.Preconditions.check(Preconditions.java:49)
    at com.github.scribejava.core.utils.Preconditions.checkNotNull(Preconditions.java:19)
    at com.github.scribejava.core.model.OAuth1Token.<init>(OAuth1Token.java:18)
    at com.github.scribejava.core.model.OAuth1AccessToken.<init>(OAuth1AccessToken.java:17)
    at com.github.scribejava.core.model.OAuth1AccessToken.<init>(OAuth1AccessToken.java:13)
    at io.github.redouane59.twitter.signature.TwitterCredentials.asAccessToken(TwitterCredentials.java:26)
    at io.github.redouane59.twitter.helpers.RequestHelper.signRequest(RequestHelper.java:71)
    at io.github.redouane59.twitter.helpers.AbstractRequestHelper.makeRequest(AbstractRequestHelper.java:88)
    at io.github.redouane59.twitter.helpers.AbstractRequestHelper.makeRequest(AbstractRequestHelper.java:81)
    at io.github.redouane59.twitter.helpers.AbstractRequestHelper.makeRequest(AbstractRequestHelper.java:59)
    at io.github.redouane59.twitter.helpers.RequestHelper.postRequestWithBodyJson(RequestHelper.java:27)
    at io.github.redouane59.twitter.helpers.RequestHelper.postRequest(RequestHelper.java:31)
    at io.github.redouane59.twitter.TwitterClient.getOauth1Token(TwitterClient.java:1216)
        ...

I tought this method is for obtaining a initial request token. With this token I wanted to build a url to authenticate and then afterwards request an access token. Why I need a token to "initialze the login process"?

Thanks

redouane59 commented 2 years ago

Can you try to use twittered.getOauth1Token("oob"); instead? Is it working ?

ghost commented 2 years ago

Hi @redouane59 , this was actually the first thing I tried when I ran into the error. But no luck...

Isn't it wrong that it tries to get an access token?

redouane59 commented 2 years ago

No on my side it was working. This test uses that : twittered/ITwitterClientV1Test.java at 4003f42215a13457a8627d0a5d443bc640ae3abd · redouane59/twittered

Are you sure about your credentials ? I'll try to perform the test again on my side tonight.

ghost commented 2 years ago

Yeah I use the same credentials with a other library (twitter4j). I was looking for an alternative. This one here looks really promising :)

redouane59 commented 2 years ago

Hmmm honestly it's hard for me to debug because on my side, it is working correctly with oob parameter. If you run the testGetOauth1Token test in ITwitterClientV1Test class, does it work ? You just have to put your credentials in test-twitter-credentials.json .

Did you also try to test it using postman ? Is it working ?

ghost commented 2 years ago

As I said it works with another library. Just to make sure there is no misunderstanding here: What do you mean with "your credentials"? As far as I remember the examples in the README assume a consumerKey, consumerSecret, accessToken and accessTokenSecret. I could generate the last two for my personal account but I don't want that. In other projects I "start" with consumerKey and consumerSecret...then the user goes through the login process and graps their personal token(secret).

I mention that because I always struggling a bit with the oauth stuff...maybe my assumption is wrong...but for now we're on the same page. :)

Do you used your consumer credentials only? Or do you also used your (personal) access token? That would explain why it's working on your side.

redouane59 commented 2 years ago

As far as I remember the examples in the README assume a consumerKey, consumerSecret, accessToken and accessTokenSecret. I could generate the last two for my personal account but I don't want that. In other projects I "start" with consumerKey and consumerSecret...then the user goes through the login process and graps their personal token(secret).

Yes this is correct. Like the unit test :

  @Test
  public void testGetOauth1Token() {
    twitterClient.getTwitterCredentials().setAccessToken("");
    twitterClient.getTwitterCredentials().setAccessTokenSecret("");
    RequestToken result = twitterClient.getOauth1Token("oob");
    assertTrue(result.getOauthToken().length() > 1);
    assertTrue(result.getOauthTokenSecret().length() > 1);
    //twitterClient.getOAuth1AccessToken(result, "12345");
  }

Just the API key and the API secret key are used, nothing else

Can you confirm this unit test is not working on your side ? If no can you try to debug ? As far as it works on my side, really hard to understand the problem :(

ghost commented 2 years ago

Hi @redouane59,

sorry for the late response. I took some time but I think I hunted it down:


class OAuthTest {

    @Test
    fun `should receive a oauth token with EMPTY access credentials`() {
        val client = TwitterClient(
            TwitterCredentials.builder()
                .apiKey(API_KEY)
                .apiSecretKey(API_KEY_SECRET)
                .accessToken("")
                .accessTokenSecret("")
                .build()
        )

        val result = client.getOauth1Token("oob")
        assertTrue(result.oauthToken.length > 1)
        assertTrue(result.oauthTokenSecret.length > 1)
    }

    @Test
    fun `should receive a oauth token with MISSING access credentials`() {
        val client = TwitterClient(
            TwitterCredentials.builder()
                .apiKey(API_KEY)
                .apiSecretKey(API_KEY_SECRET)
                .build()
        )

        val result = client.getOauth1Token("oob")
        assertTrue(result.oauthToken.length > 1)
        assertTrue(result.oauthTokenSecret.length > 1)
    }
}

The test with missing credentials is failing. And as far as I can see your test only tests that the credentials are set to empty string.

Regards

PS.: I also noticed that you test suite for "V1" is annotated with @Disabled

redouane59 commented 2 years ago

Hey @gh-kirito ,

Sorry i'm really busy these days, do you feel that you could submit a pull request to implement what you need ?

ghost commented 2 years ago

To be honest, for now I am fine with setting accessToken and accessTokenSecret to empty string. That works for. Maybe that is not the expected behavior in the first place but it is ok.