Bungie-net / api

Resources for the Bungie.net API
Other
1.22k stars 92 forks source link

[Question] Authorization Code Invalid #203

Closed ChuckTerry closed 6 years ago

ChuckTerry commented 6 years ago

I can not seem to get an Authorization Token back from the code parameter. I keep getting an "AuthorizationCodeInvalid"error. I was originally working in PHP, but decided to throw together some quick javascript to make troubleshooting easier. I have tried several different changes to the code, and I've looked into several of the OAuth pages on both Bungie.net and Github.

bnet image 1

bnet image 2

I'm not much of a programmer, however, any help with this would be greatly appreciated.

ArkahnX commented 6 years ago

Try sending a "POST" request with the content in the following format: "client_id={CLIENT_ID}&grant_type=authorization_code&code={authCode}"

It is expecting a url style string instead of a JSON string

Edit: you will also be wanting to use the official OAuth method of authentication, a good community guide can be found here and here

ChuckTerry commented 6 years ago

Woah... That time I failed a CORS check lol. Do you happen to know if "*" is acceptable on BNet as the Origin Header, or does that factor into the return code as well?

Edit: Thank you for the links, I'll take a look into them right now.

Edit 2: I will continue looking into this tomorrow, though I think I see my issues. It also didn't help that my quick javascript throw together hit the Authorize endpoint lol. I'll get to it as soon as I have time where this can be closed quickly.

iBotPeaches commented 6 years ago

You have to be specific with origin header. * is not going to fly then proceed with ArkanX comment.

ChuckTerry commented 6 years ago

Yes, I had it specified as "https://zebadee.cc" That's why the CORS error caught me off guard. But at the same time it was probably because I was hitting the Authorize endpoint instead of the token endpoint. In PHP I had been using the GetTokenFromCode endpoint (I think that's the one, I currently don't have access to my laptop laptop to confirm), which started throwing invalid json errors at me, followed by invalid authorization code.

I took a read over those 2 articles and did have another question. One of them said to set an Authorization header with content:

Basic {base64encode(client-id:CLIENTSECRET)}

I'm probably just overthinking the whole thing. But am I encoding "client-id:CLIENTSECRET", just the client secret, do the braces go around it, etc?

The bad thing is that I want this final project to be largely PHP, with JavaScript handling any changes by the user. But I'm much much more comfortable with JavaScript, so I'm trying to start there to get a working demo, then port my code. The downside of this is not being able to make a live demo for fear of revealing the client secret. Which is hindering my troubleshooting.

I do greatly appreciate the help though.

azazael13 commented 6 years ago

The header when you are to that point will be an encoded "client-id:secret" eg: client id 1234, client secret qwerty12345, your header becomes Basic MTIzNDpxd2VydHkxMjM0NQ==

ChuckTerry commented 6 years ago
function httpPost() {

  var clientSecret = "My client secret"
  var clientId = "21910"
  var authHeader = "Basic " + btoa(clientId + ":" + clientSecret);
  var xhr = new XMLHttpRequest();

  xhr.onreadystatechange = readyStateChange;
  xhr.open("POST", "https://www.bungie.net/Platform/App/OAuth/Token/", true);
  xhr.setRequestHeader("X-API-Key","05dcc6c93fbd44bab9b93f1302d45188");
  xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
  xhr.setRequestHeader("Authorization", authHeader);

  xhr.send("grant_type=authorization_code&code=44cd903adb23212081b2e065fae39e38");

  function readyStateChange() {

    if (xhr.readyState==4) {
      if (xhr.status==200) {
        console.log(xhr.responseText);
      }
      else if (xhr.status==400) {
        console.error("Bad Request (400) Response: " + xhr.responseText);
      }
      else if (xhr.status==401) {
        console.error("Unauthorized (401) Response: " + xhr.responseText);
      }
      else {
        console.error("There was a Problem: " + xhr.responseText);
      }
    }

  }

}

httpPost();

