javaguyels
javaguyels

Reputation: 51

OAuth2 requesting token returns 401

I'm trying to authenticate to a site that uses OAuth2 and store the token in my session object. My web app initially checks to see if there's a token already there, and if there isn't it redirects the user to the login page on the external site, where the user logs in and gets redirected back to my app. So far, so good, this works. My app directs me to the external site (Mendeley), I log in there, and then it redirects me back to the url in my app that I expect it to.

When it redirects back to my app, I expect a code and a state parameter on the request, and I do see these, so I assume I'm on the right track (stop me if I'm wrong). So then, if I understand correctly, I'm supposed to post the code back to the Mendeley service to get my authorization token, and that's where it all blows up.

URL url = new URL("https://api-oauth2.mendeley.com/oauth/token");
HttpsURLConnection connection = (HttpsURLConnection) url
        .openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type",
    "application/x-www-form-urlencoded");

        String authString = getClientId() + ":" + "[MY CLIENT SECRET]";
        System.out.println("auth string: " + authString);
        byte[] authEncBytes = Base64.getUrlEncoder().encode(
                authString.getBytes());
        String authStringEnc = new String(authEncBytes);
        System.out.println("Base64 encoded auth string: " + authStringEnc);

        connection.addRequestProperty("Authorization", "Basic "
                + authStringEnc);

connection.setDoOutput(true);
OutputStream os = connection.getOutputStream();
OutputStreamWriter writer = new OutputStreamWriter(os);
writer.write("scope=all&grant_type=authorization_code");
writer.write("&client_id=");
writer.write(getClientId());
writer.write("&code=");
writer.write(code);
writer.write("&redirect_uri=");
writer.write(getMendeleyRedirectUrl(request));
writer.write("&client_secret=");
writer.write("[MY CLIENT SECRET]");
writer.flush();
writer.close();
int responseCode = connection.getResponseCode();
BufferedReader reader = new BufferedReader(new InputStreamReader(
        connection.getInputStream()));

The response code I get is 401. On that last line where it tries to get the inputStream from the connection it throws an exception, and that makes sense to me sense it returned a 401 and doesn't have one.

Yes, the redirect_uri is encoded. (I don't think the initial redirect to the login would work otherwise.)

My Spidey Sense tells me I'm overlooking something that should be obvious to me, but I've tried everything I could think of. Any help would be greatly appreciated.

Edit: changed how auth header is added, now getting response code 400.

Upvotes: 0

Views: 875

Answers (1)

fbiagi
fbiagi

Reputation: 826

You should check if you are creating the correct basic auth header. It should be something like this:

String user = "your app id";
String password = "your app secret";
String authValue = user + ":" + password;

Base64.Encoder encoder = Base64.getEncoder();
Bytes[] btyes = authValue.getBytes(StandardCharsets.UTF_8);

String authValueEncoded = encoder.encodeToString(bytes);

connection.addRequestProperty("Authorization",
                    "Basic "+authValueEncoded);

This values for user and password are specific for Mendeley. See step 4 of http://dev.mendeley.com/reference/topics/authorization_auth_code.html

Regarding the error 400, you might want to check the grant_type, code or redirect_uri. Remember that the code can only be used once. from the docs:

Errors due to incorrect or missing values for grant_type, code and redirect_uri result in a HTTP bad request response with a status of 400 Bad Request and a JSON format error code and message:

HTTP/1.1 400 Bad Request Content-Type: application/json Content-Length: 82

{"error":"invalid_grant","error_description":"Invalid access code"}

Missing values generate a response with an invalid_request error code. Invalid values (including previously used codes) generate a response with an invalid_grant error code. Specifying a value other than authorization_code (or refresh_token) generate a response with an unsupported_grant_type error code.

So you might wan to look inside the response body to see what's wrong.

Upvotes: 1

Related Questions