node-500px icon indicating copy to clipboard operation
node-500px copied to clipboard

Implement OAuth

Open ro-ka opened this issue 10 years ago • 10 comments

Some API endpoints need OAuth to work. Add it!

ro-ka avatar Sep 02 '14 06:09 ro-ka

Ok so I'm thinking about the best way to do this. OAuth is pretty awkward here because of the round trip that has to be made to 500px to get an access token from the request token. Obviously it's not feasible to pop open a browser window to make sure the user has authenticated as part of a backend flow.

Perhaps we'd need to say that you should provide the oauth access token directly? This would require you setting up some sort of testing environment from which you could grab the access token though, which can be a real pain. Maybe we could provide a small page hosted on github pages where they can just enter their consumer key and secret and hit go, then it will pop up the oauth box and you hit accept, then the page gives you back the access token that you can use key in alongside the consumer key for the methods that need it? The only alternative is booting up a small server, sending the user to a browser address, and having the callback set to hit the small server so we can get the access key, which seems like an outrageous hack to me and a lot of work.

I spent a minute looking through the other libraries as well for any ideas. The python library has some crazy handling for this, I don't totally get what's going on here though. I briefly checked out the iOS and Android examples as well, and it looks like both of them use user/pass auth (usually called x-auth if I'm not mistaken), but I don't see any support for this in the 500px api docs, so not sure what's going on there either.

It's definitely a pain, but oauth unfortunately isn't really that great for this type of developer authentication :confused: Would love to hear any other thoughts you might have on this! IMHO I think the best way forward would be to ask directly for an access token and provide a little helper to more easily grab one.

EDIT: Here's another node library and the way they handle the oauth, which also looks rather painful: https://github.com/alexindigo/node-api_500px - what's going on here is essentially that there's a gap left where you need to hit a provided url and manually grant access to your app from 500px in a browser, so it's not really a continuous flow. Also since it doesn't really store anything, it seems like you'd have to do this every time, where if you ask for the access token directly, it wouldn't need any extra round trips.

jescalan avatar Sep 07 '14 06:09 jescalan

Ok so I mocked out how the flow would look for a sort of "authentication helper" app. It's kind of a crazy concept to need a companion app in order to get authentication working, but I'm afraid forcing only oauth 1.0 to be able to make API calls doesn't really consider server-side personal usage, it more favors a client side sign in so we can pull your data kind of thing. Anyways, here are the screens I mocked out.

screen shot 2014-09-07 at 11 40 05 am

screen shot 2014-09-07 at 11 40 24 am

screen shot 2014-09-07 at 11 40 40 am

screen shot 2014-09-07 at 11 40 49 am

The logic for this app shouldn't be too challenging. It would generate a unique id and present it as the callback url on the first screen, and stash it in a session. Then on the second screen, use the consumer key and secret to make the first call to get the 500px auth url on the server, then return that url to the client, which would open it as a popup. The user would then approve the app, which would hit the provided callback on the server, giving the access token and signature details needed. The page would then move to the final screen to display those details to the user. Finally, the user could enter these details alongside the client key with this library in order to make authenticated API calls.

Definitely going to be a pain to have to make the first time around, but it should make life much easier for anyone else trying to work with this API. I'd also really love to get the 500px engineering team's feedback on this, since it really shouldn't be necessary to jump through this many hoops, so I might ping them and see if I can get someone to jump in and offer their viewpoint on this issue.

jescalan avatar Sep 07 '14 15:09 jescalan

Hey guys, a @500px developer here. We're using https://github.com/intridea/omniauth ourselves to connect to 3rd-party authentication services — check their code out for some examples on OAuth flows.

Let us know if you need anything!

freeatnet avatar Sep 08 '14 22:09 freeatnet

Hi @freeatnet! Thanks for stopping by, really appreciate it. Omniauth is a wonderful ruby library, and I have used it a few times in the past, but I don't think it solves the issue here, or really relates to it at all. I think probably I just wasn't really clear enough in the issue I was experiencing, let me try to explain it better.

OAuth is a client-side auth flow. For this reason, you guys @500px have a wonderful client-side javascript library already made that does this well. This however is a node library that does not necessarily connect to the browser at all, so a flow like OAuth that requires the user to hit a specific url in their browser and interact with it doesn't really fit as well. The use cases for this library, as far as I know, are the following:

  1. You are making an app in which users can "sign in with 500px" in order to have the app utilize the 500px data in some way. In this situation, you would use the javascript library in-browser to collect the oauth token, then send it to the back end, where this library would use it to make calls to an API for the user's info.
  2. You are making an app which uses your personal 500px data in some specific manner. In this case, you would need to set up a situation in which you go through the OAuth yourself in order to get the token, then hard code that token into the back end for this library to make calls with.

In either of these situations, this library is not the one responsible for the actual OAuth flow, it's only responsible for making calls to the 500px API using a stored or hard-coded token. Because of this, I feel like the best way to treat implementing OAuth into this library is to ask directly for the OAuth token, rather than the consumer key and secret which can be used with an in-browser flow to get the OAuth token eventually, which this library is not capable of doing. This was the first conclusion I was asking you guys' opinion on.

The second piece I was interested in hearing from you guys on is as relates specifically to the second use case described above. For the app I'm working on, I'm just looking for access to my personal 500px data, and I assume I'm not the only one that has this desire. In this case, it's a pretty big pain to actually get the OAuth token needed to make requests. While OAuth makes plenty of sense for a user-based flow, if you are just looking to access your own account's data, you are jumping through a lot of hoops here. What's really needed is a pre-provided personal access token that you can use to access your own data. Above, I mocked out a sample app that could be used to hack this functionality by creating a shell app that is used to get a personal access token. Although this would work, it would be a bunch of extra work to implement.

My proposed solution here I'm going to borrow from twitter, who have been using OAuth for quite a long time. When you create a new twitter application, in addition to giving you the consumer key and secret which you can use to do user authentication, they provide a "pre-authed" personal access token that can be sent directly along with requests. If you guys were to implement something like this, it would be immensely useful, at least for me. Here's a screenshot of how the "personal token" section looks on the twitter developers page for a sample app, as a reference:

personal-token

Sorry for my boatload of stuff earlier, and I hope this explanation is a little more clear!

jescalan avatar Sep 08 '14 23:09 jescalan

I totally agree with you @jenius. Can't think of another way to get the user OAuth token without asking for it directly. I have the same use case that I want to have access to my own profile data. Till now it was sufficient to not have OAuth implemented and no one requested it. But lacking it is what kept me from making a v1 release as not the complete API is covered.

The Mockups look good! :)

ro-ka avatar Sep 09 '14 10:09 ro-ka

Ok, so I'm going to move forward with the pull request to add OAuth methods by providing the OAuth token alongside the client key in the initial config then, if that makes sense to you @ro-ka.

The only question left here is will @500px make it easier for us to access personal data by providing a personal token, or are we going to have to figure out a way around this like the hacky app mocked above?

jescalan avatar Sep 09 '14 14:09 jescalan

:+1:

ro-ka avatar Sep 09 '14 14:09 ro-ka

Hey just a note, I did finally end up implementing this and it works. Whoo! I added a couple of authenticated methods to the API and have them tested through. Will add the rest and complete the API spec when I have some time on my hands :grinning:

https://github.com/jenius/600px

jescalan avatar Feb 04 '15 03:02 jescalan

Great! Will take a look and maybe port it over to pure JS!

Btw. With things like 6to5 it would look nicer to you, too, right? No need for coffee anymore. ;)

ro-ka avatar Feb 04 '15 15:02 ro-ka

Maybe, would have to see! Coffee is still a lot cleaner than es6 though, in general...

jescalan avatar Feb 04 '15 15:02 jescalan