Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations gkittelson on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Any experience with Etsy OAuth API?

Status
Not open for further replies.

TinyNinja

Programmer
Oct 1, 2018
99
US
Hello VFP Community,

I have hit a wall with Etsy OAuth. I've been trying to figure this out for a week now and went down the rabbit hole of searches.
I have looked over Etsy's overview guides and struggled to get the results they show. I did a few searches through their forums and still confused.

I have a developer account with Etsy and have my Keystring & Shared secret ready to go for my project.

I have used MSXML2.XMLHTTP.6.0 to connect to Etsy's API and got that working. In one of my searches I found people using WinHttp.WinHttpRequest.5.1 for other things and the comments mentioned OAuth, is this able to use OAuth?

I have looked over and tried to figure out Olaf's amazing creations VFPOAuth & VFPTweetAPI but struggle when it comes to the token request and storing feature. I'm not fully sure which items need to be changed to satisfy Etsy's requirements. I must be not filling in the correct info because no external window opens up with a token to fill in with. I'm also not sure the best way to save the token once I do get it.

Could someone please give me a push in the right direction please?
 
Jo, thanks for trying, but I only worked for sometime on the VFPTweetAPI and that worked with Twitter, I doubt it will still. And I tried to generalized this to VFPOauth to work with any OAuth authentication scheme, but I also never tested this with anything but Twitter.

This was designed after the OAuth 1.0a standard, which was new back then. And I see Etsy is using OAuth version 1.0, not sure if that difference already is explaining it. But you surely need your key and secret and I also assume most web based OAuth implementations expect a callback URL, which is a concept not working with a Desktop Application as VFP EXEs are.

It shouldn't be hard to find what you need as library in other languages, and let VFP work via that. Either in IE automation by a JS library or by writing a website in whatever supports a library in PHP or PyYhon or Node.js and address that. I don't have the time to work on this at the moment.

Bye, Olaf.

Olaf Doschke Software Engineering
 
Thank you for the insight Olaf.

Let me just make sure I understand what you are saying. VFP struggles with the callback URL part so it would be better to pair VFP with another language listed or found that can handle the callback. Would it then need to pass over the parameters to the vfp app or would the other language hold onto the connections allowing vfp app to run the API connections desired freely?
 
Well, the callback isn't really a callback in the usual sense, but as this is authentication on the web the usual assumption is you're using something from the web and not a Desktop software. The callback URL is something you get redirected to by Etsy after authentication, your Desktop app doesn't react to such a redirect, though, your Desktop application is not a webserver.

AS far as I remember one other mechanism back then from twitter was to let Twitter display a code on some page that you then must enter into a desktop application, but I don't think this works that way anymore. Anyway, from API specifications I see also for example for Google Drive the expectation is that only websites/domains make use of web authentication to authenticate against some web service. You always have that technology mismatch with Desktop apps using some cloud service, even though Google itself does provide the Backup&Sync software that actually is a Desktop software to sync the cloud drive with your local directory mapped to the root Google drive, for example.

Bye, Olaf.

Olaf Doschke Software Engineering
 
OK, now I looked at it a bit and remember that strange idea to specify 'oob' as redirect URL as you can see in oauthgoogle.prg

Code:
cRedirectURI        = 'oob'

This was by the OAth specifications step 6.1.1:

Instead of Google or Twitter redirecting you to a page of the web application that authenticated, Google or twitter displayed a page with a PIN number and the INPUTBOX in my _test.prg was there to enter that. I don't think any site does that this way, anymore.

Sites either use OAuth 2 or OAuth 1, not 1.0a

Bye, Olaf.

Olaf Doschke Software Engineering
 
Oh, and last not least, you should be aware that OAuth os not over after you authenticated. Once you have the result, the OAuth token, every further request you do must be cryptographically signed with it. The token itself is not passed back, it becomes a client secret on top of the key/secret pair you start with as API client. You only prove that you have this token by the correct signature of any further service requests.

And I remember that was a criticism of the 1.0a version: The token has some power for the usage of a server as some user it authenticates. And it can be set to never expire. Thus to store such tokens becomes a client-side security issue for safe storage. I think I just programmed this at the wrong time.

Bye, Olaf.

