Announcement Announcement Module
Collapse
No announcement yet.
401 Unauthorized Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • 401 Unauthorized

    I am trying to allow a user to connect to twitter. I have set up the connectcontroller as in the spring social example. The user is redirected to twitter, I click allow, and it redirects back to my app correctly, but I get a 401 unauthorized when it attempts to exchange the token through the rest template. Here's the stack trace:

    Code:
    org.springframework.web.client.HttpClientErrorException: 401 Unauthorized
    	org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:75)
    	org.springframework.web.client.RestTemplate.handleResponseError(RestTemplate.java:486)
    	org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:443)
    	org.springframework.web.client.RestTemplate.execute(RestTemplate.java:401)
    	org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:377)
    	org.springframework.social.oauth1.OAuth1Template.getTokenFromProvider(OAuth1Template.java:113)
    	org.springframework.social.oauth1.OAuth1Template.exchangeForAccessToken(OAuth1Template.java:102)
    	org.springframework.social.web.connect.ConnectController.oauth1Callback(ConnectController.java:146)
    I turned on the debugger and stepped through and it worked correctly, so I'm not sure if my timestamp is off or something. Once I did this recorded the following info within ConnectController:

    Code:
    request parameters:  {oauth_token=97Iep0zIjGem38dJfPJWMu5F7S7MV079pph80D2P8Q, oauth_verifier=sBPMoP3BXcxqCsV5z3qzDlyUKCXY6lzP3cPw74wN8E}
    
    
    
    token secret:  {oauth_token=97Iep0zIjGem38dJfPJWMu5F7S7MV079pph80D2P8Q, oauth_verifier=sBPMoP3BXcxqCsV5z3qzDlyUKCXY6lzP3cPw74wN8E}
    
    
    headers: 
    Authorization=[OAuth oauth_version="1.0", oauth_nonce="6820bc9d-5301-41fc-9153-b3749dc35ffd", oauth_signature_method="HMAC-SHA1", oauth_consumer_key="AX7rm1dATVSM1HKAVVl2w", oauth_token="97Iep0zIjGem38dJfPJWMu5F7S7MV079pph80D2P8Q", oauth_verifier="sBPMoP3BXcxqCsV5z3qzDlyUKCXY6lzP3cPw74wN8E", oauth_timestamp="1300630257", oauth_signature="bcAqHWFo6ztOXVnQTFP05zIqRbY%3D"]}
    
    
    error response:
    {Date=[Sun, 20 Mar 2011 14:28:45 GMT], Server=[hi], Status=[401 Unauthorized], X-Transaction=[1300631325-94860-61806], Last-Modified=[Sun, 20 Mar 2011 14:28:45 GMT], X-Runtime=[0.00741], Content-Type=[text/html; charset=utf-8], Content-Length=[1], Pragma=[no-cache], X-Revision=[DEV], Expires=[Tue, 31 Mar 1981 05:00:00 GMT], Cache-Control=[no-cache, no-store, must-revalidate, pre-check=0, post-check=0], Set-Cookie=[k=98.24.46.159.1300631325234674; path=/; expires=Sun, 27-Mar-11 14:28:45 GMT; domain=.twitter.com, guest_id=130063132524132408; path=/; expires=Tue, 19 Apr 2011 14:28:45 GMT, _twitter_sess=BAh7CDoPY3JlYXRlZF9hdGwrCDoKq9MuAToHaWQiJTM3OWIwZjljYThiZDg4%250AYWNhMThjNjJkNzI2NTVjNjY4IgpmbGFzaElDOidBY3Rpb25Db250cm9sbGVy%250AOjpGbGFzaDo6Rmxhc2hIYXNoewAGOgpAdXNlZHsA--2dfeb74ba30d2a05bfc40afdc50aeb626b4e504b; domain=.twitter.com; path=/; HttpOnly], X-XSS-Protection=[1; mode=block], X-Frame-Options=[SAMEORIGIN], Vary=[Accept-Encoding], Keep-Alive=[timeout=15, max=99], Connection=[Keep-Alive]}

    Any ideas on where I should look next? I'm really thrown off by the fact that when I stepped through the debugger it worked. I tried moving my time forward by a minute locally but that didn't solve the problem.

  • #2
    I've exactly the same behaviour.


    This evening, i will try to use my consumer key + secret on spring-social-showcase demo app or use their values in my app.

    Just be sure that theses generated values are ok.
    Last edited by bguerout; Mar 21st, 2011, 06:38 AM. Reason: typo + add info

    Comment


    • #3
      There has been quite a bit of discussion on the Twitter discussion list (http://groups.google.com/group/twitt...1865585b129b5#) over the weekend regarding 401s coming from Twitter and some in the discussion seem to believe it is time related (as jespey has suggested). The last word in the discussion is that they're looking into it.

      FWIW, I tried it with the showcase just a moment ago and it worked fine. But that's not to say that there isn't a problem...just that I didn't experience it.

      Another thing to check: I've occasionally seen 401s during the connection process if I fail to set a callback URL when registering the application. When you registered your application with Twitter, did you set it to be a "Browser" application and specify a callback URL?

      Comment


      • #4
        401 Unauthorized

        Thanks Craig. I did specify browser and a callback. In my case, I'm not getting the 401 until the auth callback hits my server. So it finds my application fine and twitter asks the user if they want to allow my app to connect. It's when the oauth callback is invoked that I get the 401. So it appears that my key and secret are correct.

        Comment


        • #5
          Seems to be fixed

          For what it's worth, it appears that it must have been a twitter issue as my code is working now with no changes from what I was trying yesterday.

          Comment


          • #6
            never mind

            I take that back, it worked when I stepped through a debugger again, so I'm thinking it has to be a timing issue. It looks like their authorization appears to be "expired" unless I delay by a few moments as I step through the debugger.

            Comment


            • #7
              Try using this TwitterServiceProvider instead; I rewrote the URLs to point at the non-SSL Twitter API. It works for me, and others have reported success as well using the non-SSL servers.

              https://gist.github.com/894348

              Comment


              • #8
                Yes, there are two workarounds for this problem:

                1. Put at 15 second or more delay between obtaining the request token and exchanging for the access token. For example, if the user were to delay for 15 seconds before agreeing to the access.
                2. Use HTTP instead of HTTPS

                Neither of these is ideal. #1 is absurd and #2 just leaves the exchange of the access token vulnerable.

                Twitter is aware of this issue (http://code.google.com/p/twitter-api...detail?id=2118) and is supposedly working on it. But as you can see from the comments on that issue, this has been going on awhile and no resolution yet.

                Comment


                • #9
                  I ran into this deploying on a test server while it didn't occur in my dev environment. From their comments in the thread, it seems they think they solved it, when they obviously haven't

                  Comment


                  • #10
                    They did fix this problem quite some time ago and I've not had any issue with it lately. Even if it were still a problem, it'd be consistently a problem on your test server and your dev environment. If you're running into trouble in one environment, but not in another, then there's probably something out of sorts with regard to that environment.

                    Out of curiosity: Is it the exact same stack trace as show above?

                    Comment


                    • #11
                      no

                      Actually, not exactly

                      PHP Code:
                      org.springframework.web.client.HttpClientErrorException401 Unauthorized
                              at org
                      .springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:75)
                              
                      at org.springframework.web.client.RestTemplate.handleResponseError(RestTemplate.java:486)
                              
                      at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:443)
                              
                      at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:415)
                              
                      at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:391)
                              
                      at org.springframework.social.oauth1.OAuth1Template.exchangeForToken(OAuth1Template.java:195)
                              
                      at org.springframework.social.oauth1.OAuth1Template.fetchRequestToken(OAuth1Template.java:116)
                              
                      at org.springframework.social.connect.web.ConnectSupport.buildOAuth1Url(ConnectSupport.java:124)
                              
                      at org.springframework.social.connect.web.ConnectSupport.buildOAuthUrl(ConnectSupport.java:84)
                              
                      at org.springframework.social.connect.web.ProviderSignInController.signIn(ProviderSignInController.java:118

                      Comment


                      • #12
                        I'm just wondering if this has to do something with the calling domain.
                        I tested on my dev environment which uses a hosts file based :90 address which is different from the authorized domain. This worked fine each and every time.
                        The acceptance server is at Rackspace and uses .acc.domain as domain and this one actually has been added to the authorized domains @twitter. This fails each and every time.

                        Comment


                        • #13
                          When you say "authorized domain", do you mean the entries under the "@Anywhere domains" tab on Twitter? If so, then that shouldn't have anything to do with it. Those are for some of Twitter's Javascript widgets from their @Anywhere JS library. Even the callback URL in the application settings is flexible because ConnectController/ProviderSignInController will always send a callback URL to override the configured one.

                          In your stack trace, it appears to be failing when it gets the request token, via the call to OAuth1Template.fetchRequestToken(). At that point, the callback URL is the only thing passed in. So, either the OAuth1Template is misconfigured (because the TwitterConnectionFactory was given the wrong consumer key/secret) or the callback URL is bad.

                          I don't believe Twitter does anything with the callback URL at this point other than note it for future use--in fact, I've tested this with completely made-up URLs and it works fine. (I've even tested it with things that don't look like URLs, eg. "xxxxxx", and it still fetches a request token for me.) So, if I were guessing, I'd say something's not right about your TwitterConnectionFactory configuration and the consumer key/secret pair. If those are wrong, you'd definitely get a 401 at that point.

                          Comment


                          • #14
                            ok

                            Based on your reply I think it may be because my web server adds slashes to rest urls without slashes and redirects. My redirect url was without slashes. Awesome, thanks for the info.

                            Comment


                            • #15
                              Nope, no luck. This is also reported

                              RestTemplate.handleResponseError(478) | POST request for "https://api.twitter.com/oauth/request_token" resulted in 401 (Unauthorized); invoking error handler

                              Comment

                              Working...
                              X