0

I have done code to access yahoo weather API with oath by following all steps provided by yahoo in documentation as 1) Create Yahoo account 2) Create App 3) White list App 4) C# code to access yahoo weather API with oath

I am getting Unauthorized access exception while requesting API. Here is the code :

public class WeatherYdn
{
    public static void Main(string[] args)
    {
        const string appId = "YOUR-WHITELISTED-APPID";
        const string consumerKey = "YOUR-CONSUMER-KEY";
        const string consumerSecret = "YOUR-SECRET-KEY";
        const string url = "https://weather-ydn-yql.media.yahoo.com/forecastrss";

        string timestamp = StringHelper.GenerateTimeStamp();
        String oauthNonce = StringHelper.GenerateNonce();
        IList<string> parameters = new List<string>();
        parameters.Add("oauth_consumer_key=" + consumerKey);
        parameters.Add("oauth_nonce=" + oauthNonce);
        parameters.Add("oauth_signature_method=HMAC-SHA1");
        parameters.Add("oauth_timestamp=" + timestamp);
        parameters.Add("oauth_version=1.0");
        // Make sure value is encoded
            parameters.Add("location=" + HttpUtility.UrlEncode("pune,in", Encoding.UTF8));
            parameters.Add("format=json");
            ((List<string>) parameters).Sort();

            StringBuilder parametersList = new StringBuilder();
            for (int i = 0; i < parameters.Count; i++)
            {
                parametersList.Append(((i > 0) ? "&" : "") + parameters.ElementAt(i));
            }

            var signatureString = "GET&" +
                                  HttpUtility.UrlEncode(url,Encoding.UTF8) + "&" +
                                  HttpUtility.UrlEncode(parametersList.ToString(), Encoding.UTF8);
            string signature = null;
            try
            {
                string secretAccessKey = consumerSecret;
                byte[] secretKey = Encoding.UTF8.GetBytes(secretAccessKey);
                HMACSHA1 hmac = new HMACSHA1(secretKey);
                hmac.Initialize();
                byte[] bytes = Encoding.UTF8.GetBytes(signatureString);
                byte[] rawHmac = hmac.ComputeHash(bytes);
                signature = Convert.ToBase64String(rawHmac);
            }
            catch (Exception e)
            {
                Console.WriteLine("Unable to append signature");                
            }
            string authorizationLine = "OAuth " +
                                       "oauth_consumer_key=\"" + consumerKey + "\", " +
                                       "oauth_nonce=\"" + oauthNonce + "\", " +
                                       "oauth_timestamp=\"" + timestamp + "\", " +
                                       "oauth_signature_method=\"HMAC-SHA1\", " +
                                       "oauth_signature=\"" + signature + "\", " +
                                       "oauth_version=\"1.0\"";

            HttpWebRequest request = (HttpWebRequest) WebRequest.Create(url + "?location=pune,in&format=json");
            request.Headers.Add("Authorization", authorizationLine);
            request.Headers.Add("Yahoo-App-Id", appId);
            request.ContentType = "application/json; charset=UTF-8";
            request.Accept = "application/json";
            HttpWebResponse response = (HttpWebResponse) request.GetResponse();
            Stream receiveStream = response.GetResponseStream();
            StreamReader readStream = new StreamReader(receiveStream, Encoding.UTF8);
            Console.WriteLine(readStream.ReadLine());
        }    
}

5 Answers5

0

In which line you get the error? The GetResponse() returns it? I think that the credentials you are using (appId,consumerKey,consumerSecret) are invalid!

Dr. K
  • 1,001
  • 7
  • 7
  • I have ckecked all credentials, and also contacted to yahoo technical team, as per their suggestions I have made all the changes.but then also my issue not get solved.so I asked for help here. – Tejashri Sawashe Jan 18 '19 at 10:14
  • @TejashriSawashe I also have similar issue? How's the fix? – stuckedunderflow Jan 20 '19 at 16:33
  • I'm getting the same response - 401 Unauthorized. Converted code from Java to VB.NET, looks very similar to yours. Any luck finding a solution? – DonnieDarko Jan 22 '19 at 19:04
  • i think that you must use an other lib or another language for this Yahoo Weather API. https://developer.yahoo.com/weather/documentation.html?guccounter=1#java – Dr. K Jan 23 '19 at 13:24
0
public string appId = "Your app-id";
        public string consumerKey = "Your-consumer key";
        public string consumerSecret = "Your Consumer Secret key";

        // GET: api/Random
        [HttpGet("{CityName}")]
        public async Task<IActionResult> GetAsync([FromUri] string CityName)
        {




        string urlss = "https://weather-ydn-yql.media.yahoo.com/forecastrss?location=";
            string url = urlss + CityName+ "&format=json&u=c";
            JObject jresult;
            using (var client = new HttpClient())
            {
                try
                {

                    var webClient = new WebClient();
                    webClient.Headers.Add(AssembleOAuthHeader());
                    var d = webClient.DownloadString(url);
                    jresult = JObject.Parse(d);
                    var json_jsonstring = Newtonsoft.Json.JsonConvert.SerializeObject(jresult);
                    return Ok(json_jsonstring);

                }
                catch (HttpRequestException httpRequestException)
                {
                    return BadRequest($"Error getting weather from Yahoo Weather: {httpRequestException.Message}");
                }


            }


        }

        public string AssembleOAuthHeader()
        {
            return "Authorization: OAuth " +
                   "realm=\"yahooapis.com\"," +
                   "oauth_consumer_key=\"" + consumerKey + "\"," +
                   "oauth_nonce=\"" + Guid.NewGuid() + "\"," +
                   "oauth_signature_method=\"PLAINTEXT\"," +
                   "oauth_timestamp=\"" + ((DateTime.UtcNow.Ticks - new DateTime(1970, 1, 1).Ticks) / (1000 * 10000)) +
                   "\"," +
                   "oauth_version=\"1.0\"," +
                   "oauth_signature=\"" + consumerSecret + "%26\"," +
                   "oauth_callback=\"oob\"";

        }