Olaf Doschke Software Engineering
 
I looked more over the Twitter OAuth1 and now second guesting myself.
Am I suppose to do everything in the example and then add at the bottom the stuff from the Etsy example to successfully communicate with the API?

I just added the code below to my app and got the token and token secret. When I did the Oauth from the Etsy example it showed connected since there were no error messages.

Code:
lcConsumerKey = "etsy_CONSUMER_KEY"
lcConsumerSecret = "etsy_CONSUMER_SECRET"

lcRequestTokenUrl = "[URL unfurl="true"]https://openapi.etsy.com/v2/oauth/request_token"[/URL]
lcAuthorizeUrl = "[URL unfurl="true"]https://etsy/oauth/authorize"[/URL]
lcAccessTokenUrl = "[URL unfurl="true"]https://etsy/oauth/access_token"[/URL]

* The port number is picked at random. It's some unused port that won't likely conflict with anything else..
lcCallbackUrl = "[URL unfurl="true"]http://localhost:3017/"[/URL]
lnCallbackLocalPort = 3017

* The 1st step in 3-legged OAuth1.0a is to send a POST to the request token URL to obtain an OAuth Request Token
loHttp = CreateObject('Chilkat_9_5_0.Http')

loHttp.OAuth1 = 1
loHttp.OAuthConsumerKey = lcConsumerKey
loHttp.OAuthConsumerSecret = lcConsumerSecret
loHttp.OAuthCallback = lcCallbackUrl

loReq = CreateObject('Chilkat_9_5_0.HttpRequest')
loResp = loHttp.PostUrlEncoded(lcRequestTokenUrl,loReq)
IF (loHttp.LastMethodSuccess <> 1) THEN
    ? loHttp.LastErrorText
    RELEASE loHttp
    RELEASE loReq
    CANCEL
ENDIF

* If successful, the resp.BodyStr contains something like this:  
* oauth_token=-Wa_KwAAAAAAxfEPAAABV8Qar4Q&oauth_token_secret=OfHY4tZBX2HK4f7yIw76WYdvnl99MVGB&oauth_callback_confirmed=true
? loResp.BodyStr

loHashTab = CreateObject('Chilkat_9_5_0.Hashtable')
loHashTab.AddQueryParams(loResp.BodyStr)

lcRequestToken = loHashTab.LookupStr("oauth_token")
lcRequestTokenSecret = loHashTab.LookupStr("oauth_token_secret")
loHttp.OAuthTokenSecret = lcRequestTokenSecret
 
Skimming through Chilkats twitter code and etsy code, the twitter code shows how to obtain tokens and the etsy code how to use them.
Your code goes as far as getting the request token. You need to get an access token with this request token to then start acting authorized by the etsy user.

So you need to take the oath_token from the resp.BodyStr as the last few lines do, and then go for the lcAccessTokenUrl = " and the response for that gets the access token you actually need to do something.

Bye, Olaf.

Olaf Doschke Software Engineering
 
Success!
I added Chilkats entire code and tweaked where needed. I have grabbed the access tokens now for Etsy and will be testing an upload now.

But now something strange happens. Once the code is done running it will close up my entire VFP IDE and I have to restart VFP. I've looked over the code and have tried to stop this from happening when it goes to the end but nothing has worked.

Has anything like this happened to anyone else?
 
Indeed just today, though I can put my finger on experiments with Bindevents and Windows Message handling gone wrong and I don't see you doing such a low-level thing. But worth noting I didn't get a C5 error, VFP simply closed as if quit normally. Which is new.

The lowest level stuff in Chilkat code is HTTP, especially a passage of the Chilkat code acting as a webserver for the callback request we talked about by listening to a socket on a given port.

The only advice here is to single-step through the code in the debugger to see ar which line VFP crashes. SET STEP ON after the last line you know works correctly, ie you know you get the access token and are quite at the end already? Add the SET STEP ON there. If it's actually happening at the end of code, when VFP automatically releases variables, it might be destroy of some object crashing and this also crashing the VFP process. So even set step on at the end might bring up something in the debugger, like Destroy event code.

Bye, Olaf.



Olaf Doschke Software Engineering
 
crash_k083dq.png


