Troubleshooting OAuth 1.0A


I’ve been helping developers understand OAuth 1.0a for a number of years and have come away with a few tips that I hope will help you while debugging OAuth issues.

  • Make liberal use of the OAuth Tool linked to from each piece of REST API documentation and from your application record on this site. The OAuth Tool allows you create ideal OAuth signature base strings, executable curl commands, and a level of verbosity to the entire process that will help you to identify problems in your own code or environment.

  • Use header-based OAuth whenever possible. It separates concerns and brings clarity to the spec – oauth_* aren’t placed in the POST body or querystring, which often alleviates common encoding issues.

  • Know how to access the signature base string in the OAuth library you are using. Many libraries make this intermediate signing step difficult to access or locked within private methods. Most issues with OAuth signing can be tracked back to an invalidly formatted signature base string.

  • If you’re using header-based OAuth, make sure that your HTTP Authorization header is being properly setup and formatted. This will be language-specific. Also make sure that you aren’t repeating any of the oauth_* parameters in the POST body or URL of your actual executed request. Only parameters that don’t begin with oauth_* should appear in the POST body or query string. (In other words, don’t present double authentication)

  • Make sure that your HTTP verbs are in agreement

    • If you’re sending a POST, make sure your HTTP client is actually sending a POST and that your OAuth signature base string’s method component matched
  • Check you are using the right HTTP request method. Most methods on the Twitter API require a POST or GET request.

  • Ensure that your system’s timestamp is in sync with Twitter’s. We return the current time in the “Date” HTTP header with every request. If your request fails due to a timestamp mismatch, use this time to determine the delta between the system clock and our server clock and adjust your oauth_timestamps for subsequent requests accordingly.

  • Use a well-supported OAuth library. The various encoding steps of the protocol are difficult to get right – your programming language’s URL encoding methods, for example, may not be of the adequate flavor that OAuth 1.0A is expecting.

  • Try alternate tools. When you run into issues with OAuth, try to replicate the request in another library or tool. Compare and contrast the differences between a successful request and a failed request. The OAuth Tool on this site is particularly helpful for this.

  • Learn how to override the oauth_timestamp and oauth_nonce values in your OAuth library. Use this capability to replay signature generation scenarios for comparative analysis.

  • Use auth on all REST API methods that support it. All Twitter REST API methods (except Search) support authentication and using auth means the requests are evaluated within the context of your current user.

  • If you think you’re not being rate limited in the proper context (150 requests per hour instead of 300), check for an X-Warning HTTP header in the response to your request. Some API methods that can be satisfied in a unauthenticated context will be served as such despite invalid authorization credentials and the X-Warning HTTP header will indicate whether an invalid signature was detected.

  • Don’t include oauth_* parameters not pertinent to the request. oauth_callback should only be sent to the request_token method, for example.

  • Use valid endpoints. REST API requires as the subdomain, and /1/ preceding the path to indicate the version. not

  • Associate access token credentials with user ids, not screen names.

  • oauth_token and oauth_token_secret strings change when a user’s access moves between permission levels, or if a user denies your application access and then re-grants it access. Never assume that the strings will remain constants.

Many find these documents especially useful while learning OAuth.

  • [node:139] - Explores the differences between Basic Auth and OAuth with newcomers in mind.

  • [node:114] - Twitter offers a few flavors of OAuth and this helps you choose the right path for your application

  • [node:115] - A more in depth look at the OAuth 1.0A protocol

What tips do you have for developers running into issues with OAuth?


I found the ‘Using OAuth 1.0a’ [1] very useful for getting my OAuth client correct. Thank you! I did notice an error in the documentation.

In the “Making a resource request on a user’s behalf”, the signature is incorrect.

Currently the signature is

but the correct value is actually

That could trip up folks. Thanks again.



I believe the signature is correct. On my machine I did

printf '%s' "POST&" | openssl dgst -sha1 -hmac "MCD8BKwGdgPHvAuvgvz4EQpqDAtx89grbuNMRd7Eh98&J6zix3FfA9LofH0awS24M3HcBYXO5nI1iYe8EfBA" -binary | openssl base64

and got yOahq5m0YjDDjfjxHaXEsW9D+X0= as expected.

Hope this helps.


I have my application with correct consumer key and secret but still showing me exception as…

