Receiving 400 bad request while invoking the token api

Hi Team

Can someone guide me on this?

I am trying to invoke the https://oauth2.sky.blackbaud.com/token API to request for a token. I have set the required body params which is grant_type (hardcoded to “authorizationcode”), code (exact code received from the Query param), redirect_uri (the uri specified in my application).

For the header param, i have set the Content-Type as "application/x-www-form-urlencoded". For the authorization param, i am sending the word “Basic ” (with a space after it) and an 64 encoded value which i derived from applicationid : application_secret.

All my input request looks fine to me. But i get a 400 Bad Request as response. (Pasting the error below, apologies for the junk String pasted). Has anyone faced such error? Please advise.

HttpResponseProxy{HTTP/1.1 400 Bad Request [Cache-Control: no-cache, Pragma: no-cache, Content-Type: application/json;charset=UTF-8, Expires: -1, Strict-Transport-Security: max-age=31536000;includeSubDomains, Content-Security-Policy: default-src 'self';script-src 'self' 'unsafe-inline' 'unsafe-eval' https://cdn.mxpnl.com/libs/mixpanel-2-latest.min.js https://ajax.googleapis.com/ajax/libs/jquery/3.2.0/jquery.min.js;style-src 'self' 'unsafe-inline' fonts.googleapis.com https://signin.blackbaud.com;img-src 'self' data: https://*.blob.core.windows.net/bbdevappassets/;font-src 'self' fonts.gstatic.com https://sky.blackbaudcdn.net;connect-src 'self' https://signin.blackbaud.com/api/accountmanagement/user/jwt https://*.mixpanel.com, X-Frame-Options: DENY, Date: Thu, 11 Nov 2021 21:43:58 GMT, Content-Length: 101, Set-Cookie: visid_incap_855125=TrB5ajn5T1Co7BDlHqPEZ56OjWEAAAAAQUIPAAAAAADP6cYiEGlB2pE65YzZ+CuZ; expires=Fri, 11 Nov 2022 09:46:21 GMT; HttpOnly; path=/; Domain=.sky.blackbaud.com, Set-Cookie: incap_ses_7224_855125=xu1JQ+YVPze4ejIJ+81AZJ6OjWEAAAAAoN/snm1HJ1iYIodaefgRng==; path=/; Domain=.sky.blackbaud.com, X-CDN: Imperva, X-Iinfo: 10-139097324-139097628 NNNN CT(5 14 0) RT(1636667036966 1795) q(0 0 0 0) r(0 0) U5] ResponseEntityProxy{[Content-Type: application/json;charset=UTF-8,Content-Length: 101,Chunked: false]}}

Comments

  • Below are few more inputs. The actual error thrown is: response: {"error":"invalid_request","error_description":"The required grant_type parameter was not provided."}.

    Please look at the sample code that I wrote. I have clearly included the grant_type as per API specification.

    import java.util.Base64;

    import com.sun.jersey.api.client.Client;

    import com.sun.jersey.api.client.ClientResponse;

    import com.sun.jersey.api.client.WebResource;

    public class Sample1 {

    public static void main(String a[]){

    String url = "https://oauth2.sky.blackbaud.com/token";

    String name = “<application id>”;

    String password = "application secrect”

    String authString = name + ":" + password;

    String authStringEnc = Base64.getEncoder().encodeToString( authString.getBytes());

    System.out.println("Base64 encoded auth string: " + authStringEnc);

    Client restClient = Client.create();

    WebResource webResource = restClient.resource(url);

    String input = "{\\"grant_type\\":\\"authorization_code\\",\\"code\\":\\"79fc5fb7de6541138d8ac93e4290c994\\",\\"redirect_uri\\":\\"https://localhost/ccall/blackbaudAuth\\"}";

    ClientResponse resp = webResource.accept("application/json")

    .header("Authorization", "Basic " + authStringEnc)

    .post(ClientResponse.class, input);

    if(resp.getStatus() != 200){

    System.err.println("Unable to connect to the server");

    }

    String output = resp.getEntity(String.class);

    System.out.println("response: "+output);

    }

    }

  • Hi Shahul

    Please take a close look at the request example in step 4 of this tutorial.

    Your setting

    String input = “{\\"grant_type\\":\\"authorization_code\\",………}”

    Which is a JSON object. Instead your input string should be FormURLEncoded, like the example.

    String input = “grant_type=authorization_code&……...”

  • Chris Rodgers
    Chris Rodgers Blackbaud Employee
    Ninth Anniversary Kudos 3 Name Dropper Participant

    Hey Shahul,

    +1 what Amanda wrote.

    I also don't see the `Content-Type` header (application/x-www-form-urlencoded) in your request.

    I don't work in Java much, so here's a snippet I pulled from Postman based on authorization code exchanges I've performed. I haven't tested this, and it's using the OkHttp Client unlike your code, but it may clue you into what you need to change:

    import java.io.*;
    import okhttp3.*;
    public class main {
    public static void main(String []args) throws IOException{
    OkHttpClient client = new OkHttpClient().newBuilder()
    .build();
    MediaType mediaType = MediaType.parse("application/x-www-form-urlencoded");
    RequestBody body = RequestBody.create(mediaType, "redirect_uri=https://localhost/ccall/blackbaudAuth&code=79fc5fb7de6541138d8ac93e4290c994&grant_type=authorization_code");
    Request request = new Request.Builder()
    .url("https://oauth2.sky.blackbaud.com/token")
    .method("POST", body)
    .addHeader("Authorization", "Basic **authStringEnc**")
    .addHeader("Content-Type", "application/x-www-form-urlencoded")
    .build();
    Response response = client.newCall(request).execute();
    System.out.println(response.body().string());
    }
    }

  • Thanks Chris/Amanda

    The suggestions worked. You were right. The format of the request body that was sending was incorrect. The correct format is pasted below. After correcting it, it worked. Thanks for the help.

    String inputStr = "grant_type=authorization_code"
    + "&code=" + code
    + "&client_id="+ name
    + "&client_secret=" + password
    + "&redirect_uri=" + "https://localhost/ccall/blackbaudAuth";

    ClientResponse resp = webResource.accept("application/json")
    .header("Authorization", "Basic " + authStringEnc)
    .header("content-type", "application/x-www-form-urlencoded")
    .post(ClientResponse.class, inputStr);

  • Glad to see you were able to successfully make the request.

    Please note that you do not need (and should not) send the client id and client secret in the query string. So, that is to say that this part in your code

    + "&client_id="+ name
    + "&client_secret=" + password

    is unnecessary as part of the inputStr string. These are only needed in the Authorization header.

    The client_secret, as the name implies, is a secret and should be treated as such.

Categories