How OAuth 2.0 works in real life:
I was driving by Olaf's bakery on my way to work when I saw the most delicious donut in the window -- I mean, the thing was dripping chocolatey goodness. So I went inside and demanded "I must have that donut!". He said "sure that will be $30."
Yeah I know, $30 for one donut! It must be delicious! I reached for my wallet when suddenly I heard the chef yell "NO! No donut for you". I asked: why? He said he only accepts bank transfers.
Seriously? Yep, he was serious. I almost walked away right there, but then the donut called out to me: "Eat me, I'm delicious...". Who am I to disobey orders from a donut? I said ok.
He handed me a note with his name on it (the chef, not the donut): "Tell them Olaf sent you". His name was already on the note, so I don't know what the point of saying that was, but ok.
I drove an hour and a half to my bank. I handed the note to the teller; I told her Olaf sent me. She gave me one of those looks, the kind that says, "I can read".
She took my note, asked for my id, asked me how much money was ok to give him. I told her $30 dollars. She did some scribbling and handed me another note. This one had a bunch of numbers on it, I guessed that's how they keep track of the notes.
At that point I'm starving. I rushed out of there, an hour and a half later I was back, standing in front of Olaf with my note extended. He took it, looked it over and said, "I'll be back".
I thought he was getting my donut, but after 30 minutes I started to get suspicious. So I asked the guy behind the counter "Where's Olaf?". He said "He went to get money". "What do you mean?". "He take note to bank".
Huh... so Olaf took the note that the bank gave me and went back to the bank to get money out of my account. Since he had the note the bank gave me, the bank knew he was the guy I was talking about, and because I spoke with the bank they knew to only give him $30.
It must have taken me a long time to figure that out because by the time I looked up, Olaf was standing in front of me finally handing me my donut. Before I left I had to ask, "Olaf, did you always sell donuts this way?". "No, I used to do it different."
Huh. As I was walking back to my car my phone rang. I didn't bother answering, it was probably my job calling to fire me, my boss is such a ***. Besides, I was caught up thinking about the process I just went through.
I mean think about it: I was able to let Olaf take $30 out of my bank account without having to give him my account information. And I didn't have to worry that he would take out too much money because I already told the bank he was only allowed to take $30. And the bank knew he was the right guy because he had the note they gave me to give to Olaf.
Ok, sure I would rather hand him $30 from my pocket. But now that he had that note I could just tell the bank to let him take $30 every week, then I could just show up at the bakery and I didn't have to go to the bank anymore. I could even order the donut by phone if I wanted to.
Of course I'd never do that -- that donut was disgusting.
I wonder if this approach has broader applications. He mentioned this was his second approach, I could call it Olaf 2.0. Anyway I better get home, I gotta start looking for a new job. But not before I get one of those strawberry shakes from that new place across town, I need something to wash away the taste of that donut.
I'm facing similar issues, and am also relatively new to OAuth. I've implemented "Resource Owner Password Credentials" in our API for our official mobile app to use -- the web flows just seem like they'd be so horrible to use on a mobile platform, and once the user installs an app and trusts that it's our official app, they should feel comfortable typing username/password directly into the app.
The problem is, as you point out, there is no way for my API server to securely verify the client_id of the app. If I include a client_secret in the app code/package, then it's exposed to anyone who installs the app, so requiring a client_secret wouldn't make the process any more secure. So basically, any other app can impersonate my app by copying the client_id.
Just to direct answers at each of your points:
I keep re-reading different drafts of the spec to see if anything's changed, and am focused mostly on the Resource Owner Password Credentials section, but I think you're correct on these. Client Credentials(4) I think could also be used by an in-house or third-party service that might need access to more than just "public" information, like maybe you have analytics or something that need to get information across all users.
I don't think you can keep anything confidential on the client.
Nothing stops someone else from using your client id. This is my issue too. Once your code leaves the server and is either installed as an app or is running as Javascript in a browser, you can't assume anything is secret.
For our website, we had a similar issue to what you describe with the Client Credentials flow. What I ended up doing is moving the authentication to the server side. The user can authenticate using our web app, but the OAuth token to our API is stored on the server side, and associated with the user's web session. All API requests that the Javascript code makes are actually AJAX calls to the web server. So the browser isn't directly authenticated with the API, but instead has an authenticated web session.
It seems like your use-case for Client Credentials is different, in that you're talking about third-party apps, and are only serving public data through this method. I think your concerns are valid (anyone can steal and use anyone else's API key), but if you only require a free registration to get an API key, I don't see why anyone would really want to steal one.
You could monitor/analyze the usage of each API key to try to detect abuse, at which point you could invalidate one API key and give the legitimate user a new one. This might be the best option, but it's in no way secure.
You could also use a Refresh Token-like scheme for this if you wanted to lock it up a bit tighter, although I don't know how much you would really gain. If you expired the Javascript-exposed api tokens once a day and required the third-party to do some sort of server-side refresh using a (secret) refresh token, then stolen api tokens would never be good for more than a day. Might encourage potential token thieves to just register instead. But sort of a pain for everyone else, so not sure if this is worth it.
Best Answer
Theres an example of how to get started on the asp.net website, specifically here:
http://www.asp.net/aspnet/overview/owin-and-katana/owin-oauth-20-authorization-server
I quote:
Obviously you will need to go ahead and verify the actual client id / secret exist perhaps in a local database sometwhere before you go ahead and set the context to validated.
In terms of deciding which flow to use, you need to ask yourself, if the application is requesting access to your APIs on behalf of an actual user, then you need to use Resource Owner, however if the application itself needs access then Client Credentials is the way to go.
Generally speaking though, most implementations use Authorisation Code Flow, so if you can form a security stand point, get the users redirected to a page you host to take their credentials, opposed to sending them over the wire via Resource Owner Flow.