Alright, so what I ended up having to do is putting "*" on the Origin Header at Bungie.net. For some reason I could not get Bungie to let me use any combination of my domain name (Including combinations with www and trailing slash). This could be because I don't have an SSL certificate for www . Either way, there's the code that worked, and I greatly appreciate all the help from y'all. I am unsure of Bungie's conventions on closing tickets. Therefor, I'm simply going to comment without closing. Thanks again everyone :)

Tetron-bng commented 6 years ago

If you view the error message Bungie.net returns when the origin header does not match, it includes exact origin you should use to ensure success.

ChuckTerry commented 6 years ago

@Tetron-bng so it turns out I can get it to work in PHP with the origin header set properly. However, the exact same code in Javascript (Chrome V8) continues to throw CORS, redirect, or preflight errors. Which changes based on slashes, www, and directories. In Bungie's errors I've been getting the same origin I am using, precisely as it shows in both the browser and in the request.

Once I get Apache set back up (and verify I don't have weird redirects on my end), I'm going to try adding an SSL certificate for "www" and see if that changes anything. I will update this issue when I figure it out, I expect that to be within 3 days.

If I don't get this figured out I'm going to proceed by leaving my origin header set to "*" and using my web server as a simple proxy to handle authentication... I'm much more versed in Javascript anyway. As long as I enforce same origin policy I don't see any additional security issues. Worst case scenario someone gets an Access Token for their own account.

ckhicks commented 6 years ago

I've been working on this one for a while now - I believe that (historically) browser based apps have issues due to the way XHR is handled from the client, not to mention dealing with the various return headers, tokens, etc.

Here's another thread where I talked about a few options: https://github.com/Bungie-net/api/issues/71#issuecomment-329556540

Right now I'm working on a simple app that might assist folks like us who want to plug their credentials into a web service and get right to building. My theory so far has been something much like the Auth0 solution I tried in that other thread, but built on something like AWS Lambda in more of a data-in-data-out functional flow.

At the risk of a thread hijack - it's been hard to find fellow browser devs to weigh in - does any of that sound like it would be useful for getting these types of apps up and running?

I've been using the wildcard origin for my tests as well, by the way. Seems like the best way to remove constraints from the auth flow when running entirely on the client.

Tetron-bng commented 6 years ago

I can't think of a reason you would need a web proxy to get this working. Such a solution will likely represent a security vulnerability. I am happy to help you troubleshoot if you can share the details of the issues you are facing.

ckhicks commented 6 years ago

Oh I wasn't meaning a proxy - just an external handler for the OAuth handshake to avoid the hassle of OAuth in browser apps.

Tetron-bng commented 6 years ago

How will you secure this external handler?

vpzed commented 6 years ago

It would be nice if the community would publish some Bungie Oauth code in various languages so each dev didn't have to reinvent the wheel.

From what I can see at this point most people are reinventing the wheel on almost everything for each app. For D2 we've got a few libraries/packages that have started helping with things like API query wrappers, but decoding the response data is still left as an exercise. How many different people have written "reinvent the wheel" code to display armor and/or weapon perks, or display the weekly activity information like Nightfall and Flashpoint for example.

If there were reference implementations of things like Bungie Oath for people to either use directly or at least model, it would make a lot of people's projects simpler. There are packages/libraries that implement many other Oath systems like Facebook and Google so it isn't a new idea.

ckhicks commented 6 years ago

Agreed. And that may be a better option vs a little service, but it's chasing that same desire to get folks up and running. Here's the flow I was considering:

@Tetron-bng Do you/your team look at something like this as a security hole, or would something like this be permissible? You guys are being really excellent to help us with all this so I don't want to duplicate efforts or cause any headaches. This was my thought process as a tool for devs who want to get up and running. Much like Destiny Plumbing helps with Manifest data, I'm seeing a lot of folks get hung up on the OAuth process and would like to assist if I can.

vpzed commented 6 years ago

You mentioned you're using JS. Have you been following thetraveler package for D2? It recently implemented Oauth but I haven't tried it yet.

ckhicks commented 6 years ago

I've seen it but not tried it either - I'm trying to find a way to not have to embed my client secret in the app somewhere if I can avoid it.

vpzed commented 6 years ago

Ahh, I keep forgetting about the Javascript client side stuff. I'm still working on the back-end for my app and haven't gotten to that side of the work yet.

But that's all part of what I'm talking about. As much as I've been playing with the Destiny API in the last couple months I still don't fully understand how to get it working securely with various setups to be able to decide how I'd like to implement.

Tetron-bng commented 6 years ago

@ckhicks Your approach replaces the client secret with the custom key. So the developer still ends up putting a secret in their app. What has been gained?

ckhicks commented 6 years ago

You're right, there's still one small key that exists, but at least it's not application creds from your system! The biggest gain here is not having to wrestle with OAuth in a browser app. When you look at solutions like PassportJS or similar packages on NPM, they come with highly opinionated flows that don't all play nicely with Bungie's header requirements.

My goal is finding a way to remove the headaches for devs who want to use the protected endpoints without having to wrangle tokens or use a service that doesn't come ready for the specifics of the Bungie authorization flow.

...unless you really dislike the idea, that is. XD

Tetron-bng commented 6 years ago

It does not matter what key it is. The door opens just as wide. Bungie's OAuth should work with third party OAuth clients. The X-API-Key header, for example, is not required on the OAuth endpoints, so there should be no conflict there.

ChuckTerry commented 6 years ago

Here's my issue with all of this. I don't want to use any third party libraries. If the code is GNU licensed I don't mind incorporating some of it, but I'm not even using jQuery, even though it's known for being the fastest callback based Ajax handler out there. Plus I don't care about reverse browser compatibility, at least not back to stone age. I just want minimal code that accomplishes nothing more than what It has to do.

As far as thread hijacking, go for it. Any discussion that can benefit others is absolutely welcome.

Realistically I'm not worried about security if my webserver only acts as a proxy. There are plenty of javascript exclusive apps that simply reveal the Client Secret. If someone has the knowledge to read through the code and use the Client Secret or my proxy key and state for malicious purposes, then they easily have the knowledge to simply get an API Key and code their own malicious app. Outside of that, packet interception and injection, however unlikely, is a security concern regardless of proxy, Using same origin policy on my webserver should help protect my code instead of using an authorization key. Grated this all depends on how I decide to layout my codebase.

To recreate my problem:

When I actually have some free time, I will try to post photos of the configuration, process, and errors I'm getting.

ckhicks commented 6 years ago

This is good stuff. I like the suggestion from earlier on having more examples of vanilla code folks can use in various languages. I’ve found JS to be the strangest so far as I read comments here and on Discord - if we can hammer out good methods it will go a long way to helping more people get up and running.

Tetron-bng commented 6 years ago

@tda0909 I am not sure if you are using a platform where you can run Fiddler, but a Fiddler trace showing the full interaction both with your server and Bungie.net would go a long way to helping me understand what is happening.

ChuckTerry commented 6 years ago

@Tetron-bng Fiddler actually looks like something I'd be really interested in using. However, I don't think the little raspberry pi I'm testing on actually has space for it lol. I'll talk to the server owner and see if we can remove some libraries from it. I know he's got a massive amount of cryptography stuff he's no longer using, so that's a maybe.

Beyond that I just added a www certificate, and an initial request no longer shows a trailing slash on the origin header (even with no www). Therefor give me a couple hours to get back to my laptop and I'll look into this.

EDIT: For anyone else running Apache on Raspbian, it does appear that a www certificate changes the origin header, even without changing the address itself to include www. Even though Javascript is client side, I feel like this might have something to do with my problem.

Tetron-bng commented 6 years ago

Cool thing about Fiddler, is you can run it on your PC, and set your Proxy on the Raspery PI to be the IP address of your PC, port 8888 (google how to configure fiddler to accept connections from external computers). It is such a magically useful tool, I encourage you to give it a try.

ChuckTerry commented 6 years ago

@Tetron-bng Oh, that would actually makes things much better. The more I read about Fiddler, the more I like the idea of using it, I greatly appreciate the recommendation. It's gonna take a bit though, I'm helping a friend refactor some code suffering from callback hell. It's taking a LOT more time (days) than I previously thought. Luckily it is pounding into my head the importance of promises, and the role of a dedicated event handler.

ChuckTerry commented 6 years ago

Here's another bit of info, and looking back on this I wish I would have installed fiddler first to where I could see exactly what changed. I revoked my SSL certificate and set Apache back to HTTP only. I then generated 2 certs, one for the www and one for the base domain. Instead of using an automatic setup script to configure Apache, I did everything manually this time. After I got things set up I noticed that my origin header in javascript ajax requests changed from "https://zebadee.cc/" to "https://zebadee.cc" simply dropping the trailing slash. I can now use "https://zebadee.cc" as the origin on Bnet successfully.

Now the problem is I don't know what changed. Did the www certificate fix things even though I'm not including www in my origin? Did the SSL automation script add an odd redirect that was stripping information? Did I have some other kind of redirect that I didn't know about? And even if it was one of those things, how did it effect client side script?

I'm happy I solved my problem, but at the same time, I pretty much managed to do so without being able to contribute anything helpful to this issue. I'm just explaining what worked to where maybe someone can find it useful in the future.

Tetron-bng commented 6 years ago

To my knowledge, the certificate has no bearing on how the origin header is composed. It is strictly a function of the URL where the JavaScript was downloaded that makes the Ajax request. The origin header is typically the scheme (https) the host (zebadee.cc) and port (implied 443 for https). So it should look like https://zebadee.cc commonly without the trailing slash since the trailing slash is really the first part of the URL path which is not part of the origin. But that is up to the browser implementation.

ckhicks commented 6 years ago

This is all good continued info - I’m trying to compile a list for JS implementations and this thread is helping a lot. Keep it coming!

ChuckTerry commented 6 years ago

I didn't think any of the server side stuff should have effected it either. When I get back to the house I'll check and see if chrome updated without my knowledge. Maybe one of my developer extensions was messing with something. At least, if that's the case, Ill have logs for what changed :)

ChuckTerry commented 6 years ago

Found it, and it was completely my fault. I have a bad habit of throwing together quick and dirty chrome extensions to speed up some common tasks. A couple years ago I made one that acted as a "semi"-dynamic cache buster for use on Wikia (I know purge exists, this was for another bot related issue). Chrome updated to version 62 and, in turn, disabled that extension.

If I re-enable that extension, it breaks my Bnet request, and it is that trailing slash that causes the problem. Beforehand, I had a trailing slash on Bungie because it showed up on my request and I assumed it's what I needed. But it was just some poor coding on my behalf in the past. Also explains why previously PHP worked but JavaScipt did not :)

Tetron-bng commented 6 years ago

Glad you figure it out!

ckhicks commented 6 years ago

Ha, well at least you found it! Any thoughts on where we should archive some code examples for JS devs who won’t find this thread? I’m convinced that browser apps will only grow in number so we’re money ahead if we can document these different approaches somewhere.

vpzed commented 6 years ago

Are you on the Destiny API Discussion Discord server? I'm VictoryPapaZulu there and I've started a preliminary Wiki collecting Destiny2 information. I've got a list of D2 projects on the Wiki and I'm accepting articles from people as well. Since we can't message each other on GitHub you can contact me there, or if you'd prefer something else please let me know.

ChuckTerry commented 6 years ago

How about here, on the Github Wiki? I know it's not currently user editable. But since most of the dev discussion and questions have migrated from the Bnet group forum to here, it might be a place to pop up some native code examples.