Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Question] Authorization Code Invalid #203

Closed
ChuckTerry opened this issue Oct 6, 2017 · 35 comments
Closed

[Question] Authorization Code Invalid #203

ChuckTerry opened this issue Oct 6, 2017 · 35 comments

Comments

@ChuckTerry
Copy link

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
Copy link

ArkahnX commented Oct 6, 2017

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
Copy link
Author

ChuckTerry commented Oct 6, 2017

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
Copy link

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

@ChuckTerry
Copy link
Author

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
Copy link

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
Copy link
Author

ChuckTerry commented Oct 8, 2017

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
Copy link

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
Copy link
Author

@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
Copy link

ckhicks commented Oct 18, 2017 via email

@Tetron-bng
Copy link

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
Copy link

ckhicks commented Oct 18, 2017 via email

@Tetron-bng
Copy link

How will you secure this external handler?

@vpzed
Copy link

vpzed commented Oct 18, 2017

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
Copy link

ckhicks commented Oct 18, 2017

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:

  • Dev creates an account in the handler app using Github SSO
  • Dev logs their Bungie app credentials in the secure DB, much like Auth0.com
  • Handler salts and hashes the API key and a custom phrase to create a custom key
  • Dev points their Bungie application redirect to the handler
  • Dev places a link to the OAuth URL in their app with the custom key in the "state" parameter
  • User starts the OAuth flow, is redirected to the handler, which signs/refreshes tokens on behalf of the dev after decoding and verifying the state parameter against the DB
  • Handler redirects the user back to dev with a token, who stores it somewhere within their app
  • Dev uses a similar endpoint within the handler to refresh tokens for returning users

@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
Copy link

vpzed commented Oct 18, 2017

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
Copy link

ckhicks commented Oct 18, 2017 via email

@vpzed
Copy link

vpzed commented Oct 18, 2017

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
Copy link

@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
Copy link

ckhicks commented Oct 18, 2017

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
Copy link

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
Copy link
Author

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:

  • Apache
  • SSL Cert, non wildcard, doesnt cover www
  • the above code that I said works with "*"
  • Bnet configured to confidential
  • Origin header set to "https://domain.com/"
    When doing this, my browser displays the Origin header exactly as written. My request in Chrome's Console displays the Origin header exactly as written. Bnets error response displays the Origin header exactly as written. And, finally, Bnet's app page shows the Origin header exactly as written

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

@ckhicks
Copy link

ckhicks commented Oct 19, 2017 via email

@Tetron-bng
Copy link

@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
Copy link
Author

ChuckTerry commented Oct 19, 2017

@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
Copy link

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
Copy link
Author

@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
Copy link
Author

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
Copy link

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
Copy link

ckhicks commented Oct 22, 2017 via email

@ChuckTerry
Copy link
Author

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
Copy link
Author

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
Copy link

Glad you figure it out!

@ckhicks
Copy link

ckhicks commented Oct 23, 2017 via email

@vpzed
Copy link

vpzed commented Oct 23, 2017

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
Copy link
Author

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants