1

Authenticating with .NET using DotNetOpenAuth

Ok, so its done! This works.

First, grab the latest DotNetOpenAuth library, which is here: http://www.dotnetopenauth.net

Next, make a new desktop project, like a console application. Note, that this explanation is really just to gain understanding, and that it involves interrupting the process to hit the authentication web page, authenticating and injecting the validation token. You could make this more seamless by using a web application with an embedded browser or something.

Anyways, moving along.

Create a second project, a class library called yahoo.fantasysports

Add reference to the DotNetOpenAuth and the Log4net assemblies.

Immediately create a class, called "InMemoryTokenManager"

CODEBOX
using System;
using System.Collections.Generic;
using System.Diagnostics;
using DotNetOpenAuth.OAuth.ChannelElements;
using DotNetOpenAuth.OAuth.Messages;
using DotNetOpenAuth.OpenId.Extensions.OAuth;

namespace yahoo.fantastysports {
/// <summary>
/// A token manager that only retains tokens in memory.
/// Meant for SHORT TERM USE TOKENS ONLY.
/// </summary>
/// <remarks>
/// A likely application of this class is for "Sign In With Twitter",
/// where the user only signs in without providing any authorization to access
/// Twitter APIs except to authenticate, since that access token is only useful once.
/// </remarks>
internal class InMemoryTokenManager : IConsumerTokenManager, IOpenIdOAuthTokenManager {
private Dictionary<string, string> tokensAndSecrets = new Dictionary<string, string>();

/// <summary>
/// Initializes a new instance of the <see cref="InMemoryTokenManager"/> class.
/// </summary>
/// <param name="consumerKey">The consumer key.</param>
/// <param name="consumerSecret">The consumer secret.</param>
public InMemoryTokenManager(string consumerKey, string consumerSecret) {
if (String.IsNullOrEmpty(consumerKey)) {
throw new ArgumentNullException("consumerKey");
}

this.ConsumerKey = consumerKey;
this.ConsumerSecret = consumerSecret;
}

/// <summary>
/// Gets the consumer key.
/// </summary>
/// <value>The consumer key.</value>
public string ConsumerKey { get; private set; }

/// <summary>
/// Gets the consumer secret.
/// </summary>
/// <value>The consumer secret.</value>
public string ConsumerSecret { get; private set; }

#region ITokenManager Members

/// <summary>
/// Gets the Token Secret given a request or access token.
/// </summary>
/// <param name="token">The request or access token.</param>
/// <returns>
/// The secret associated with the given token.
/// </returns>
/// <exception cref="ArgumentException">Thrown if the secret cannot be found for the given token.</exception>
public string GetTokenSecret(string token) {
return this.tokensAndSecrets[token];
}

/// <summary>
/// Stores a newly generated unauthorized request token, secret, and optional
/// application-specific parameters for later recall.
/// </summary>
/// <param name="request">The request message that resulted in the generation of a new unauthorized request token.</param>
/// <param name="response">The response message that includes the unauthorized request token.</param>
/// <exception cref="ArgumentException">Thrown if the consumer key is not registered, or a required parameter was not found in the parameters collection.</exception>
/// <remarks>
/// Request tokens stored by this method SHOULD NOT associate any user account with this token.
/// It usually opens up security holes in your application to do so. Instead, you associate a user
/// account with access tokens (not request tokens) in the <see cref="ExpireRequestTokenAndStoreNewAccessToken"/>
/// method.
/// </remarks>
public void StoreNewRequestToken(UnauthorizedTokenRequest request, ITokenSecretContainingMessage response) {
this.tokensAndSecrets[response.Token] = response.TokenSecret;
}

/// <summary>
/// Deletes a request token and its associated secret and stores a new access token and secret.
/// </summary>
/// <param name="consumerKey">The Consumer that is exchanging its request token for an access token.</param>
/// <param name="requestToken">The Consumer's request token that should be deleted/expired.</param>
/// <param name="accessToken">The new access token that is being issued to the Consumer.</param>
/// <param name="accessTokenSecret">The secret associated with the newly issued access token.</param>
/// <remarks>
/// <para>
/// Any scope of granted privileges associated with the request token from the
/// original call to <see cref="StoreNewRequestToken"/> should be carried over
/// to the new Access Token.
/// </para>
/// <para>
/// To associate a user account with the new access token,
/// <see cref="System.Web.HttpContext.User">HttpContext.Current.User</see> may be
/// useful in an ASP.NET web application within the implementation of this method.
/// Alternatively you may store the access token here without associating with a user account,
/// and wait until <see cref="WebConsumer.ProcessUserAuthorization()"/> or
/// <see cref="DesktopConsumer.ProcessUserAuthorization(string, string)"/> return the access
/// token to associate the access token with a user account at that point.
/// </para>
/// </remarks>
public void ExpireRequestTokenAndStoreNewAccessToken(string consumerKey, string requestToken, string accessToken, string accessTokenSecret) {
this.tokensAndSecrets.Remove(requestToken);
this.tokensAndSecrets[accessToken] = accessTokenSecret;
}

/// <summary>
/// Classifies a token as a request token or an access token.
/// </summary>
/// <param name="token">The token to classify.</param>
/// <returns>Request or Access token, or invalid if the token is not recognized.</returns>
public TokenType GetTokenType(string token) {
throw new NotImplementedException();
}

#endregion

#region IOpenIdOAuthTokenManager Members

/// <summary>
/// Stores a new request token obtained over an OpenID request.
/// </summary>
/// <param name="consumerKey">The consumer key.</param>
/// <param name="authorization">The authorization message carrying the request token and authorized access scope.</param>
/// <remarks>
/// <para>The token secret is the empty string.</para>
/// <para>Tokens stored by this method should be short-lived to mitigate
/// possible security threats. Their lifetime should be sufficient for the
/// relying party to receive the positive authentication assertion and immediately
/// send a follow-up request for the access token.</para>
/// </remarks>
public void StoreOpenIdAuthorizedRequestToken(string consumerKey, AuthorizationApprovedResponse authorization) {
this.tokensAndSecrets[authorization.RequestToken] = String.Empty;
}

#endregion
}
}