0

For yahoo weather new authentication you can use this python library yahoo-weather

hong4rc
  • 3,999
  • 4
  • 21
  • 40
Mojtaba Ahadi
  • 316
  • 1
  • 4
0

I think your code is fine. The problem lies with a poorly implemented URL Decode on Yahoo's end. Java URL Encode encodes with uppercase while .net HTTPUtility.URLEncode encodes in lower case. I created an extension method for a string that will rectify the problem and URL Encode in a way that the Yahoo API can handle. After doing that all worked well (I had the exact same problem you did).

  <Extension>
    Public Function UppercaseURLEncode(ByVal sourceString As String) As String

        Dim temp As Char() = HttpUtility.UrlEncode(sourceString).ToCharArray()

        For i As Integer = 0 To temp.Length - 2

            If temp(i).ToString().Equals("%", StringComparison.OrdinalIgnoreCase) Then

                temp(i + 1) = Char.ToUpper(temp(i + 1))
                temp(i + 2) = Char.ToUpper(temp(i + 2))

            End If

        Next

        Return New String(temp)

    End Function
DonnieDarko
  • 93
  • 1
  • 14
  • You also need to append an ampersand to your consumer key in this line: string secretAccessKey = consumerSecret; So it should be string secretAccessKey = consumerSecret + "&"; – DonnieDarko Jan 23 '19 at 18:54
0
//Here Is The Working Code :

public class YWSample
{
    const string cURL = "https://weather-ydn-yql.media.yahoo.com/forecastrss";
    const string cAppID = "Your-App-ID";
    const string cConsumerKey = "Your-Consumer-Key";
    const string cConsumerSecret = "Your-Consumer-Secret";
    const string cOAuthVersion = "1.0";
    const string cOAuthSignMethod = "HMAC-SHA1";
    const string cWeatherID = "woeid=727232";  // Amsterdam, The Netherlands
    const string cUnitID = "u=c";           // Metric units
    const string cFormat = "xml";

    //Code to get timestamp
    static string _get_timestamp()
    {
        var lTS = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
        return Convert.ToInt64(lTS.TotalSeconds).ToString();
    }  

    //Code to get nonce
    static string _get_nonce()
    {
        return Convert.ToBase64String(
         new ASCIIEncoding().GetBytes(
          DateTime.Now.Ticks.ToString()
         )
        );
    }  // end _get_nonce

    static string _get_auth()
    {
        var lNonce = _get_nonce();
        var lTimes = _get_timestamp();
        var lCKey = string.Concat(cConsumerSecret, "&");
        var lSign = $"format={cFormat}&" + $"oauth_consumer_key={cConsumerKey}&" + $"oauth_nonce={lNonce}&" +
                       $"oauth_signature_method={cOAuthSignMethod}&" + $"oauth_timestamp={lTimes}&" +
                       $"oauth_version={cOAuthVersion}&" + $"{cUnitID}&{cWeatherID}";

        lSign = string.Concat(
         "GET&", Uri.EscapeDataString(cURL), "&", Uri.EscapeDataString(lSign)
        );

        using (var lHasher = new HMACSHA1(Encoding.ASCII.GetBytes(lCKey)))
        {
            lSign = Convert.ToBase64String(
             lHasher.ComputeHash(Encoding.ASCII.GetBytes(lSign))
            );
        }  // end using

        return "OAuth " +
               "oauth_consumer_key=\"" + cConsumerKey + "\", " +
               "oauth_nonce=\"" + lNonce + "\", " +
               "oauth_timestamp=\"" + lTimes + "\", " +
               "oauth_signature_method=\"" + cOAuthSignMethod + "\", " +
               "oauth_signature=\"" + lSign + "\", " +
               "oauth_version=\"" + cOAuthVersion + "\"";

    }  // end _get_auth

    public static void Main(string[] args)
    {
        const string lURL = cURL + "?" + cWeatherID + "&" + cUnitID + "&format=" + cFormat;

        var lClt = new WebClient();

        lClt.Headers.Set("Content-Type", "application/" + cFormat);
        lClt.Headers.Add("Yahoo-App-Id", cAppID);
        lClt.Headers.Add("Authorization", _get_auth());

        Console.WriteLine("Downloading Yahoo weather report . . .");

        var lDataBuffer = lClt.DownloadData(lURL);

        var lOut = Encoding.ASCII.GetString(lDataBuffer);

        Console.WriteLine(lOut);

        Console.Write("Press any key to continue . . . ");
        Console.ReadKey(true);
    }//end of Main

}  // end YWSample