Dhaval Pandya
Dhaval Pandya

Reputation: 1617

x-csrf-token validation fails on HttpPost

I have to post xml payload to an ODATA service which requires Authentication and x-csrf-token.

I have two AsyncTasks. In First one has URLConnection object and fetches x-csrf-token with code below:

 URL obj = new URL(Util.ODATA_URL + "SO_BEATPSet");
                    URLConnection conn = obj.openConnection();
                    conn.setRequestProperty("Authorization", "Basic " + authStringEnc);
                    conn.addRequestProperty("x-csrf-token", "fetch");

......
......

 String server = conn.getHeaderField("x-csrf-token");

Now, in Second AsyncTask executed right after the first one finishes succesfully, i encounter 403 error. It bascially says that my x-csrf-token validation has failed.

I ran a simple looping test, where i ran the first AsyncTask three times, and i got three different tokens. That is where i think the problem is. When in Second AsyncTask I use HttpPost, the server is expecting a different token other than an already fetched one.

Is there any way that i can fetch and pass the X-csrf-token in the same call? My Second AsyncTask is like below:

HttpPost postRequest = new HttpPost(url);

String credentials = UUSERNAME + ":" + PASSWORD;
                    String base64EncodedCredentials = Base64.encodeToString(credentials.getBytes(), Base64.NO_WRAP);

postRequest.addHeader("Authorization", "Basic " + base64EncodedCredentials);
postRequest.addHeader("x-csrf-token", X_CSRF_TOKEN); //   JHc4mG8siXrDtMSx0eD9wQ==

StringEntity entity = new StringEntity(XMLBuilders.BeatXMLBuilder());
entity.setContentType(new BasicHeader("Content-Type",
                            "application/atom+xml"));
postRequest.setEntity(entity);

Upvotes: 1

Views: 8760

Answers (3)

Leebeth Anacona
Leebeth Anacona

Reputation: 61

I encountered the same error when making two requests in Java. Specifically, when I made the GET token request, I received a different token each time. Consequently, when I passed the fresh new token to my POST call, it returned a 403 Forbidden error with the message 'CSRF token validation failed'.

The solution is to initialize the HttpClient like so:

HttpClient client = HttpClient.newBuilder().cookieHandler(new CookieManager()).build();

Upvotes: 0

Dhaval Pandya
Dhaval Pandya

Reputation: 1617

I was eventually able to get the successful POST result. However, the solution seems a bit dirty to me. But, it did sort out my problem for now.

I put the Code like below in doInBackground() method of AsyncTask

 HttpClient httpclient = new DefaultHttpClient();
 HttpPost postRequest = new HttpPost(url);

 String credentials = USERNAME + ":" +PASSWORD;
 String base64EncodedCredentials = Base64.encodeToString(credentials.getBytes(), Base64.NO_WRAP);

  /**---------------------------------------------------------------------------------- **/
  /** THIS CODE BELOW CALLS THE SERVER FOR THE TOKEN AND PASSES THE VALUE TO THE SUBSEQUENT POSTREQUEST CALL.
      BY DOING THIS, THE SERVER IS NOT CALLED AGAIN BEFORE POSTREQUEST, AND USER GETS THE LATEST TOKEN **/
                        {
                            HttpGet httpget = new HttpGet(url);
                            httpget.setHeader("Authorization", "Basic " + base64EncodedCredentials);
                            httpget.setHeader("x-csrf-token", "fetch");

                            System.out.println("request:-------------------");
                            System.out.println(httpget.getRequestLine());
                            Header headers[] = httpget.getAllHeaders();
                            for (Header h : headers) {
                                System.out.println(h.getName() + "---:---- " + h.getValue());
                            }

                            HttpResponse res = httpclient.execute(httpget);                           
                            System.out.println("response:-------------------");
                            System.out.println(res.getStatusLine());

                            headers = res.getAllHeaders();
                            for (Header h : headers) {
                                System.out.println(h.getName() + "---:---- " + h.getValue());
                                if (h.getName().equals("x-csrf-token")) {
                                    X_CSRF_TOKEN = h.getValue();
                                }
                            }
                        }
  /**--------------------------------------------------------------------- **/


    // The main POST REQUEST
     postRequest.addHeader("Authorization", "Basic " + base64EncodedCredentials);
     postRequest.setHeader("x-csrf-token", X_CSRF_TOKEN); //   PASSING THE TOKEN GOTTEN FROM THE CODE ABOVE


     StringEntity entity = new StringEntity(myString);
     entity.setContentType(new BasicHeader("Content-Type",
                                "application/atom+xml"));
     postRequest.setEntity(entity);


     HttpResponse response = httpclient.execute(postRequest);
     Log.d("Http Post Response:", response.toString());

     String result = EntityUtils.toString(response.getEntity());
     Log.d("Http Response:", result);

     int responseCode = response.getStatusLine().getStatusCode();
     Log.d("Http Response: ", "Response code " + responseCode);

As I explain in the Code comments as well, the Code makes another call to the server while HttpPost has already made one and gets the latest token, which in turn is passed to the subsequent POST request.

Upvotes: 2

silentsudo
silentsudo

Reputation: 6963

Have you tried encoding or decoding x-csrf-token?

String tokenEncoded = URLEncoder.encode("xcsrftoken", "UTF-8")

String tokenDecoded = URLDecoder.decode("xcsrftoken", "UTF-8");

I once had similar issues using encoding did the trick for me.

Upvotes: 0

Related Questions