Next, create a second class called "YahooFantasySportsService"

CODEBOX
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using DotNetOpenAuth.OAuth;
using DotNetOpenAuth.Messaging;
using DotNetOpenAuth.OAuth.ChannelElements;

namespace yahoo.fantastysports {
public static class YahooFantasySportsService {

public static readonly ServiceProviderDescription Description = new ServiceProviderDescription {
RequestTokenEndpoint = new MessageReceivingEndpoint("https://api.login.yahoo.com/oauth/v2/get_request_token", HttpDeliveryMethods.PostRequest),
UserAuthorizationEndpoint = new MessageReceivingEndpoint("https://api.login.yahoo.com/oauth/v2/request_auth", HttpDeliveryMethods.GetRequest),
AccessTokenEndpoint = new MessageReceivingEndpoint("https://api.login.yahoo.com/oauth/v2/get_token", HttpDeliveryMethods.GetRequest),
TamperProtectionElements = new ITamperProtectionChannelBindingElement[] {
new HmacSha1SigningBindingElement()
}
};

}
}


Next Create a class called "OAuthWrapper"

CODEBOX
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Text;

using DotNetOpenAuth.OAuth.ChannelElements;

namespace yahoo.fantastysports {
public class OAuthWrapper {

public DotNetOpenAuth.OAuth.DesktopConsumer consumer { get; set; }

private string RequestToken = "";
public string ConsumerKey { get; set; }
public string ConsumerSecret { get; set; }

public OAuthWrapper(string consumer_key, string consumer_secret) {
this.ConsumerKey = consumer_key;
this.ConsumerSecret = consumer_secret;

consumer = new DotNetOpenAuth.OAuth.DesktopConsumer(
YahooFantasySportsService.Description,
new InMemoryTokenManager(ConsumerKey, ConsumerSecret));
return;
}

public string BeginAuth() {
var requestArgs = new Dictionary<string, string>();
return this.consumer.RequestUserAuthorization(requestArgs, null, out this.RequestToken).AbsoluteUri;
}

public string CompleteAuth(string verifier) {
var response = this.consumer.ProcessUserAuthorization(this.RequestToken, verifier);
return response.AccessToken;
}

public IConsumerTokenManager TokenManager {
get {
return (IConsumerTokenManager)consumer.TokenManager;
}
}


}
}


So this is what you need to authenticate to Yahoo Fantasy Sports, and what will be needed to sign requests to make calls to the services. Of course it would make sense to create methods for such calls, and mange their usage. Now go back to that console application we made.

Add an Application Configuration File. And add this to it:

CODEBOX
<appSettings>
<add key="key" value="your_key"/>
<add key="secret" value="your secret"/>
</appSettings>


Now, all of that boils down to this... in your Program.cs file, make this call.

CODEBOX
yahoo.fantastysports.OAuthWrapper wrapper = new yahoo.fantastysports.OAuthWrapper(ConfigurationManager.AppSettings["key"], ConfigurationManager.AppSettings["secret"]);