Aftering running the debugger it crashes at the end where my cancel is. I took a screenshot of where in the code it goes to and the error to hopefully helps.

It's a lot to post but the flow is I do the steps through twitter_oauth1 and modified everything to match Etsy needs and after that is successful roll right into etsy_update_inventory_listing. I have a test upload that fails but that is not where the VFP IDE crashes so no biggy, will fix later. I have a cancel at the end and that is where the crazy crash happens.

I'm not sure where this is exactly but I did upload a screenshot of the point of failure before it takes VFP offline.

I even tried releasing each variables used and still crashes at the cancel.

Code:
loJsonResponse = Createobject([Chilkat_9_5_0.JsonObject])
loJsonResponse.Load(lcJsonResponseText)
loJsonResponse.EmitCompact = 0

? loJsonResponse.Emit()

SET STEP ON

? "Response status code: " + Str(loRest.ResponseStatusCode)

Cancel    <-- This is where the crash happens
 
Cancel? This is something you can use in an error handler, but not in normal code. Return or just do nothing, which means an implicit return .T. - but notice the name return comes mainly from returning control to the caller, the next higher stack level (or lower, depending how you interpret what stack levels going down or up), not from returning=transporting back a value. You can write RETURN without a value, that's optional.

Cacnel is more rigorous than what the introduction line of the help states: "Ends execution of the current Visual FoxPro program file."
You only need return to do that or even just nothing, just let the program pointer hit the end of the PRG file and it will return to the caller. And if you do a PRG from the command window, that'll be the caller and the staack will be empty and this also bringa you back to the command window.

Cancel also means to VFP to stop continue with any further code, not continue with the line after the call, so stop executing and go back to interactive IDE mode. And in deep stack you better cause a clear events when a read events is active or use RETURN TO MASTER.

But as said, CANCEL only has a meaningful use (to me) in an error handler. Or when you're stuck with nonreleasing objects even CLEAR ALL don't get rid off. So CANCEL is among a series of cleanup code I use to bring an IDE back to normal after something crashes without crashing the IDE fully, at least.

Anyway, your code may also crash without CANCEL. It's worth a try simply removing that line. But release of local and private variables also is done with a normal RETURN from a PRG. So the next level of analysis is to use SET COVERAGE and write a log. With the caveat it only logs lines of code executing. Itt seems some destroy event of a released object crashes your IDE and that will only show up in the coverage log when there is code in destroy. So you would need to do anything like SET MESSAGE TO 'Bye from me' or something else non-blocking and working without any prerequisites. If you have that in all the classes used within the context your last line of coverage log tells you what destroy causes the crash, if it's not simply your timer event.

And I know, this could be hard for all the ActiveX objects involved, when you use them as is not a derived class, and deriving a class from an ActiveX control actually isn't real inheritance, you always inherit from the VFP baseclass OleControl and let it be that OleControl (and an "onionskin" of VFP properties, method and events including a Destroy. So you never get into the actual destroy event of an ActiveX control, only VFPs "onion skin" destroy. It should be enough to get from the coverage login which object last executes it's destroy.

What you can do then is try to resolve the issue by actively releasing objects in another order, there may be a dependency that causes the crash and objects released in correct order don't crash. Also some objects need to release in a good state. I think a crash candidate is a Socket you release while it is set to listen to a port. First it should stop listening.

I don't see what I could get from the screenshot, the program pointer arrow points to the last line in the screenshot and likely the crucial code crashing is just following. I would suggest you configure the debugger to skip timer events, so timer code is not included in debugging, as it's often crucial the timer events are done within timer intervals to not crash the system.

Skimming through code I see you have a means to stop timers while debugging, I guess exactly that mechanism fails, but it's simply a debugger option to generally not display and single-step through timer events: In the main VFP IDE Tools-Optoins, Debug tab untick "Display Timer events"

notimerevents_djsbey.jpg


Bye, Olaf.

Olaf Doschke Software Engineering
 
Hey Olaf,

I only use cancel when I am going through the design phase of the code and want it to stop before the end since I close everything out and don't want to keep reopening windows. After everything works I will remove the cancels I placed throughout the code. I checked and I did have the Display Timer Event unchecked like you show in the picture.

