Closed hfloyd closed 6 years ago
Hi @hfloyd. Thanks for your question. I will check that and send you more detailed example. Seems that the current documentation would be misunderstand. If Goodreads behaviour is different from the documentation, I will update it too.
Thanks for your assistance, @VladimirRybalko and for your work on this library :-)
The Goodreads documentation about OAuth is here: https://www.goodreads.com/api/documentation#oauth
And their sample code (only in ruby & python): https://www.goodreads.com/api/oauth_example
I spent some more time with this, trying different things and stepping through the code - including your library code and have some other observations.
Using this code...
// Create an unauthenticated API client [because right now I have no tokens, right?]
var client = new GoodreadsClient(apiKey, apiSecret);
var testData = client.Authors.GetAuthorIdByName("John Milton").Result; //This does return data, so I know the API key is working....
// Get the Goodreads URL to redirect to for authorization
var callbackUrl = HttpContext.Current.Request.Url.ToString();
var authorizeUrl = client.Connection.Credentials.GetRequestTokenAndBuildAuthorizeUrl(callbackUrl);
//The unauthenticated API client has data in the "credentials" property....
var requestToken = client.Connection.Credentials.OauthToken; //this matches the string included in 'authorizeUrl'
var requestSecret = client.Connection.Credentials.OauthTokenSecret; //I wonder where this comes from???
if (string.IsNullOrEmpty(requestToken))
{
HttpContext.Current.Response.Redirect(authorizeUrl);
return string.Format("Click here to Authenticate: {0}", authorizeUrl);
}
else
{
// Get the access token from the unauthenticated client?
var credentials = client.Connection.Credentials.GetAccessToken(apiKey, apiSecret, requestToken, requestSecret);
//At this point "credentials.OauthToken" and "credentials.OauthTokenSecret" are NULL, so the next part doesn't work...
// Create an authenticated API client
var authClient = new GoodreadsClient(apiKey, apiSecret, credentials.OauthToken, credentials.OauthTokenSecret);
var test = authClient.Connection.IsAuthenticated;
var userId = authClient.Users.GetAuthenticatedUserId().Result;
return string.Format("Current User: {0}", userId);
}
In "GetAccessToken()" I am seeing a response of "Invalid OAuth Request" when passing in those two OAuth values, so that still isn't right...
Okay! I've figured it out!
So, the "client.Connection.Credentials.OauthToken" & "client.Connection.Credentials.OauthTokenSecret" ARE the request values, so if I stored them for later retrieval (on the callback url)...
//The unauthenticated API client has data in the "credentials" property.... these are the request values
var requestToken = client.Connection.Credentials.OauthToken;
var requestSecret = client.Connection.Credentials.OauthTokenSecret;
//store these for later in cookies
var cookieResponse = SaveRequestTokens(requestToken, requestSecret); //returns an HttpResponseMessage with the cookies added
var returnVal = string.Format("<p>Click here to Authenticate: <a href=\"{0}\">{0}</a></p>", authorizeUrl);
HttpContext.Current.Response.ContentType = "html";
HttpContext.Current.Response.Write(returnVal);
return cookieResponse;
Then on the callback...
//retrieve original request tokens from cookies
var requestToken = GetRequestToken();
var requestSecret = GetRequestSecret();
//Pass in original request tokens...
var credentials = client.Connection.Credentials.GetAccessToken(apiKey, apiSecret, requestToken, requestSecret);
//store the access token info for later use
var cookieResponse = SaveAccessTokens(credentials.OauthToken, credentials.OauthTokenSecret);
// Create an authenticated API client now works
var authClient = new GoodreadsClient(apiKey, apiSecret, credentials.OauthToken, credentials.OauthTokenSecret);
I wonder if it would make sense to rename the properties: client.Connection.Credentials.OauthToken --> "OauthRequestToken" & client.Connection.Credentials.OauthTokenSecret --> "OauthRequestSecret" to make it clearer?
Also, I'd be happy to add a Wiki page with my entire code sample.
Hey!
Sorry I've been a bit busy lately but I'm glad you got things figured out, good job! I was just working on a solution here and confusing myself in the process as well. The properties could definitely be renamed a bit clearer and I wonder if the whole process could be streamlined.
You definitely hit on the right solution though. Storing the request token and request secret for future requests is how I would do it too.
I just created a goodreads-dotnet-samples repo where we can maybe create a few simple applications illustrating this library. An example piece of code that you can run and debug through is always a huge help. I'll see if I can get a basic structure out today and we can go from there.
Hi @adamkrogh. Attached is a slightly stripped-down version of my code (which is a WebApi) feel free to incorporate this as you see fit. Sample Goodreads WebApi Controller.txt
Or, let me know where you'd like this pasted in your skeleton project and I'll be happy to add it for you.
Ough. Sorry for delay. Now I'm changing my place of residence. So I'm a bit busy. @hfloyd @adamkrogh, it's a really cool job! I think we may include samples into this repository or add link to read.me at least.
@hfloyd thank you for your MVC example. I think I will include it into our new Demo application. It will be soon..
@hfloyd Thank you for your question. It inspired me to redesign our auth infrastructure and add many examples. Please check links below: Demo application Wiki page
@VladimirRybalko Looks great :-)
If I ever pick up my tentative project again, I'll be sure to test it out. (I've been finding the GoodReads API to be irritatingly limited in many ways...)
Hello, I am a bit new to OAuth, but am struggling to understand how this library can be used to get access to an authenticated user's data.
The example includes these two lines:
I have my API Key & Secret... my confusion is related to the other 4 items : oauthToken, oauthTokenSecret, requestToken, requestSecret. If I do the following:
Redirect user to authorizeUrl for "Allow" permission to be granted. Goodreads redirects back to the callBack url including a query string like: "?oauth_token=xxxxxxxxx&authorize=1"
What does "oauth_token" represent? Is this the "requestSecret"?
Example code from callback, which includes the query string data:
I am missing something significant here... Can you point out where I am going wrong? Thanks