Hi Dani, AFAIK OAuth 2.0 supports 3 flavours: Server side apps, client side apps and installed apps. Does Daniweb Oauth allow OOB in the redirect_uri which is part of the support for installed/standalone apps? If no, are you expecting desktop app writers to spawn a local web server and use the serverside flow?

Recommended Answers

All 21 Replies

I, personally, am a web developer with no desktop application experience. As a result, there is no native support for OAuth with installed apps. It would be great if you could point me to some examples on the correct method to handle installed apps and I'll defintely look into it.

I'm personally not aware of what kind of code changes are to be required to the server to support OAuth 2.0 standalone apps. But, I can definitely point you to the document which outlines how clients should interact with providers who have desktop/standalone support.

Using OAuth 2.0 for Installed Applications

In the document you linked me to, it specifies that, "This flow requires that the application has access to the system browser or the ability to embed a browser control in the application."

The method outlined on that page would work with our existing serverside implementation.

Oooh I see what you mean by OOB. We currently only support the redirect uri being an http://localhost port. Is there a need to expand this to support the other method as well?

EDIT: Missed your latest post so the below is for #4 post in this thread.

The method outlined on that page would work with our existing serverside implementation.

No, there is a very important distinction which is why the "are you expecting desktop app writers to spawn a local web server" part in my original post.

In the standalone mode, the application just needs the capability of opening up a URL in the system-default browser which is pretty easy and painless. Once that URL is opened, the user can login to the oauth provider, accept the application terms and get back a token. This user can then input this code/token into your standalone app and we are golden.

In the serverside mode, the application needs to provide a redirect URL. Let's assume that I say http://localhost:8080 (since it's a local app). Now the problem is that the OAuth provider would try redirecting to this address which would fail. Why? Because there is nothing accepting connections on that host/port combination. To get around this, the standalone app writer has to spawn a web server (in-process or out-of-process) which would accept the redirect by the Oauth provider, capture the code and then start phase 2.

Hope that makes sense.

Is there a need to expand this to support the other method as well?

I would say "yes" otherwise it's pretty painful to spawn a local web server just to get the code and makes the entire task look daunting. Plus if you are hoping for an Android/Win/iOS port, adding this would ease the job of the guy writing it.

I had something else already on the todo list for today but I'll try to tackle this as well!

Random question ...

Now the problem is that the OAuth provider would try redirecting to this address which would fail.

Are you not able to simply send an HTTP request and then capture the header information that is returned? The information that you need is tacked on as a query string parameter to the redirect_uri. You can simply throw out the redirect_uri and parse the parameters??

Sorry, my only experience is with web development. Similarly, can you please confirm that desktop applications cannot parse the browser's URL but they can parse the browser's title bar?

I've made some changes. Still working on it, but please let me know if this is what you're looking for. Sorry but I have no experience with this stuff. Feedback much appreciated!!

Sure, I'll try testing it on my side. I'm assuming you have made some changes to how standlone apps deal with the Daniweb oauth infrastructure. I tried sending a request:

http://www.daniweb.com/api/oauth?response_type=code&client_id=40&redirect_uri=urn:ietf:wg:oauth:2.0:oob

which should ideally bring me to a page which asks for user permission. When approved, a new page should open up which has the code that the client can put in my app.

Right now, after using the above URL and allowing the app to access my data, I don't get redirected to a new page. You can click on the above link and see what I'm trying to say.

Try setting the redirect_uri to simply 'oob' instead of the whole urn:blahblahblah.

Are you not able to simply send an HTTP request and then capture the header information that is returned? The information that you need is tacked on as a query string parameter to the redirect_uri. You can simply throw out the redirect_uri and parse the parameters??

Problem is that this process is not automated and requires user intervention. For e.g. I can send an HTTP request but then I would be greeted by a page which asks the user for permission. Since I need user to click a button, I can't easily do it completely in code, I have to spawn a browser process. Once I spawn the process, the control is out of my hands and it really would be painful to get a handle to the new process and read the process specific data like title bar or headers.

Similarly, can you please confirm that desktop applications cannot parse the browser's URL but they can parse the browser's title bar?

I won't be parsing anything but would be relying on the user to enter the generated code. Like mentioned in previous post, I'm aiming for something like this screenshot.

Try setting the redirect_uri to simply 'oob' instead of the whole urn:blahblahblah.

Great, that worked though I think you should later refactor code to stick to the standards. :)

Anyways, moving on, I now get the error "There was an error fetching an access token" when I submit a POST request for the access token. Here is the code I'm using (it's Python but should be very easy to follow):

url2 = 'http://www.daniweb.com/api/access_token'
post_data = { 'code': 'my_code', 'client_id': '40', 'client_secret': 'my_secret', 'redirect_url': 'oob', 'grant_type': 'authorization_code' }
resp=requests.post(url2, data=post_data)

Would you be able to take a look at the request I sent across and find out what went wrong?