Now you can start the authentication process.

CODEBOX
string url = wrapper.BeginAuth();


URL is the address you will need to hit to authenticate and allow access to your data. So make sure you break after you call this, and paste the URL into a browser. Do the authentication, and you will get a short validation token. Copy that.

Then you can call in the immediate window, or just set a string variable to the value of that token, and call:

CODEBOX
wrapper.CompleteAuth(validator_token);


Bam! your in!

Play around with it, and I'm sure it will start to make sense. I'm still making sense of it myself. =)

Back to the idea of having an embedded browser, it would be really easy to extract that validationtoken programatically from an embedded browser, and streamline the process a lot more. And if you're not using a desktop application, I believe you can specify a url for the token to be posted back to you, further simplifying this process.

Also, that class we made, InMemoryTokenManager, that would likely be changed to store tokens in a database, so that you dont need to authenticate every time, you could just refresh the tokens when they expire.

Hope this is helpful, any questions or comments, please by all means.

A big thanks to http://www.theleagueofpaul.com/blog/2010/0...oauth-together/ for helping me piece this libraries usage together.

by
29 Replies
  • I almost forgot, you will need to reference System.Configuration assembly in the console application, in order to make use of the ConfigurationManager, to extract keys from the ApplicationConfigurationFile
    0
  • Thanks Sam, this is very helpful!
    0
  • Thanks Sam! Now I'm going to try and convert this into Java for an android application. I've been struggling understanding how to get started.
    0
  • No Problem Guys! Remember, I'm trying to get into this too, so excuse any errors! =)

    Steven, it might be helpful for you to read the developer.yahoo.com/oauth guide, I'm not sure exactly if this library is available in java or not, but I do have some code that I wrote that may be easier to port to java, it would be a plain text authentication to the authentication services. Just be aware that the actual service calls cannot be plain text, which is why I ditched what I had, as the SHA1 stuff started hurting my head. =)

    This has a dependancy on OAuthBase, for utility functions, which should also be easily ported to Java.

    So, if this helps you gain your bearings, by all means. Use whatever is helpful. =)

    Also, i think the state of OAuth libraries is in much better state than for .NET, so this may all be irrelevant.



    CODEBOX
    using System;
    using System.Collections.Generic;
    using System.Configuration;
    using System.IO;
    using System.Linq;
    using System.Net;
    using System.Reflection;
    using System.Text;
    using System.Web;
    using oauth.Properties;

    namespace oauth {

    /// <summary>
    /// Used to authenticate OAuth to Yahoo Services
    /// </summary>
    public class YahooOAuth {

    /// <summary>
    /// Encoding to use for talking to services
    /// </summary>
    private static Encoding m_encoding;

    /// <summary>
    /// Initialize Static Members
    /// </summary>
    static YahooOAuth() {
    m_encoding = Encoding.ASCII;
    }

    /// <summary>
    /// Consumer Context, generated / updated by responses from yahoo services
    /// </summary>
    public class consumer_context {

    /// <summary>
    /// initialize request qoken response
    /// </summary>
    /// <param name="source">Output from service response</param>
    public consumer_context(string source) {
    refresh(source);
    return;
    }

    /// <summary>
    /// Update Parameters from service response
    /// </summary>
    /// <param name="source">Output from service response</param>
    public void refresh(string source) {
    string[] strTok = source.Split(new string[] { "&" }, StringSplitOptions.RemoveEmptyEntries);
    foreach (string parameter in strTok) {
    string[] pair = parameter.Split(new string[] { "=" }, StringSplitOptions.RemoveEmptyEntries);
    typeof(consumer_context).GetProperty(pair[0]) //member names conveniently named from responses
    .SetValue(this, HttpUtility.UrlDecode(pair[1]), null);
    }
    }

    public string oauth_token { get; set; }

    public string oauth_token_secret { get; set; }

    public string oauth_expires_in { get; set; }

    public string xoauth_request_auth_url { get; set; }

    public string oauth_callback_confirmed { get; set; }

    public string oauth_session_handle { get; set; }

    public string xoauth_yahoo_guid { get; set; }

    public string oauth_authorization_expires_in { get; set; }

    }

    /// <summary>
    /// Step 1: Get Request Token,
    ///
    /// </summary>
    /// <param name="consumer_key">Yahoo Application Consumer Key</param>
    /// <param name="consumer_secret">Yahoo Application Consumer Secret</param>
    /// <returns>Token response</returns>
    public static consumer_context get_request_token(string consumer_key, string consumer_secret) {
    OAuthBase oauth = new OAuthBase();
    string url = Resources.url_get_request_token;
    string token_response;
    string timestamp = oauth.GenerateTimeStamp();
    string nonce = oauth.GenerateNonce();

    //Build parameters to post to get_request_token
    StringBuilder parameters = new StringBuilder();
    parameters.Append("oauth_consumer_key="); parameters.Append(consumer_key);
    parameters.Append("&oauth_signature="); parameters.Append(consumer_secret); parameters.Append("%26"); //%26 must be appended for plaintext
    parameters.Append("&oauth_nonce="); parameters.Append(nonce);
    parameters.Append("&oauth_signature_method="); parameters.Append("PLAINTEXT");
    parameters.Append("&oauth_timestamp="); parameters.Append(timestamp);
    parameters.Append("&oauth_version="); parameters.Append("1.0");
    parameters.Append("&oauth_callback="); parameters.Append("oob");
    byte[] data = m_encoding.GetBytes(parameters.ToString());

    //Post Parameters to get_request_token
    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
    request.Method = "POST";
    request.ContentType = "application/x-www-form-urlencoded";
    request.ContentLength = data.Length;
    using (Stream request_stream = request.GetRequestStream()) {
    request_stream.Write(data, 0, data.Length);
    request_stream.Flush();
    }
    //Grab response from service
    using (WebResponse response = request.GetResponse()) {
    using (StreamReader reader = new StreamReader(response.GetResponseStream())) {
    token_response = reader.ReadToEnd();
    }
    }

    return new consumer_context(token_response);
    }

    /// <summary>
    /// Get/Refresh Access Token
    /// </summary>
    /// <param name="consumer_key">Yahoo Application Consumer Key</param>
    /// <param name="consumer_secret">Yahoo Application Consumer Secret</param>
    /// <param name="get_request_token">Request Token Obtained</param>
    /// <param name="verifier_token">verifier token manually obtained, may be null</param>
    /// <returns></returns>
    public static consumer_context get_access_token(string consumer_key, string consumer_secret, consumer_context context, string verifier_token) {
    OAuthBase oauth = new OAuthBase();
    string url = Resources.url_get_access_token;
    string token_response;
    string timestamp = oauth.GenerateTimeStamp();
    string nonce = oauth.GenerateNonce();

    string normal_url, normal_parameters,

    signature = oauth.GenerateSignature(
    new Uri(url),
    consumer_key,
    consumer_secret,
    context.oauth_token,
    context.oauth_token_secret,
    "POST",
    timestamp,
    nonce, OAuthBase.SignatureTypes.PLAINTEXT,
    out normal_url,
    out normal_parameters);

    //Build parameters to post to get_request_token
    StringBuilder parameters = new StringBuilder();
    parameters.Append("oauth_consumer_key="); parameters.Append(consumer_key);
    parameters.Append("&oauth_signature_method="); parameters.Append("PLAINTEXT");
    parameters.Append("&oauth_signature="); parameters.Append(signature);
    parameters.Append("&oauth_version="); parameters.Append("1.0");
    if (verifier_token != null) {
    parameters.Append("&oauth_verifier="); parameters.Append(verifier_token);
    } else {
    parameters.Append("&oauth_session_handle="); parameters.Append(context.oauth_session_handle);
    }
    parameters.Append("&oauth_token="); parameters.Append(context.oauth_token);
    parameters.Append("&oauth_timestamp="); parameters.Append(timestamp);
    parameters.Append("&oauth_nonce="); parameters.Append(nonce);

    byte[] data = m_encoding.GetBytes(parameters.ToString());

    //Post Parameters to get_request_token
    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
    request.Method = "POST";
    request.ContentType = "application/x-www-form-urlencoded";
    request.ContentLength = data.Length;
    using (Stream request_stream = request.GetRequestStream()) {
    request_stream.Write(data, 0, data.Length);
    request_stream.Flush();
    }
    //Grab response from service
    using (WebResponse response = request.GetResponse()) {
    using (StreamReader reader = new StreamReader(response.GetResponseStream())) {
    token_response = reader.ReadToEnd();
    }
    }
    //Update Consumer Context
    context.refresh(token_response);
    return context;
    }

    public static string call_service(string service_url, string consumer_key, string consumer_secret, consumer_context context) {
    StringBuilder sb_response = new StringBuilder();

    OAuthBase oauth = new OAuthBase();
    string url = service_url;
    string timestamp = oauth.GenerateTimeStamp();
    string nonce = oauth.GenerateNonce();

    string normal_url, normal_parameters,

    signature = oauth.GenerateSignature(
    new Uri(url),
    consumer_key,
    consumer_secret,
    context.oauth_token,
    context.oauth_token_secret,
    "POST",
    timestamp,
    nonce, OAuthBase.SignatureTypes.PLAINTEXT,
    out normal_url,
    out normal_parameters);

    //Build parameters to post to get_request_token
    StringBuilder parameters = new StringBuilder();
    parameters.Append("?oauth_consumer_key="); parameters.Append(consumer_key);
    parameters.Append("&oauth_signature_method="); parameters.Append("PLAINTEXT");
    parameters.Append("&oauth_signature="); parameters.Append(signature);
    parameters.Append("&oauth_version="); parameters.Append("1.0");
    parameters.Append("&oauth_session_handle="); parameters.Append(context.oauth_session_handle);
    parameters.Append("&oauth_token="); parameters.Append(context.oauth_token);
    parameters.Append("&oauth_timestamp="); parameters.Append(timestamp);
    parameters.Append("&oauth_nonce="); parameters.Append(nonce);

    //byte[] data = m_encoding.GetBytes(parameters.ToString());

    //Post Parameters to get_request_token
    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url + parameters.ToString());
    request.Method = "GET";
    //request.ContentType = "application/x-www-form-urlencoded";
    //request.ContentLength = data.Length;
    //using (Stream request_stream = request.GetRequestStream()) {
    // request_stream.Write(data, 0, data.Length);
    // request_stream.Flush();
    //}
    //Grab response from service
    using (WebResponse response = request.GetResponse()) {
    using (StreamReader reader = new StreamReader(response.GetResponseStream())) {
    sb_response.Append(reader.ReadToEnd());
    }
    }

    return sb_response.ToString();
    }

    }
    }
    0
  • Sam, this is really, really great stuff. Thanks for going over your implementation in so much detail! I've been trying to work on some basic Fantasy-specific PHP sample code to use as a starting point, so when I get that together, I'll put up a sticky for various language specific solutions and link over to this thread for .NET stuff.
    0
  • Thanks Sean, I appreciate the encouragement. =)

    if anyone has any concerns or suggestions, please speak up, I generally don't take offense to constructive criticism, and am looking at this as a great opportunity to learn.
    0
  • To use the DotNetAuth library from a website, would you stay with the DesktopConsumer class or would you use the WebConsumer class?
    0
  • Yes, grab it off the website: http://www.dotnetopenauth.net/

    In my examples. I am using the Desktop Consumer

    I would do the same if your doing this in a console app, or a windows forms app in a really ad-hoc way, just to gain your bearings.

    But this library has lots of examples out there using web consumer...


    Sorry for the sparseness, getting late here =) But let me know if that doesn't make sense, if I can figure out how to host a zip file here, I'd gladly bundle up a project with this...
    0
  • sorry, did I mention it was late here? (re-read that, and my response was quite redundant, and didn't answer your question)

    yes you would want the web consumer for a web site.

    I haven't played with it yet, but I believe the web consumer has traits better suiting it to be used for a web application, specifically, I think it has a special way of handling multiple sets of tokens, one for each http session

    I'll see if I can piece that example together tomorrow for ya..
    0
  • Sam, that would be great - thanks. I have been looking at the Twitter and Google examples in the DotnetAuth library. They make sense to me but I cannot for the life of me get something to work with my Key/Secret.
    0
  • I've discovered that part of my problem is my callback URL....I am doing my .NET development in the VS 2008 IDE so my callback URL is whatever URL is generated by the virtual web server used with VS 2008 (for example, http://localhost:3289/default.aspx). When I include this URL in my request to Yahoo get_request_token, it does not work. When I just use "oob" the same code works. I've tried to URLEncode it as well. I am using plaintext encoding for my request. Any idea why my URL breaks the request?
    0
  • The problem would be that your loopback endpoint is both not bindable outside your machine, and of course the Yahoo Servers cannot look it up. So it cannot post the information back to your site.

    So by using the oob, telling it that you have no endpoint to post back to, you would be able to manually take the verifier token and stick it in.

    What I've been doing within the IDE to push things along is just

    CODEBOX
     yahoo.fantastysports.OAuthWrapper wrapper = new yahoo.fantastysports.OAuthWrapper(ConfigurationManager.AppSettings["key"], ConfigurationManager.AppSettings["secret"]);
    string url = wrapper.BeginAuth();
    string validator_token = "";
    string access_token = wrapper.CompleteAuth(validator_token);
    System.Console.Write(wrapper.get_stuff(access_token));

    System.Console.WriteLine("\r\nPress <Enter> To Terminate...");
    System.Console.ReadLine();

    return;


    Set a break point on access token, so the IDE enters the debug mode, then in the immediate window you can validator_token = "whatever you copied as the validator token from the website"

    or you can use the locals tool, to just paste the value into that variable.

    But if you had used the web browser control, you could just extract the value programatically upon authenticating.

    alternatively, you could set up an IIS virtual directory to point to your web application, and bind the web site to your internet facing NIC. Shut off your firewall, or add appropriate rule to allow communication, set up DMZ access , or a route on your router (if you have one) and make sure you send in an address that will translate.

    eg.

    http://24.222.123.123:8080/mytestsite/whatever.aspx

    assuming that your internet connection had the IP address 24.222.123.123
    and that you mapped port 8080, on your WAN port to port 80 on your computers connection, and that you enabled incoming traffic on port 80 on your firewall.

    does that make sense? or am I confusing you? =)
    0
  • That does make sense - thanks! I believe this same issue is causing my other attempts to use the OAuth libraries to fail as well.
    0
  • Now I'm confused...I tried putting in a callback URL and running from my web host. It still does not work. Any reason this would not work from my web host?
    0
  • what do you mean by web host? A web hosting service?

    My understanding was that once you authenticate, the callback URL would be used to redirect you after you log in, and it would post the validation token there, (Sean or someone may step in now and correct me)

    Is it a case of it not redirecting you at all?

    As soon as I have a free minute, I'm going to try this out, and see if I can help ya.
    0
  • OK< I can absolutely verify this..

    upon verifying user credentials, and allowing access to your private data, it will redirect to the url you provide, AND post the tokens,

    So you will need to process the tokens it posts,
    the post parameters are named

    oauth_token and oauth_verifier
    0
  • by the way schwane

    I stuck a page up that will echo request parameters back at ya,

    Why not stick this in as your callback url:

    http://24.142.38.61:8085/ff/test1/Default.aspx

    once you authenticate, you will be able to see what yahoo posts back at ya.

    Just.. no funny business, I'm offering this out of good will to be helpful, but it is my workstation.. =)
    0
  • QUOTE (Sam Coder @ Jul 21 2010, 09:30 AM) <{POST_SNAPBACK}>
    OK< I can absolutely verify this..

    upon verifying user credentials, and allowing access to your private data, it will redirect to the url you provide, AND post the tokens,

    So you will need to process the tokens it posts,
    the post parameters are named

    oauth_token and oauth_verifier

    Yup, just backing Sam up on this. If you provide a redirect URL for your request token, it'll just send the user (after they've permitted access to your application) to that URL with an "oauth_token" and "oauth_verifier" URL parameter appended on. For example, if I provide "http://www.yahoo.com" as my redirect URL, the user should eventually end up at something like:
    CODE
    http://www.yahoo.com/?oauth_token=k8arku8&oauth_verifier=92ygs2

    So if you end up redirecting to a page that you own instead of yahoo.com, then it gives you the ability to pull down the oauth_token and oauth_verifier as parameters when the user hits your page and then use those to:

    1) Figure out who this guy is by correlating the oauth_token to the initial request token that you'd gotten back,
    2) Use the oauth_token to retrieve the oauth_token_secret, which you should have stored somewhere keyed by the oauth_token from your initial request, and
    3) Actually get the access token by sending the oauth_token, oauth_token_secret, and oauth_verifier to the Yahoo! OAuth servers.

    That's how I imagine the flow, at least.
    0
  • So, in ASP.NET, assuming you were just going to take the tokens as they come back, and store them somewhere for your application to use, its relatively easy to match up verifier tokens.

    For this temporary bit, I would just use the Application pool,

    When you submit a get request token, use that as the key, and maintian a structure holding all the information you will need to complete the process, eg:

    CODEBOX
    public class ConsumerContext {

    /// <summary>
    /// Initialize consumer context
    /// </summary>
    /// <param name="source"></param>
    public ConsumerContext(string source) {
    refresh(source);
    return;
    }

    /// <summary>
    /// Update Parameters from service response
    /// </summary>
    /// <param name="source"></param>
    public void refresh(string source) {
    string[] strTok = source.Split(new string[] { "&" }, StringSplitOptions.RemoveEmptyEntries);
    foreach (string parameter in strTok) {
    string[] pair = parameter.Split(new string[] { "=" }, StringSplitOptions.RemoveEmptyEntries);
    typeof(ConsumerContext).GetProperty(pair[0]) //member names conveniently named from responses
    .SetValue(this, HttpUtility.UrlDecode(pair[1]), null);
    }
    }

    public string oauth_token { get; set; }

    public string oauth_token_secret { get; set; }

    public string oauth_expires_in { get; set; }

    public string xoauth_request_auth_url { get; set; }

    public string oauth_callback_confirmed { get; set; }

    public string oauth_session_handle { get; set; }

    public string xoauth_yahoo_guid { get; set; }

    public string oauth_authorization_expires_in { get; set; }

    }


    so, in the part of your application that requests access, say register. aspx

    CODEBOX
    #region [Helper Methods]

    /// <summary>
    /// Register User to Application
    /// </summary>
    private void register() {
    yahoo.fantasysports.OpenAuth.ConsumerContext context = yahoo.fantasysports.OpenAuth.get_request_token(
    ConfigurationManager.AppSettings["consumer_key"],
    ConfigurationManager.AppSettings["consumer_secret"],
    ConfigurationManager.AppSettings["callback_url"]);
    Application[context.oauth_token] = context;

    redirect(context.xoauth_request_auth_url);

    return;
    }

    /// <summary>
    /// Redirect to the
    /// </summary>
    /// <param name="url"></param>
    private void redirect(string url) {
    Response.Redirect(url);
    return;
    }

    #endregion


    This would redirect you to the yahoo authentication page, you enter your credentials if needed, unless you are already signed in, in which case, you would just authorize access. Upon doing so, you get redirected, and the tokens are posted.

    example possible handling:

    CODEBOX
    if (Request.Params["oauth_token"] != null) {
    Response.Write("<table>");
    if (Application[Request.Params["oauth_token"]] != null) {
    yahoo.fantasysports.OpenAuth.ConsumerContext consumer_context
    = (yahoo.fantasysports.OpenAuth.ConsumerContext)Application[Request.Params["oauth_token"]];

    yahoo.fantasysports.OpenAuth.get_access_token(
    ConfigurationManager.AppSettings["consumer_key"],
    ConfigurationManager.AppSettings["consumer_secret"],
    consumer_context,
    Request.Params["oauth_verifier"]);

    Response.Write("<tr><td>oauth_token:</td><td>"
    + consumer_context.oauth_token
    + "</tr></tr>");

    Response.Write("<tr><td>oauth_token_secret:</td><td>"
    + consumer_context.oauth_token_secret
    + "</tr></tr>");

    }
    Response.Write("</table>");


    Of course you wouldnt just echo the stuff back, you would likely store it in a database or something. All you need when making requests to services is the access token, and you can use the other fields you have stored to re call get_token to give you new access tokens when they expire.

    This is something around the solution that I am working with now, where my application is actually a desktop style application, im using a small web app to do the registration, and sharing the database with the desktop style application. Its pretty slick.
    0
  • id be willing to post a complete full circle implementation of this, if someone could instruct me on how to post such a zip file to these forums.

    I don't have any way of hosting the file myself for any amount of time.
    0
  • QUOTE (Sam Coder @ Jul 23 2010, 07:54 AM) <{POST_SNAPBACK}>
    id be willing to post a complete full circle implementation of this, if someone could instruct me on how to post such a zip file to these forums.

    I don't have any way of hosting the file myself for any amount of time.


    I'd love to see the full source of what you are doing. I cannot find any way to attach a file in these forums. Can you post it on a public site like YouSendIt or FileDropper and post the link here? Or even use DropBox?

    I have built a web app for my fantasy league in ASP.net MVC and am trying to do some minimal integration with Yahoo FF. I have the example you posted working just fine via WinForms, but am having trouble wrapping my head around how to persist the credentials so the user does not have to login to Yahoo every time they login to my app. I have not even started working on porting this to ASP.net, but it looks like you have done a lot of that already, so it would be very helpful.

    Thanks!
    0
  • Yup, I will figure something out. It will likely be tomorrow, today, I'm busy cleaning up another project going out the door.

    will keep you posted
    0
  • Did you ever find a location to put the the full source? I think it would be extremely helpful. Thanks
    0
  • Thanks Sam! I will try it out when I get some time.
    0
  • Guys, I know this is an old thread but would really appreciate some help. Basicall, I'm creating a web site (on SharePoint) to manage our fantasy leagues year round. I would absolutely LOVE to be able to pull in data right from our yahoo league(s) and render that right to my page (i can handle the formatting of the data fine once I get it).

    My first and most ideal goal was to just have a simple set of HTML code (in an xml viewer web part, that renders the XML returned by the REST request I already have built). Unfortunately, this OAUTH stuff is killing me and it doesn't seem there is any way I can issue simple HTML requests to get our data back.

    So, that landed me on this thread. I was able to create all the classes, compile the code, and can paste the provided URL from a console app into a browser and generate a request for my app to access my data. Now... here is where I am stuck. I put in a readline() section where I could pass back to my code the provided "auth token" hoping I could then have my code issue the http request and return the XML data. This isn't working. Can anyone lend a hand how I can get this returning the data?[code]

    string url = wrapper.BeginAuth();
    Console.WriteLine(url);

        //string validator_token=Console.ReadLine();
        string validator_token = "";
        wrapper.CompleteAuth(validator_token);

        HttpWebRequest request = WebRequest.Create("http://query.yahooapis.com/v1/yql?q=select%20*%20from%20fantasysports.leagues.scoreboard%20where%20league_key%3D'257.l.24009'") as HttpWebRequest;

        using(HttpWebResponse response = request.GetResponse() as HttpWebResponse)
        {
        StreamReader reader = new StreamReader(response.GetResponseStream());
        Console.WriteLine(reader.ReadToEnd());
        }

    Second question: If I were to have this code running behind the scenes on the server, how would this interact with the person hitting the website? Ideally I would like anyone from our (or any league they belong to) to hit the side and have their league data come back.
    0
  • Guys, I know this is an old thread but would really appreciate some help. Basicall, I'm creating a web site (on SharePoint) to manage our fantasy leagues year round. I would absolutely LOVE to be able to pull in data right from our yahoo league(s) and render that right to my page (i can handle the formatting of the data fine once I get it).

    My first and most ideal goal was to just have a simple set of HTML code (in an xml viewer web part, that renders the XML returned by the REST request I already have built). Unfortunately, this OAUTH stuff is killing me and it doesn't seem there is any way I can issue simple HTML requests to get our data back.

    So, that landed me on this thread. I was able to create all the classes, compile the code, and can paste the provided URL from a console app into a browser and generate a request for my app to access my data. Now... here is where I am stuck. I put in a readline() section where I could pass back to my code the provided "auth token" hoping I could then have my code issue the http request and return the XML data. This isn't working. Can anyone lend a hand how I can get this returning the data?[code]

    string url = wrapper.BeginAuth();
    Console.WriteLine(url);

        //string validator_token=Console.ReadLine();
        string validator_token = "";
        wrapper.CompleteAuth(validator_token);

        HttpWebRequest request = WebRequest.Create("http://query.yahooapis.com/v1/yql?q=select%20*%20from%20fantasysports.leagues.scoreboard%20where%20league_key%3D'257.l.24009'") as HttpWebRequest;

        using(HttpWebResponse response = request.GetResponse() as HttpWebResponse)
        {
        StreamReader reader = new StreamReader(response.GetResponseStream());
        Console.WriteLine(reader.ReadToEnd());
        }

    Second question: If I were to have this code running behind the scenes on the server, how would this interact with the person hitting the website? Ideally I would like anyone from our (or any league they belong to) to hit the side and have their league data come back.
    0
  • Hi Charles,

    You look to be creating an entirely new web request at the end there, without leveraging any of your returned OAuth data. It's best to use the provided wrapper class to make that final web request, like so:

    [code]    XmlDocument xml = new XmlDocument();
                string requestUrl = "http://query.yahooapis.com/v1/yql?q=select%20*%20from%20fantasysports.leagues.scoreboard%20where%20league_key%3D'257.l.24009'";

                string accessToken = wrapper.CompleteAuth(validator_token);
                var request = wrapper.consumer.PrepareAuthorizedRequestAndSend(new MessageReceivingEndpoint(requestUrl, HttpDeliveryMethods.GetRequest), accessToken);

                using (Stream res = request.ResponseStream)
                {
                    xml.Load(res);
                }[/code]

    That will load the query data into your xml object.
    0
  • hello sam,
    i am getting same error "file not found" on requesting token.
    what's wrong in that url? plz tell me
    thanks


    QUOTE (Sam Coder @ 16 Jul 2010 7:43 AM) Thanks Sean, I appreciate the encouragement. =)

    if anyone has any concerns or suggestions, please speak up, I generally don't take offense to constructive criticism, and am looking at this as a great opportunity to learn.
    0
  • This is absolutely FANtastic...

    But I do not understand, when I am done I have this access token, how do I use that to make my queries? seems like I am missing that last step...

    0

Recent Posts

in Fantasy Sports API