401 unauthorized with "requesttoken" request


#1

Hi,

I am getting the exception only if i include “oauth_callbackurl”. I am getting request token if “callbackurl” is not included. Here is the authorization signature and “authorization header” i am using.

Parameter string using to caluculate oauth_signature is

parameter_string=oauth_consumer_key=dsfasd&oauth_nonce=0961ce9cfcf6493bbba47a57a793de76&oauth_callback=http%3A%2F%2F127.0.0.1%3A8080%2Fcallbackurl&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1433356147&oauth_version=1.0

Authorization string:

authorization_header_string=OAuth oauth_consumer_key=“uuiii”,oauth_signature_method=“HMAC-SHA1”,oauth_timestamp=“1433356147”,oauth_nonce=“0961ce9cfcf6493bbba47a57a793de76”,oauth_callback=“http%3A%2F%2F127.0.0.1%3A8080%2Fcallbackurl”,oauth_version=“1.0”,oauth_signature=“FDPjh8lamRHsFIN2rExrU36FmuM%3D”

I am using same callbackurl in the application settings also. Please help me.


#2

What language are you using? What SDK/library are you using?


#3

I am using Java. Below is the code i am using. I am getting request token successfully if i don’t include callback url.

 public static String encode(String value) 
    {
        String encoded = null;
        try {
            encoded = URLEncoder.encode(value, "UTF-8");
        } catch (UnsupportedEncodingException ignore) {
        }
        StringBuilder buf = new StringBuilder(encoded.length());
        char focus;
        for (int i = 0; i < encoded.length(); i++) {
            focus = encoded.charAt(i);
            if (focus == '*') {
                buf.append("%2A");
            } else if (focus == '+') {
                buf.append("%20");
            } else if (focus == '%' && (i + 1) < encoded.length()
                    && encoded.charAt(i + 1) == '7' && encoded.charAt(i + 2) == 'E') {
                buf.append('~');
                i += 2;
            } else {
                buf.append(focus);
            }
        }
        return buf.toString();
    }
    
    private static  String computeSignature(String baseString, String keyString) throws GeneralSecurityException, UnsupportedEncodingException 
    {
        SecretKey secretKey = null;

        byte[] keyBytes = keyString.getBytes();
        secretKey = new SecretKeySpec(keyBytes, "HmacSHA1");

        Mac mac = Mac.getInstance("HmacSHA1");
        mac.init(secretKey);

        byte[] text = baseString.getBytes();

        return new String(Base64.encodeBase64(mac.doFinal(text))).trim();
    }
    
    
    public static JSONObject startTwitterAuthentication(String twitter_consumer_key, String twitter_consumer_secret) 
    {
    
            JSONObject jsonresponse = new JSONObject();
            
            // this particular request uses POST
            String get_or_post = "POST";
            String callback_url="http://127.0.0.1:8080/callbackurl";
            
            // I think this is the signature method used for all Twitter API calls
            String oauth_signature_method = "HMAC-SHA1";
            
            // generate any fairly random alphanumeric string as the "nonce". Nonce = Number used ONCE.
            String uuid_string = UUID.randomUUID().toString();
            uuid_string = uuid_string.replaceAll("-", "");
            String oauth_nonce = uuid_string; // any relatively random alphanumeric string will work here
            
            // get the timestamp
            Calendar tempcal = Calendar.getInstance();
            long ts = tempcal.getTimeInMillis();// get current time in milliseconds
            String oauth_timestamp = (new Long(ts/1000)).toString(); // then divide by 1000 to get seconds
            
            // assemble the proper parameter string, which must be in alphabetical order, using your consumer key'
            //String parameter_string = "oauth_consumer_key=" + twitter_consumer_key + "&oauth_nonce=" + oauth_nonce +"&oauth_callback="+encode(callback_url)+ "&oauth_signature_method=" + oauth_signature_method + "&oauth_timestamp=" + oauth_timestamp + "&oauth_version=1.0";
          
            // specify the proper twitter API endpoint at which to direct this request
            String twitter_endpoint = "https://api.twitter.com/oauth/request_token";
            String twitter_endpoint_host = "api.twitter.com";
            String twitter_endpoint_path = "/oauth/request_token";
            
            // assemble the string to be signed. It is METHOD & percent-encoded endpoint & percent-encoded parameter string
            // Java's native URLEncoder.encode function will not work. It is the wrong RFC specification (which does "+" where "%20" should be)... 
            // the encode() function included in this class compensates to conform to RFC 3986 (which twitter requires)
            String signature_base_string = get_or_post + "&"+ encode(twitter_endpoint) + "&" + encode(parameter_string);
            
            // now that we've got the string we want to sign (see directly above) HmacSHA1 hash it against the consumer secret
            String oauth_signature = "";
            try {
                oauth_signature = computeSignature(signature_base_string, twitter_consumer_secret + "&");  // note the & at the end. Normally the user access_token would go here, but we don't know it yet for request_token
            } catch (GeneralSecurityException e) {
                e.printStackTrace();
            }       
            catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
            
  
            // each request to the twitter API 1.1 requires an "Authorization: BLAH" header. The following is what BLAH should look like
            String authorization_header_string = "OAuth oauth_consumer_key=\"" + twitter_consumer_key + "\",oauth_signature_method=\"HMAC-SHA1\",oauth_timestamp=\"" + 
                    oauth_timestamp + "\",oauth_nonce=\"" + oauth_nonce + "\",oauth_callback=\""+encode(callback_url)+"\",oauth_version=\"1.0\",oauth_signature=\"" + encode(oauth_signature) + "\"";
            System.out.println("authorization_header_string=" + authorization_header_string);     // print out authorization_header_string for error checking
            
            String oauth_token = "";
            String oauth_token_secret = "";
            //String oauth_callback_confirmed = "";
              
            // I'm using Apache HTTPCore to make the connection and process the request. In theory, you could use HTTPClient, but HTTPClient defaults to the wrong RFC encoding, which has to be tweaked.
            HttpParams params = new SyncBasicHttpParams();
            HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
            HttpProtocolParams.setContentCharset(params, "UTF-8");
            HttpProtocolParams.setUserAgent(params, "HttpCore/1.1");
            HttpProtocolParams.setUseExpectContinue(params, false);
                 
            HttpProcessor httpproc = new ImmutableHttpProcessor(new HttpRequestInterceptor[] {
                    // Required protocol interceptors
                    new RequestContent(),
                    new RequestTargetHost(),
                    // Recommended protocol interceptors
                    new RequestConnControl(),
                    new RequestUserAgent(),
                    new RequestExpectContinue()});

            HttpRequestExecutor httpexecutor = new HttpRequestExecutor();
            HttpContext context = new BasicHttpContext(null);
            HttpHost host = new HttpHost(twitter_endpoint_host, 443); // use 80 if you want regular HTTP (not HTTPS)
            DefaultHttpClientConnection conn = new DefaultHttpClientConnection();

            context.setAttribute(ExecutionContext.HTTP_CONNECTION, conn);
            context.setAttribute(ExecutionContext.HTTP_TARGET_HOST, host);

            try{ // jsonexception block
                try 
                {
                    // initialize the HTTPS connection
                    SSLContext sslcontext = SSLContext.getInstance("TLS");
                    sslcontext.init(null, null, null);
                    SSLSocketFactory ssf = sslcontext.getSocketFactory();
                    Socket socket = ssf.createSocket();
                    socket.connect(new InetSocketAddress(host.getHostName(), host.getPort()), 0);
                    conn.bind(socket, params);
                     
                     // for HTTP, use this instead of the above.
                     // Socket socket = new Socket(host.getHostName(), host.getPort());
                     // conn.bind(socket, params);
                     
                    BasicHttpEntityEnclosingRequest request2 = new BasicHttpEntityEnclosingRequest("POST", twitter_endpoint_path);
                    request2.setEntity( new StringEntity("", "application/x-www-form-urlencoded", "UTF-8"));
                    //request2.setEntity( new StringEntity("oauth_callback=" + encode(callback_url), "application/x-www-form-urlencoded", "UTF-8"));
                    request2.setParams(params);
                    request2.addHeader("Authorization", authorization_header_string); // this is where we're adding that required "Authorization: BLAH" header.
                    httpexecutor.preProcess(request2, httpproc, context);
                    HttpResponse response2 = httpexecutor.execute(request2, conn, context);
                    response2.setParams(params);
                    httpexecutor.postProcess(response2, httpproc, context);

#4

OK. My approach to this would probably be to compare what you’re doing to Twitter4J or one of the other Java libraries for Twitter.