These forums have been archived and are now read-only.

The new forums are live and can be found at https://forums.eveonline.com/

EVE Technology Lab

 
  • Topic is locked indefinitely.
 

CREST oauth problem

Author
Ariea Thellare
EVE University
Ivy League
#1 - 2016-10-24 03:18:34 UTC
Hello,

I am trying to develop an android app with the new CREST api.
To do that I need to authenticate via oauth. So the first part works, ie. I get a proper "authorization code" returned to my app after login in. And with this I need to make a post request to get access/refresh token.

This is the code for the post request


        String url = "https://login.eveonline.com/oauth/token";
        String charset = "UTF-8";
        String grant_type = "authorization_code";
        String enc_auth = Base64.encodeToString("9d7dcbb0380f450ea0d2b435b60f4c15:ssEAFgv5PfEs29bluxs9N3milKgC7j6saILCtMPw".getBytes(), Base64.DEFAULT);

        String query = null;
        try {
            query = String.format("grant_type=%s&code=%s",
                    URLEncoder.encode(grant_type, charset),
                    URLEncoder.encode(code[0], charset));
        }

         connection = new URL(url).openConnection();
        connection.setDoOutput(true); // Triggers POST.
        connection.setRequestProperty( "Authorization", enc_auth);
        connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=" + charset);

        try (OutputStream output = connection.getOutputStream()) {
            output.write(query.getBytes());
        }

NOTE: I removed a bunch of unnecessary code to make it easier to read.


So I base64 encode the Authorization, I set the Content type and i wrote the grant type and the access code to the body.

But as an answer i get "HTTP/1.1 400 Bad Request"
and I have no Idea why.
Althalus Stenory
Flying Blacksmiths
#2 - 2016-10-24 08:09:08 UTC
I believe it's because you are missing the keyword "Basic" here :
connection.setRequestProperty( "Authorization", enc_auth);

as it should be:
connection.setRequestProperty( "Authorization", "Basic " + enc_auth);


http://eveonline-third-party-documentation.readthedocs.io/en/latest/sso/authentication.html#verify-the-authorization-code

EsiPy - Python 2.7 / 3.3+ Swagger Client based on pyswagger for ESI

Ariea Thellare
EVE University
Ivy League
#3 - 2016-10-24 13:47:59 UTC
Ok, I added the bacis keyword but I am still getting the "Bad Request"
Cat Evergreen
Doomheim
#4 - 2016-10-24 14:44:49 UTC
Try using HttpsURLConnection instead of an HttpURLConnection. The login server does not answer on regular http for security reasons.
Ariea Thellare
EVE University
Ivy League
#5 - 2016-10-24 15:19:37 UTC  |  Edited by: Ariea Thellare
ok this is my new code but i get the same "Bad reqest error"


            HttpsURLConnection connection = null;
            try {
                connection = (HttpsURLConnection) new URL(url).openConnection();
            } catch (IOException e) {
                e.printStackTrace();
            }

            connection.setRequestMethod("POST");
            connection.setDoOutput(true); // Triggers POST.
            connection.setRequestProperty( "Authorization","Basic " + enc_auth);
            connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=" + charset);
            connection.setRequestProperty("Host", "login.eveonline.com");

            try (OutputStream output = connection.getOutputStream()) {
                output.write(query.getBytes());
            } catch (IOException e) {
                e.printStackTrace();
            }

Note: the part where all variables are defined stays the same
Blacksmoke16
Imperial Academy
#6 - 2016-10-24 15:51:03 UTC
Just an FYI if 9d7dcbb0380f450ea0d2b435b60f4c15:ssEAFgv5PfEs29bluxs9N3milKgC7j6saILCtMPw is really your clientID and secret key you should not use that in your actual app. Those should never be visible.
Ariea Thellare
EVE University
Ivy League
#7 - 2016-10-24 16:12:05 UTC
I know they are just example things :D
Ariea Thellare
EVE University
Ivy League
#8 - 2016-10-26 04:27:52 UTC
I am still stuck and would appreciate any help.
Althalus Stenory
Flying Blacksmiths
#9 - 2016-10-26 07:06:24 UTC
Ariea Thellare wrote:
I am still stuck and would appreciate any help.

You should have a JSON body in your response from CREST telling you why you had an HTTP 400.

For example :
{
"error": "invalid_client",
"error_description": "Unknown client"
}


Thiis might help you on solving your issue I think

EsiPy - Python 2.7 / 3.3+ Swagger Client based on pyswagger for ESI

Cat Evergreen
Doomheim
#10 - 2016-10-26 10:22:42 UTC  |  Edited by: Cat Evergreen
I don't have a Java environment available right now, so I can't run some tests on your code on my own. What I would do is to make sure that the encodings work as intended by comparing the final url (and all parts) to the examples in the documentation. (Run your code with their client_id and secret of course.)

You also asked for a code example on how I managed to slay the SSO dragon. I used JavaScript in Node.js but still here is the function:


app.get('/crest/', function(req, res) {
    var sess = req.session;
    if (sess.auth.state != req.query.state) {
        //...
    } else {
        var loginUrl = URL.parse(CREDENTIALS.login_url);
        var options = {
            method : 'POST',
            host : loginUrl.host,
            path : O_TOKEN_PATH,
            headers : {
                'Host' : loginUrl.host,
                'Authorization' : 'Basic ' + UTIL.btoa(CREDENTIALS.client_id + ':' + CREDENTIALS.client_secret),
                'Content-Type': 'application/json'
            }
        };
        var callback = function(response) {
            //...
        };
        var request = HTTPS.request(options, callback);
        var body = {
            'grant_type' : 'authorization_code',
            'code' : req.query.code
        };
        request.write(JSON.stringify(body));
        request.end();
    }
});

Main difference is, that I used the JSON body instead of x-www-form-urlencoded

Edit: Which Base64 class are you using? (And which Java version?)
Ariea Thellare
EVE University
Ivy League
#11 - 2016-10-28 05:53:28 UTC
i am using
JRE: 1.8.0_76-release-b03 amd64 according to android studio

and i am using the base64 encoding thing from android.util.Base64.

but with the base64 encoding i am 80 % sure it's right, because check it with the example given in the doc and it got the correct output.

Cat Evergreen
Doomheim
#12 - 2016-10-28 07:32:36 UTC
Only other idea I got for you at the moment, is to try the JSON format, if you have a JSON writer in your Java setup.
Ariea Thellare
EVE University
Ivy League
#13 - 2016-10-29 15:56:56 UTC  |  Edited by: Ariea Thellare
Ok, I finally found the answer.
As it turns out the Base64 encoding did something weird.
Instead of Base64.DEFAULT I had to use Base64.NO_WRAP

so the line would be

String enc_auth = Base64.encodeToString("9d7dcbb0380f450ea0d2b435b60f4c15:ssEAFgv5PfEs29bluxs9N3milKgC7j6saILCtMPw".getBytes(), Base64.NO_WRAP);


Otherwise it would add random linebreaks in the encoded string.


Just one more questin:
the "expires_in":1200 from the answer,
is that in second or minutes or hours or days or what?
Nick Zander
Caldari Provisions
Caldari State
#14 - 2016-10-29 21:40:20 UTC
Ariea Thellare wrote:


Just one more questin:
the "expires_in":1200 from the answer,
is that in second or minutes or hours or days or what?


RFC 6749 (OAuth 2.0) says:

expires_in
RECOMMENDED. The lifetime in seconds of the access token. For
example, the value "3600" denotes that the access token will
expire in one hour from the time the response was generated.
If omitted, the authorization server SHOULD provide the
expiration time via other means or document the default value.