I usually put a return at the end of my code to denote the EOF and will put procedures or functions below it.

This time I was able to scroll down and capture the procedure with the issue. This crash happens at the return part which is my EOF. I released the variables used but I really feel this might be linked to the listening part of Chilkats code when waiting for the browser to open up. I feel like I could remove that whole part and should be fine.

I will play around with more of the items you suggested but found this for right now.

crash_fxzazz.png



I did the Set Coverage To and found the sequence of everything.
Logs of programs.
Logs_o0qrbz.png



The last things to fire off after the program finishes is:
timer ------ \thor\tools\procs\thor_proc_intellisensextimer.fxp
getwindowtype ------ \thor\tools\procs\thor_proc_intellisensextimer.fxp
foxtabstoolbar.tmrremovefoxtab.timer ------ \thor\tools\apps\foxtabs\foxtabs\foxtabs.vct
foxtabstoolbar.removefoxtab ------ \thor\tools\apps\foxtabs\foxtabs\foxtabs.vct
foxtabcontrol.foxtab_assign ------ \thor\tools\apps\foxtabs\foxtabs\foxtabs.vct
foxtabstoolbar.removefoxtab ------ \thor\tools\apps\foxtabs\foxtabs\foxtabs.vct
foxtabcontrol.destroy ------ \thor\tools\apps\foxtabs\foxtabs\foxtabs.vct
foxtabstoolbar.removefoxtab ------ \thor\tools\apps\foxtabs\foxtabs\foxtabs.vct
foxtabstoolbar.showlastfoxtab ------ \thor\tools\apps\foxtabs\foxtabs\foxtabs.vct
foxtabstoolbar.removefoxtab ------ \thor\tools\apps\foxtabs\foxtabs\foxtabs.vct
foxtabcontrol.tabstyle_assign ------ \thor\tools\apps\foxtabs\foxtabs\foxtabs.vct
foxtabcontrol.setimageorientation ------ \thor\tools\apps\foxtabs\foxtabs\foxtabs.vct
foxtabcontrol.tabstyle_assign ------ \thor\tools\apps\foxtabs\foxtabs\foxtabs.vct
foxtabstoolbar.removefoxtab ------ \thor\tools\apps\foxtabs\foxtabs\foxtabs.vct
timer ------ \thor\tools\procs\thor_proc_intellisensextimer.fxp
getwindowtype ------ \thor\tools\procs\thor_proc_intellisensextimer.fxp
timer ------ \thor\tools\procs\thor_proc_intellisensextimer.fxp


This is exactly where it is coming undone really -- > thor_proc_intellisensextimer.fxp
Code:
Procedure GetWindowType
Local laEnv[25], llResult, lnHandle, lnResult

	If Not 'FOXTOOLS.FLL' $ Upper(Set('Library'))
		Set Library To(Home() + 'FoxTools.Fll') Additive
	Endif
	lnHandle = _WonTop()

	Try
		llResult = _EdGetEnv(lnHandle, @laEnv)
	Catch
		llResult = -1
	Endtry

	If llResult > 0
		Return laEnv[25]
	Else
		Return - 1
	Endif

Endproc
 
Update,

When I do not use Thor, the VFP IDE still crashes and I get no reports from the debugger or log files now. It just shows that I am running everything from my mainapp.prg and then it just decides to crash.

I did stop the code after the
loSock.Close(50)

and it still crashed. I believe like you said where something is not ending properly and I think it is in the listening sock code.
 
Sockets are a beast. A detail I remember is a listening socket getting a request should not be used to respond, that task needs to be put to a new socket. In your case of listening to the callback from setsy, you're not responding, though, all you want is the data coming in with the request, so after that is received the socket can be released.

I wonder what's going wrong here, because as far as I see the socket used is a Chilkat Ole class, too.

Bye, Olaf.

Olaf Doschke Software Engineering
 
I found the solution!!!! :)

I did a search on Chilkat blog to see if anyone asks about VFP crashing and they posted a fix. I gave it a shot and it works!!

Code:
loGlobal = CreateObject('Chilkat_9_5_0.Global')
lnSuccess = loGlobal.FinalizeThreadPool()

The FinalizeThreadPool() does the magic.

Thank you for all your help Olaf! :)
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top