2

I am trying to send a POST request to an sign in endpoint. I keep getting HTTP error 422 'Unprocessable Entity'. How do I get past this error?

Here are some examples of commands I have tried:

curl -v -X POST -F 'user[email]=test@email.com' -F 'user[password]=password' https://example.com/users/sign_in

curl -v -H 'Accept: text/html,application/xhtml+xml,application/xml;' -H 'Content-Type: application/x-www-form-urlencoded' -d 'utf8=%E2%9C%93&authenticity_token=123456789123456789123456789123123123456456456789789789789VX4KgMBr6zgGjo123456789123456789njQ%3D%3D&user%5Bemail%5D=test%40sign_in.com&user%5Bpassword%5D=password&commit=Sign+in' https://example.com/users/sign_in

I want the request to send back a 200 or 301/302 response status, but instead I get this:

* upload completely sent off: 208 out of 208 bytes
< HTTP/1.1 422 Unprocessable Entity
< Server: nginx/1.12.2
< Date: Fri, 08 Feb 2019 12:08:07 GMT
< Content-Type: text/html; charset=utf-8
< Content-Length: 0
< Connection: keep-alive
< X-Request-Id: 6ceb5baa-7740-448a-8105-6f67dd203fbb
< X-Runtime: 0.021676

Any help or advice is appreciated. Thanks

Update

I see now that the Rails log from such a request renders an InvalidAuthenticityToken Error

Started POST "/users/sign_in" for 127.0.0.1 at 2019-02-08 14:30:50 +0000
Processing by Users::SessionsController#create as */*
Can't verify CSRF token authenticity.
Completed 422 Unprocessable Entity in 1ms (ActiveRecord: 0.0ms)

ActionController::InvalidAuthenticityToken - ActionController::InvalidAuthenticityToken:

Any ideas on how to get past this? All I am seeking to do is ensure that routes which require authentication are returning 200/301/302 responses.

ethaning
  • 386
  • 4
  • 12
  • 1
    Can you show the rails' log when you do that request? – arieljuod Feb 08 '19 at 14:08
  • @arieljuod Thanks for the reply - I have updated the post with an excerpt from the rails log. Any ideas on how to post to curl with a valid authenticity token? – ethaning Feb 08 '19 at 14:39
  • 1
    The token is generated at the moment by rails (you'll need to do two requests, one to the actual login page, parse it and get the token to do the curl request). You can disable the token verification too if you know what you are doing, check this https://stackoverflow.com/questions/1177863/how-do-i-ignore-the-authenticity-token-for-specific-actions-in-rails#1177883 and read about the token here https://guides.rubyonrails.org/security.html#csrf-countermeasures – arieljuod Feb 08 '19 at 14:48

1 Answers1

1

There are at least two ways to do this:

Option 1: get and use a token

One way to solve this is to actually capture and utilize the authenticity token that rails generates. To do this, we also need to capture and then send back cookies, to allow ourselves to utilize a session that is associated with the generated token. I was able to get this to work with something like the following incantation.

(Note: I'm assuming a scaffold has been created for "thing", creating a things_controller.rb, etc. Adapt this to your use case as needed.)

step 1: capture the token:

token=$(curl -s -c myjar https://example.com/things/new | \
     sed -n 's/.*name="authenticity_token" value="\([^"]*\)".*/\1/p')

step 2: use it in the request:

cat myjar | \
  curl -b - -s \
        -H "Accept: application/json" \
        -H "Content-type: application/json" \
        -d '{"thing": {"field1":"Test","field2":"Testing"},
             "authenticity_token":"'"$token"'"}' \
        https://example.com/things | jq .

This works, without any changes to the application. When I run that, I see a pretty rendering of the JSON from a successful object creation as output.

(Ignore the | jq . if you just want the raw JSON data, perhaps to send it along to something else.)

However, there is another option. With a small tweak to the controller, one can achieve a bit easier curl usage (no cookiejar required, fewer parameters, only a single curl command, and no strange nested quotes), as follows:


Option 2: disable token checking:

Another way to get past this is to disable the validity_token checking for the create action in any controller(s) you wish to allow this sort of thing from. For example, given my example of a scaffold called "thing", one might update the app/controllers/things_controller.rb file to add the second line shown here:

class ThingsController < ApplicationController                     # EXISTING LINE
  skip_before_action :verify_authenticity_token, only: [:create]   # NEW LINE
  before_action :set_img, only: [:show, :edit, :update, :destroy]  # EXISTING LINE
  # ... additional content elided ...

And then rails simply won't do that check, so one can do a one-step requset something like:

curl -s \
  -H "Accept: application/json" \
  -H "Content-type: application/json" \
  -d '{"thing": {"field1":"Test","field2":"Testing"}}' \
  http://example.com/things | jq .

Again, I see the jq-generated output, this time without having to capture cookies or a token or anything.

lindes
  • 9,854
  • 3
  • 33
  • 45
  • As a side note: thanks to @epigene and [this answer](https://stackoverflow.com/a/34431717/313756) to a similar question for inspiration on how to do Option 2. – lindes Mar 17 '21 at 08:34