09-22 20:15:09.112: ERROR/in Main.OAuthLogin(509): 401:Authentication credentials ( were missing or incorrect. Ensure that you have set valid conumer key/secret, access token/secret, and the system clock in in sync.
09-22 20:15:09.112: ERROR/in Main.OAuthLogin(509): <?xml version="1.0" encoding="UTF-8"?>
09-22 20:15:09.112: ERROR/in Main.OAuthLogin(509):
09-22 20:15:09.112: ERROR/in Main.OAuthLogin(509): Desktop applications only support the oauth_callback value 'oob’
09-22 20:15:09.112: ERROR/in Main.OAuthLogin(509): /oauth/request_token
09-22 20:15:09.112: ERROR/in Main.OAuthLogin(509):

the code snippet is as follow…

void OAuthLogin() {
try {
twitter = new TwitterFactory().getInstance();
twitter.setOAuthConsumer(consumerKey, consumerSecret);
requestToken = twitter.getOAuthRequestToken(CALLBACKURL);
String authUrl = requestToken.getAuthenticationURL();
this.startActivity(new Intent(Intent.ACTION_VIEW, Uri
} catch (TwitterException ex) {
Toast.makeText(this, ex.getMessage(), Toast.LENGTH_LONG).show();
Log.e(“in Main.OAuthLogin”, ex.getMessage());

please help me.



It’s because your app is registered as a desktop client.
To overwrite callback URL, your app need to be registered as a browser client.

Try configuring a dummy callback URL ( or whatever you want) at[appid]/settings e> Callback URL
and your app will be recognized as a browser client.



hi…i also have the same problem…
i too already insert the correct consumerKey and consumerSecret
i also filled the callback URL with dummy url but just could not get it work

here is my code

<?php /* author : n1colius ( web : */ require("twitteroauth/twitteroauth.php"); session_start(); // The TwitterOAuth instance $twitteroauth = new TwitterOAuth('JU7odvwZ08KqJIcXXXXX', 'vaZjICA9h1L7CvWkK7G8XXXXXX'); // Requesting authentication tokens, the parameter is the URL we will be redirected to $request_token = $twitteroauth->getRequestToken(''); // Saving them into the session $_SESSION['oauth_token'] = $request_token['oauth_token']; $_SESSION['oauth_token_secret'] = $request_token['oauth_token_secret']; // If everything goes well.. if($twitteroauth->http_code==200){ // Let's generate the URL and redirect $url = $twitteroauth->getAuthorizeURL($request_token['oauth_token']); header('Location: '. $url); } else { // It's a bad idea to kill the script, but we've got to know when there's an error. die('Something wrong happened.'); } the $twitteroauth->http_code just keep returning '401' value not '200' anyone have a solution?


Hi - I will like to say thank you a lot for the post. It was very helpful. After reading thoroughly the links you provided I finally realized the mistake I have been struggling with for 3 days now. Everything worked fine, except I need to single encode the request postBody and double encode the postBody within my base string. So now finally my signature is correct.


Weird problem, when I try to twitt some message with spaces, a 401 error raises, but if I twitt only letters (without spaces) the post success.

We are using the .NET function Uri.EscapeDataString(messageToPost)


Please verify whether the device DATE and TIME are up to date. If not, then it might cause problems with the access token.


I have an app, it works with my account, but i register it with anouther user it gives a 401. with the other user it will read but not write, yet it is registered as read write.
The account that does not work is this one, JoJoMooo
Any ideas?


OK sorted, i began to think it must be something simple, I had set to read write, but did not recrearte token, Now i am getting a 403 error


I have an iOS app (with a couple of well-established libraries) that fails a call to request_token - and have been chasing this for days. Always a “401 Unauthorized” error. I also tried to create a new twitter app, use the OAuth Tool with it, and test the curl example from the tool. That fails. So the tool isn’t much help if its own output fails.


Please!!! Help me!!! I have that error:

Undefined index: oauth_token
Error Type: E_NOTICE

Rendered Page: Click here to view contents able to be rendered

Source File: C:\wamp\www\Venetuits\www\twitteroauth\twitteroauth.php Line: 82

Line 77: if (!empty($oauth_callback)) {
Line 78: $parameters[‘oauth_callback’] = $oauth_callback;
Line 79: }
Line 80: $request = $this->oAuthRequest($this->requestTokenURL(), ‘POST’, $parameters);
Line 81: $token = OAuthUtil::parse_parameters($request);
Line 82: $this->token = new OAuthConsumer($token[‘oauth_token’], $token[‘oauth_token_secret’]);
Line 83: return $token;
Line 84: }
Line 85:
Line 86: /**
Line 87: * Get the authorize URL

Please!!! really!! I’m Venezuelan! and i want create an app for twitter!

Sorry i dont speak english very much!!! i try!!!

Please Again!!!


Please help!
I’m a newbie at this and this might seem like a silly question but how can I check the X-Warning HTTP header in the response to my request?

Thanks in advance!


It varies language-to-language and framework-to-framework. Most languages allow you to get at a response object representing the response – that response object would include a hash of the HTTP headers sent back to you.


I’m struggling with OAuth. Anyone knows why it could work for UPDATE (to create tweets), but not for USER_TIMELINE. Returns 401 : Unathorized

I’ve used a C# code sample ( to post a tweet to my account using OAuth authentication AND IT WORKED.
Then I tried to reuse code to get user timeline and it keeps returning 401 error.
I’ve used your OAuth tool to compare signature created in my code and it was matched when I used same timestamp. Also, I don’t have any X-Warning headers in my response.

I don’t see anything wrong in my code, which makes me wonder if it’s a problem in API?
Could you please have a look and let me know what’s the problem.

Below is a final code for fetching timeline:

var oauth_token = “XXX”;
var oauth_token_secret = “XXX”;
var oauth_consumer_key = “XXX”;
var oauth_consumer_secret = “XXX”;

// oauth implementation details
var oauth_version = “1.0”;
var oauth_signature_method = “HMAC-SHA1”;

// unique request details
var oauth_nonce = Convert.ToBase64String(
new ASCIIEncoding().GetBytes(DateTime.Now.Ticks.ToString()));
var timeSpan = DateTime.UtcNow

  • new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
    var oauth_timestamp = Convert.ToInt64(timeSpan.TotalSeconds).ToString();

// message api details
//var status = "Updating status via REST API if this works. " + oauth_timestamp;
//var resource_url = “”;

var screenName = “ProfileGroupDev”;
var resource_url = “”;

// create oauth signature
var baseFormat = “oauth_consumer_key={0}&oauth_nonce={1}&oauth_signature_method={2}” +

var baseString = string.Format(baseFormat,

baseString = string.Concat(“GET&”, Uri.EscapeDataString(resource_url), “&”, Uri.EscapeDataString(baseString));

var compositeKey = string.Concat(Uri.EscapeDataString(oauth_consumer_secret),
"&", Uri.EscapeDataString(oauth_token_secret));

string oauth_signature;
using (HMACSHA1 hasher = new HMACSHA1(ASCIIEncoding.ASCII.GetBytes(compositeKey)))
oauth_signature = Convert.ToBase64String(

// create the request header
var headerFormat = “OAuth oauth_consumer_key=”{0}", oauth_nonce="{1}", oauth_signature="{2}"," +
" oauth_signature_method="{3}", oauth_timestamp="{4}", oauth_token="{5}", oauth_version="{6}"";

var authHeader = string.Format(headerFormat,

ServicePointManager.Expect100Continue = false;

HttpWebRequest request = (HttpWebRequest)WebRequest.Create(resource_url);
request.Headers.Add(“Authorization”, authHeader);
request.Method = “GET”;
request.ContentType = “application/x-www-form-urlencoded”;
WebResponse response = request.GetResponse();


Have you considered using an OAuth library instead of trying to roll this yourself? OAuth can get pretty complicated, and an implementation like this can be a bit fragile. When you’re building your signature base string, you need to URL encode the parameters and values separately while building the basestring, not all at the same time – when you used the OAuth tool, were you able to compare the basestring you got from that tool with the basestring you’re generating with this code?


please help me… i think my application not false but if i run my application there is an error message containing “couldn’t find OAuth token from response” …
my application is Mobile Twitter Client using J2ME-Based…

my code is

package com.sourcecode.twitter;

import com.sourcecode.utils.Base64;
import com.sourcecode.utils.HttpUtil;
import com.sourcecode.utils.ResultParser;
import com.sourcecode.utils.StringUtil;
import java.util.Date;
import java.util.Enumeration;
import java.util.Random;
import java.util.Vector;
import org.bouncycastle.crypto.digests.SHA1Digest;
import org.bouncycastle.crypto.macs.HMac;
import org.bouncycastle.crypto.params.KeyParameter;

  • @author rivan
    public class XAuth {

    private String xauthUsername;
    private String xauthPassword;
    private String token;
    private String tokenSecret;
    private String verifier;

    private static final String OAuthVersion = “1.0”;
    private static final String OAuthParameterPrefix = “oauth_”;

    private static final String OAuthConsumerKeyKey = “oauth_consumer_key”;
    private static final String OAuthCallbackKey = “oauth_callback”;
    private static final String OAuthVersionKey = “oauth_version”;
    private static final String OAuthSignatureMethodKey = “oauth_signature_method”;
    private static final String OAuthSignatureKey = “oauth_signature”;
    private static final String OAuthTimestampKey = “oauth_timestamp”;
    private static final String OAuthNonceKey = “oauth_nonce”;
    private static final String OAuthTokenKey = “oauth_token”;
    private static final String OAuthTokenSecretKey = “oauth_token_secret”;
    private static final String OAuthVerifier = “oauth_verifier”;
    private static final String XAuthUsername = “x_auth_username”;
    private static final String XAuthPassword = “x_auth_password”;
    private static final String XAuthMode = “x_auth_mode”;

    private static final String OAUTH_CONSUMER_TOKEN = “xxxxxxxxx”;
    private static final String OAUTH_CONSUMER_SECRET = “xxxxxxxxxxxxxxx”;

    private static final String HMACSHA1SignatureType = “HMAC-SHA1”;

    private String normalizedUrl = “”;
    private String normalizedRequestParameters = “”;

    public XAuth(String username, String password) {
    this.xauthUsername = username;
    this.xauthPassword = password;

    public void setTokenAndSecret(String token, String secret) {
    this.token = token;
    this.tokenSecret = secret;

    public String xAuthWebRequest(
    boolean isPost,
    String url,
    QueryParameter[] parameters,
    ResultParser parser) throws Exception {
    String outUrl = “”;
    String querystring = “”;
    String ret = “”;
    String postData = “”;
    String method = “GET”;

     //Setup postData for signing.
     //Add the postData to the querystring.
     if (isPost)
         method = "POST";
         if (parameters!=null && parameters.length > 0)
             //Decode the parameters and re-encode using the oAuth UrlEncode method.
             for(int i=0; i<parameters.length; i++) {
                 QueryParameter q = parameters[i];
                 if(postData.length()>0) {
                     postData += "&";
                 postData += q.getName() + "=" + encode(q.getValue());
             if (url.indexOf("?") > 0)
                 url += "&";
                 url += "?";
             url += postData;
     String nonce = this.generateNonce();
     String timeStamp = this.generateTimeStamp();
     //Generate Signature
     String sig = this.generateSignature(
     outUrl = normalizedUrl;
     querystring = normalizedRequestParameters;
     System.out.println("Signature: " + sig);
     if(querystring.length()>0) {
         querystring += "&";
     querystring += "oauth_signature=" + encode(sig);
     //Convert the querystring to postData
     /*if (isPost)
         postData = querystring;
         querystring = "";
     if (querystring.length() > 0)
         outUrl += "?";
     ret = webRequest(method, outUrl +  querystring, postData, parser);
     return ret;


    private String webRequest(
    String method,
    String url,
    String postData,
    ResultParser parser) throws Exception {
    String result = “”;
    System.out.println("web request URL: " + url);
    if (method.equals(“POST”)) {
    if(parser!=null) {
    result = HttpUtil.doPost(url,parser);
    } else {
    result = HttpUtil.doPost(url);
    } else {
    if(parser!=null) {
    result = HttpUtil.doGet(url,parser);
    } else {
    result = HttpUtil.doGet(url);
    return result;

    private Vector getQueryParameters(String url)
    int questionMarkIndex = url.indexOf("?");
    if(questionMarkIndex<0) {
    return new Vector();

     String parameters = url.substring(questionMarkIndex+1);
     Vector params = new Vector();
     String[] para = StringUtil.split(parameters, "&");
     for(int i=0; i<para.length; i++) {
         if(para[i].startsWith(OAuthParameterPrefix)==false) {
             String[] nameValue = StringUtil.split(para[i], "=");
             QueryParameter q = new QueryParameter(nameValue[0], nameValue[1]);
     return params;


    public String generateSignatureBase(
    String url,
    String consumerKey,
    String token,
    String tokenSecret,
    String verifier,
    String xAuthUsername,
    String xAuthPassword,
    String httpMethod,
    String timeStamp,
    String nonce,
    String signatureType) {
    if (token == null)
    token = “”;

     if (tokenSecret == null)
         tokenSecret = "";
     //normalizedUrl = null;
     //normalizedRequestParameters = null;
     Vector parameters = getQueryParameters(url);
     parameters.addElement(new QueryParameter(OAuthVersionKey, OAuthVersion));
     parameters.addElement(new QueryParameter(OAuthNonceKey, nonce));
     parameters.addElement(new QueryParameter(OAuthTimestampKey, timeStamp));
     parameters.addElement(new QueryParameter(OAuthSignatureMethodKey, signatureType));
     parameters.addElement(new QueryParameter(OAuthConsumerKeyKey, consumerKey));
     if (token!=null && token.length()!=0)
         parameters.addElement(new QueryParameter(OAuthTokenKey, token));
     } else {
         if ( xAuthUsername!=null && xAuthUsername.length()!=0)
             parameters.addElement(new QueryParameter(XAuthUsername, xAuthUsername));
         if ( xAuthPassword!=null && xAuthPassword.length()!=0)
             parameters.addElement(new QueryParameter(XAuthPassword, xAuthPassword));
             parameters.addElement(new QueryParameter(XAuthMode, "client_auth"));
     if (verifier!=null && verifier.length()!=0)
         parameters.addElement(new QueryParameter(OAuthVerifier, verifier));
     sortParameters( parameters );
     normalizedUrl = getSchemeAndHost(url);
     normalizedUrl += getAbsolutePath(url);
     System.out.println("Normalized url: " + normalizedUrl);
     normalizedRequestParameters = normalizeRequestParameters(parameters);
     System.out.println("Normalized params: " + normalizedRequestParameters);
     StringBuffer signatureBase = new StringBuffer();
     signatureBase.append(httpMethod + "&");
     signatureBase.append(encode(normalizedUrl) + "&");
     String sigBase = signatureBase.toString();
     System.out.println("Signature base: " + sigBase);
     return sigBase;


    private static String getSchemeAndHost(String url) {
    int startIndex = url.indexOf("//")+2;
    int endIndex = url.indexOf("/", startIndex);
    return url.substring(0,endIndex);

    private static String getAbsolutePath(String url) {
    int startIndex = url.indexOf("//")+2;
    int endIndex = url.indexOf("/", startIndex);
    int questionMark = url.indexOf("?");
    if(questionMark>0) {
    return url.substring(endIndex, questionMark);
    } else {
    return url.substring(endIndex);

    private static void sortParameters(Vector items) {
    boolean unsorted = true;
    while(unsorted) {
    unsorted = false;
    for(int i=items.size()-1; i>0; i–) {
    QueryParameter item1 = (QueryParameter)items.elementAt(i);
    QueryParameter item2 = (QueryParameter)items.elementAt(i-1);
    if(item1.getName().compareTo(item2.getName())<0) {
    items.setElementAt(item1, i-1);
    items.setElementAt(item2, i);
    unsorted = true;

    private String generateSignature(
    String url,
    String consumerKey,
    String consumerSecret,
    String token,
    String tokenSecret,
    String verifier,
    String xAuthUsername,
    String xAuthPassword,
    String httpMethod,
    String timeStamp,
    String nonce) {
    String signatureBase = generateSignatureBase(

     String tokenSec = "";
     if(tokenSecret!=null) {
         tokenSec = tokenSecret;
     String key = encode(consumerSecret) + "&" + encode(tokenSec);
     return getSignature(signatureBase, key);


    public String getSignature(String message, String key) {
    try {
    HMac m=new HMac(new SHA1Digest());
    m.init(new KeyParameter(key.getBytes(“UTF-8”)));
    byte[] bytes=message.getBytes(“UTF-8”);
    m.update(bytes, 0, bytes.length);
    byte[] mac = new byte[m.getMacSize()];
    m.doFinal(mac, 0);
    String signature = new Base64().encode(mac);
    return signature;
    catch (UnsupportedEncodingException ex) {
    return null;

    protected String normalizeRequestParameters(Vector parameters)
    StringBuffer sb = new StringBuffer();
    QueryParameter p = null;
    Enumeration en = parameters.elements();
    while(en.hasMoreElements()) {
    p = (QueryParameter)en.nextElement();
    if (en.hasMoreElements())
    return sb.toString();

    public String generateTimeStamp() {
    Date d = new Date();
    String timestamp = Long.toString(d.getTime()/1000);
    return timestamp;

    public String generateNonce() {
    Random random = new Random();
    String nonce = Long.toString(Math.abs(random.nextLong()), 60000);
    return nonce;

    private String unreservedCharactersPattern = “[a-zA-Z0-9\-\.~]";
    private String unreservedCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-.

    private String encode(String s) {
    if (s == null || “”.equals(s)) {
    return “”;
    StringBuffer sb = new StringBuffer(s.length()*2);
    for (int i = 0; i < s.length(); i++) {
    if (unreservedCharacters.indexOf(s.charAt(i)) == -1) {
    // get byte values of the character
    // and turn them into percent encoding
    String t = String.valueOf(s.charAt(i));
    } else {

     return sb.toString();




This code looks like it requires permissions for using xAuth – does your application have those permissions?


how to get a permissions that? I’ve contacted the twitter in can not help me … I am tired of trying to send a request for permission to twitter … Can you help me? please help me …