0
votes

I'm trying to get the ability to write to someone's Twitter account through Java and Spring Social.

Whenever I request write access through my application on twitter, I get the following exception:

org.springframework.social.NotAuthorizedException: Invalid or expired token
    org.springframework.social.twitter.api.impl.TwitterErrorHandler.handleClientErrors(TwitterErrorHandler.java:104)
    org.springframework.social.twitter.api.impl.TwitterErrorHandler.handleError(TwitterErrorHandler.java:58)
    org.springframework.web.client.RestTemplate.handleResponseError(RestTemplate.java:537)

However, when I turn off access, I don't get this exception, but I (obviously) lose the ability to write. From all the research I have done, I have yet to be able to find anything about spring social except that I need an access token. I cannot find Spring Social documentation that tells me where to get that.

Anyway, this is in my controller:

@Autowired
ConnectionRepository connectionRepository

private Twitter getTwitter() {
    connectionRepository.findPrimaryConnection(Twitter.class).api
}

@RequestMapping(value = "/connect/twitter/connect/twitter")
String loggedIn(Model model) {
    if (twitter?.authorized) {
        model.addAttribute("screenName", twitter.userOperations().screenName)
        twitter.timelineOperations().updateStatus("Welcome to Miami #helloWorld")   
        HOME
    }
    else {
        "redirect:/twitter"
    }
}

My ConnectionRepository implementation is a basic one for MongoDB. I don't think it is the issue, but if it is it is nearly identical to: https://github.com/CarloMicieli/spring-social-mongo/blob/master/src/main/java/org/springframework/social/connect/mongo/MongoConnectionRepository.java

Here is my dispatch xml:

<bean class="org.springframework.social.connect.web.ConnectController">
    <property name="applicationUrl" value="http://localhost:8081/MinnesotaCows/" />
</bean>
<bean class="org.springframework.social.connect.web.ProviderSignInController">
    <property name="applicationUrl" value="http://localhost:8081/MinnesotaCows/" />
    <property name="signUpUrl" value="/register" />
</bean>
<bean id="twitterConnectionFactory"
    class="org.springframework.social.twitter.connect.TwitterConnectionFactory">
    <constructor-arg value="bUC8VEWgkfkeTXuTBuxCg" />
    <constructor-arg value="5I1CNYKBCkNbsbgL2JfTNdSnSA9JVY4KHI4myxV7k4" />
</bean>
<bean id="connectionFactoryLocator"
    class="org.springframework.social.connect.support.ConnectionFactoryRegistry">
    <property name="connectionFactories">
        <list>
            <ref bean="twitterConnectionFactory" />
        </list>
    </property>
</bean>
<bean id="textEncryptor" class="org.springframework.security.crypto.encrypt.Encryptors"
    factory-method="noOpText" />

Note: I'm running at localhost. Could the problem be that? Since there is no callback? Also, I'm not using the signUpUrl in the ProviderSignInController for anything. I'm not quite sure what that is for either.

Anyone have any ideas on what I might be doing wrong - or how I can exactly get the access token through the API?

Thanks for your time!

1

1 Answers

0
votes

I haven't tested CarloMicieli's mongo based connection repositories, but looking the code I can see that primary connection is the first connection created. This is the same behavior that the built in jdbc based repository in Spring Social has. But I think it's wrong, primary connection should be always the last issued connection/login to the provider (the connection with rank 1 can be expired even though there are newer connections).

You could try to empty the connections collection in your mongo db and test if your code works after that. If the token works then, it is the issue that I described.

I have created my own mongo based social repositories that rank the connections by timestamp and order them so that the last issued connection is the primary one. That way you can issue multiple logins and the last login will be the primary connection.

See reference from github: https://github.com/trautonen/spring-social-mongodb/tree/master/src/main/java/org/eluder/spring/social/mongodb

You also defined ConnectController which map the social provider connection paths. You can initialize login flow by doing POST request to /connect/twitter and if completed without problems should result a working connection in your connections collection in mongodb.

See full reference here: http://docs.spring.io/spring-social/docs/1.1.0.RELEASE/reference/htmlsingle/#creating-connections-with-connectcontroller