title: How to make an OAuth 1 Twitter API call with C# (dotnet core 3.1)
body: <p>I want to be able to search for twitter handles from a dotnet core API service. I've looked at the twitter documentation for <a href="https://developer.twitter.com/en/docs/accounts-and-users/follow-search-get-users/api-reference/get-users-search" rel="nofollow noreferrer">users/search.json</a> and begged, borrowed and stolen what code examples I can from the stackoverflow, etc. (see below), but all I get back is:</p>
  
  <p><code>{"errors":[{"code":215,"message":"Bad Authentication data."</code>}]}</p>
  
  <p>when I execute the resulting curl command. </p>
  
  <p>I'm sorry the code is a bit of a mess, but can anyone see what I'm doing wrong? Or better still, if there's a library which will do this for me, I've been unable to find one, that would be even better.</p>
  
  <pre><code>using Xunit;
  using System;
  using System.Linq;
  using System.Collections.Generic;
  using OAuth; // OAuth.DotNetCore, 3.0.1
  using System.IO;
  using System.Net;
  
  namespace TwitterLibTest
  {
      public class BuildHeaderTest
      {  
          private static readonly string consumerKey = "...";
  
          private static readonly string consumerSecret = "...";
  
          private static readonly string method = "GET";
  
          private static readonly OAuthSignatureMethod oauthSignatureMethod = OAuthSignatureMethod.HmacSha1;
  
          private static readonly string oauthVersion = "1.0a";
  
          [Fact]
          public void Header()
          {
              var url = "https://api.twitter.com/1.1/users/search.json";
  
              var generatedNonce = RandomString(32);                        
  
              var generatedTimestamp = DateTimeOffset.Now.ToUnixTimeSeconds().ToString();
  
              var oauthToken = BuildAuthToken(consumerKey, consumerSecret);
  
              var generatedSignature = GetSignatureBaseString(method, url, generatedTimestamp, generatedNonce, consumerKey, oauthToken, oauthSignatureMethod.ToString(), oauthVersion, new SortedDictionary&lt;string, string&gt;());
  
              Console.WriteLine($"curl --request GET --url '{url}?q=soccer' --header 'authorization: OAuth oauth_consumer_key=\"{consumerKey}\", oauth_nonce=\"{generatedNonce}\", oauth_signature=\"{generatedSignature}\", oauth_signature_method=\"{oauthSignatureMethod.ToString()}\", oauth_timestamp=\"{generatedTimestamp}\", oauth_token=\"{oauthToken}\", oauth_version=\"{oauthVersion}\"'");
          }
  
          private static Random random = new Random();
  
          private static string RandomString(int length)
          {
              const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
              return new string(Enumerable.Repeat(chars, length)
              .Select(s =&gt; s[random.Next(s.Length)]).ToArray());
          }
  
          // https://stackoverflow.com/questions/35677711/generate-oauth1-signature-in-c-sharp
          private static string GetSignatureBaseString(string method, string strUrl, string timeStamp,
              string nonce, string strConsumer, string strOauthToken, string oauthSignatureMethod,
              string oauthVersion, SortedDictionary&lt;string, string&gt; data)
          {
              //1.Convert the HTTP Method to uppercase and set the output string equal to this value.
              string Signature_Base_String = method.ToUpper();
              Signature_Base_String = Signature_Base_String.ToUpper();
  
              //2.Append the ‘&amp;’ character to the output string.
              Signature_Base_String = Signature_Base_String + "&amp;";
  
              //3.Percent encode the URL and append it to the output string.
              string PercentEncodedURL = Uri.EscapeDataString(strUrl);
              Signature_Base_String = Signature_Base_String + PercentEncodedURL;
  
              //4.Append the ‘&amp;’ character to the output string.
              Signature_Base_String = Signature_Base_String + "&amp;";
  
              //5.append OAuth parameter string to the output string.
              var parameters = new SortedDictionary&lt;string, string&gt;
              {
                  {"oauth_consumer_key", strConsumer},
                  {"oauth_token", strOauthToken },
                  {"oauth_signature_method", oauthSignatureMethod},
                  {"oauth_timestamp", timeStamp},
                  {"oauth_nonce", nonce},
                  {"oauth_version", oauthVersion}
              };            
  
              //6.append parameter string to the output string.
              foreach (KeyValuePair&lt;string, string&gt; elt in data)
              {
                  parameters.Add(elt.Key, elt.Value);
              }
  
              bool first = true;
              foreach (KeyValuePair&lt;string, string&gt; elt in parameters)
              {
                  if (first)
                  {
                      Signature_Base_String = Signature_Base_String + Uri.EscapeDataString(elt.Key + "=" + elt.Value);
                      first = false;
                  }
                  else
                  {
                      Signature_Base_String = Signature_Base_String + Uri.EscapeDataString("&amp;" + elt.Key + "=" + elt.Value);
                  }
              }
  
              return Signature_Base_String;
          }
  
          private string BuildAuthToken(string consumerKey, string consumerSecret)
          {
              var client = Client(consumerKey, consumerSecret);
              var response = Get(client);
              var tokenMap = Parse(response);
  
              return tokenMap["oauth_token"];
          }
  
          private static OAuthRequest Client(string consumerKey, string consumerSecret)
          {
              return new OAuthRequest
              {
                  Method = method,
                  Type = OAuthRequestType.RequestToken,
                  SignatureMethod = OAuthSignatureMethod.HmacSha1,
                  ConsumerKey = consumerKey,
                  ConsumerSecret = consumerSecret,
                  RequestUrl = "https://api.twitter.com/oauth/request_token",
                  Version = oauthVersion,
              };
          }
  
          private static HttpWebResponse Get(OAuthRequest client)
          {
              string auth = client.GetAuthorizationHeader();
              var request = (HttpWebRequest) WebRequest.Create(client.RequestUrl);           
  
              request.Headers.Add("Authorization", auth);
              return (HttpWebResponse) request.GetResponse();
          }
  
          private static Dictionary&lt;string, string&gt; Parse(HttpWebResponse response)
          {
              using var stream = response.GetResponseStream() ;
              using var reader = new StreamReader( stream );
              var responseAsText = reader.ReadToEnd();
  
              var map = new Dictionary&lt;string, string&gt;();
  
              foreach( var token in responseAsText.Split("&amp;"))
              {
                  var tokens = token.Split("=");
                  map.Add(tokens[0], tokens[1]);
              }
  
              return map;
          }
      }
  }
  </code></pre>