I'm sorry, I'm still confused what isn't working? Did you follow the documentation on the API page and specify 'oob' as the redirect_uri? Is that not what you want??

I'm sorry, I'm still confused what isn't working? Did you follow the documentation on the API page and specify 'oob' as the redirect_uri? Is that not what you want??

Currently I'm able to get the "initial code" but not able to retireve the access token using the URL which I got from your OAuth Daniweb tutorial. I have posted the URL I'm using along with the POST data I'm sending.

Yes, that URL worked fine. OAuth for standalone app has two parts: getting the code by asking the user to allow access and then using that code to get the access token. The first part (i.e. the URL which you posted) works fine for me and gives me a text box with the code string.

Now what isn't working is the second step; the step wherein I use the code to retrieve the access_token.

You are using redirect_url instead of redirect_uri in your code. Took me awhile of staring at it to figure that out.

Yup that was a really bad mistake, good job spotting that! :)

Anyways, I have finally got the OAuth API functions working in a console script. There are a few problems with some API calls which I have tried to mention inline in comments. The code is in Python and assumes you have the "requests" module installed.

This code can be easily adapted to any language; just make sure that you fill in the appropriate slots which start with "put_in_your" in the below code extract.

Here is goes:

import requests, webbrowser

# send user to the app specific URL asking for code
url1 = 'http://www.daniweb.com/api/oauth?response_type=code&client_id=put_in_your_client_id&redirect_uri=oob'
webbrowser.open_new(url1)

# Use the code from the above response to send POST request
code = 'put_in_your_code_from_above'
client_secret = 'put_in_your_apps_client_secret'
url2 = 'http://www.daniweb.com/api/access_token'
post_data = { 'code': code, 'client_id': 'put_in_your_client_id, 'client_secret': client_secret, 'redirect_uri': 'oob', 'grant_type': 'authorization_code' }
res2 = requests.post(url2, data=post_data)

access_token = res2.json()['access_token']
url3 = 'http://www.daniweb.com/api/me?access_token=%s' % access_token
res3 = requests.get(url3)
res3.text

url4 = 'http://www.daniweb.com/api/me/inbox?access_token=%s' % access_token
res4 = requests.get(url4)
res4.text

# TODO: I can start watching but can't stop watching articles when POSTing
# TODO: Is there a reason why the response text of the below 4 API calls is always the LCD v/s CRT thread?!
url5 = 'http://www.daniweb.com/api/articles/watch'
aid = 468648
res5 = requests.post(url5, data={'id': aid, remove: 'false', 'access_token': access_token})
res5.text

# TODO: I can stop watching but can't start watching article when GETing
url6 = 'http://www.daniweb.com/api/articles/%s/watch?access_token=%s&remove=true' % (aid, access_token)
res6 = requests.get(url6)
res6.text

# TODO: The very first call for a given post works; after that both GET and PUT call fail
# with 400 status code (No data matching your criteria). It again starts working if I revert the vote manually using the site
url7 = 'http://www.daniweb.com/api/posts/vote'
pid = 2041959
res7 = requests.post(url7, data={'id': pid, 'vote': '1', 'access_token': access_token})
res7.text

url8 = 'http://www.daniweb.com/api/posts/%s/vote?access_token=%s&vote=%s' % (pid, access_token, 1)
res8 = requests.get(url8)
res8.text

url9 = 'http://www.daniweb.com/api/chat'
# Post to Dani's shoutbox
res9 = requests.post(url9, data={'access_token': access_token, 'room_type': 'member', 'room_id': '1', 'message': 'Hello from OAuth Desktop Client'})
res9.text
# Post in community center
res9 = requests.post(url9, data={'access_token': access_token, 'room_type': 'forum', 'room_id': '3', 'message': 'Hello from OAuth Desktop Client'})
res9.text

In terms of feedback, I'm a bit confused as to why the API calls are not pure GET or POST but a mix of both which is kind of confusing. If you are modifying something, make it a POST call. If you are retrieving something, make it a GET call. That way you don't have to specify the "GET or POST" / "GET" / "POST" parameters on the left side of your API function.

If you are modifying something, make it a POST call. If you are retrieving something, make it a GET call.

For the most part, that's the way it works. The start/stop watching articles thing is probably a bug I'll look into. Also, it's a known limitation that you can vote but you can't unvote from the API right now.

# TODO: I can start watching but can't stop watching articles when POSTing

Why can't you just do exactly what I am doing in my sample usage example?? I am stopping watching an article through a POST request.

# TODO: Is there a reason why the response text of the below 4 API calls is always the LCD v/s CRT thread?!

I don't have access to articles that you're watching so I can't debug this. More info would be helpful though.

# TODO: The very first call for a given post works; after that both GET and PUT call fail with 400 status code (No data matching your criteria). It again starts working if I revert the vote manually using the site

It's by design that you can vote via the API but not undo a vote via the API. Will most likely be added in the future. It gives you a cryptic error message, I agree.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.