ActionController::InvalidAuthenticityToken (ActionController::InvalidAuthenticityToken): Rails 5 - ruby-on-rails

Hi I have rails 5 application which is throwing following errors
Can't verify CSRF token authenticity. ActionController::InvalidAuthenticityToken error when submitting a POST request for signin in staging environment. It's weird because form is working fine for Production and development environment. Here is the request param
{
"method":"POST",
"path":"/users/sign_in",
"format":"html",
"controller":"Users::SessionsController",
"action":"create",
"status":422,
"error":"ActionController::InvalidAuthenticityToken: ActionController::InvalidAuthenticityToken",
"duration":11.53,
"view":0.0,
"params":{
"utf8":"✓",
"authenticity_token":"LDPxQ17rH9W/AoW1Hfeyd4in1Ms7snMuys6IyFIlB6K9JoCLanfjHg6OOcqlf/HkE9pPzEuOwVz3d29iwYaJbA==",
"user":{
"email":"",
"password":"[FILTERED]"
},
"commit":"Login"
},
"#timestamp":"2018-05-23T12:08:26.463Z",
"#version":"1",
"message":"[422] POST /users/sign_in (Users::SessionsController#create)"
}

You can add this to the controller
skip_before_action :verify_authenticity_token
Of course it's not recommended to do this, but for some reason it solved my problems, since it happen on one form only on my whole application and it was safe to skip this auth.

Related

axios/rack-cors/react-rails/heroku: Internal Server Error 500 on sign out, no persistence on refresh

ERROR MSG:
Error: Request failed with status code 500
Stack trace:
[42]/</t.exports#http://crdwk.herokuapp.com/packs/bundle-ecc8ea14dbe153e50352.js:1:89311
[42]/</t.exports#http://crdwk.herokuapp.com/packs/bundle-ecc8ea14dbe153e50352.js:1:251725
[42]/</t.exports/</d[h]#http://crdwk.herokuapp.com/packs/bundle-ecc8ea14dbe153e50352.js:1:88311
Ruby version: 2.3
Rails version: 5.1
I have a server-side rendered, client-side hydrated React/Rails app (using gem 'react-rails').
I added the gem 'rack-cors' plus setup in application.rb in order for my requests to work (I'm using axios). However, signing out (a DELETE request) fails and hitting refresh erases the current user. Neither issue occurs locally/in development.
Here's the app: http://crdwk.herokuapp.com
And the repo: https://github.com/English3000/crdwk
I took a look at my Heroku logs:
Completed 500 Internal Server Error in 8ms (ActiveRecord: 0.0ms)
NoMethodError (undefined method `reset_token' for nil:NilClass):
app/controllers/application_controller.rb:29:in `sign_out'
app/controllers/api/sessions_controller.rb:3:in `destroy'
Given that hitting refresh, the current user does not persist, the issue is the current user somehow isn't getting set.
However, this is not an issue in development. Why would that be?
Looking through my project, the only difference I can find on the backend as compared with a client-side rendered one (which I literally copy & pasted the code for this project from) is this line in application_controller.rb:
skip_before_action :verify_authenticity_token
However, if I comment out this line, when I try to sign up, I get the server error
Started POST "/api/users" for 127.0.0.1 at 2018-03-05 12:16:57 -0800
Processing by Api::UsersController#create as JSON
Parameters: {"user"=>{"email"=>"", "password"=>"[FILTERED]"}}
Can't verify CSRF token authenticity.
Completed 422 Unprocessable Entity in 1ms (ActiveRecord: 0.0ms)
ActionController::InvalidAuthenticityToken - ActionController::InvalidAuthenticityToken:
This is a result of using gem 'react-rails'. (I don't get this error for my other client-side rendered project.)
There isn't an "authenticity_token" parameter.
I find these two resources: Rails security and Learnetto's how-to.
So I add these two lines of code from the second artilce to my api.js:
const csrfToken = document.querySelector("meta[name=csrf-token]").content;
axios.defaults.headers.common["X-CSRF-Token"] = csrfToken;
Now my web app works with the extra application_controller.rb line commented out. EXCEPT, I can't use the DOM to grab the csrf token for my React Native version, so I now have the same issue for mobile...

rails 4 API gives 401 unathorized response after successful log in using angular2-token package

I have a setup in which I have a rails 4 API having the gem devise_token_auth and hosted as a separate application so I have also rack-cors configured to handle cross origin requests. Using angular2-token on my front end Angular 2 applicaiton I have been able to successfully sign up and sign in as well as sign out users via my API.
The issue however, which I have encountered occurs only when the user is signed in and upon refreshing the browser I get this error in the rails API console as well as in the browser, checked in firefox as well as chrome.
Started GET "/api/v1/auth/validate_token" for 127.0.0.1 at 2017-02-06 17:42:49 +0500
Processing by DeviseTokenAuth::TokenValidationsController#validate_token as JSON
followed by
SELECT "users".* FROM "users" WHERE "users"."uid" = $1 LIMIT 1 [["uid", "abc#xyz.com"]]
Completed 401 Unauthorized in 76ms (Views: 0.2ms | ActiveRecord: 0.3ms)
My initial assumption during the configuration of this package in my Angular2 app was that it will implicitly include authentication headers in each request. However after repeatedly going through the gem's documentation I also added the headers myself when I initialize the token service in my app.component.ts file.
this._tokenService.init({
apiPath: API_PATH,
globalOptions: {
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
"access_token_name": localStorage.getItem('accessToken'),
"client_name": localStorage.getItem('client'),
"uid_name": localStorage.getItem('uid')
}
}
});
Even after that the response hasn't changed to the request and I was unable to receive these headers on the server end as well.
However after hours of inspection an idea finally came to me which was to inspect the headers m getting on the server and when I used ruby's request.header.inspect on my server end application I get the following output with the information required for validation of the token but it seems that the name of the keys of these header values are different form what the devise_token_auth expects to validate token (I went through the source of the devise_auth_token gem here.
"HTTP_ACCESS_TOKEN_NAME"=>"xxxxxxxxxxxxxxxxxx", "HTTP_EXPIRY"=>"xxxxxxxxxxxxxxxxxx", "HTTP_UID"=>"abc#xyz.com", "HTTP_CLIENT_NAME"=>"xxxxxxxxxxxxxxxxxx", "HTTP_TOKEN_TYPE"=>"Bearer"
What I believe is the user is not being set by the devise_token_auth gem based on the headers that are being passed.
After repeatedly going through the documentation of Angular2-token as well as devise_token_auth gem I am confused whether or not to manually add headers for authentication because I believe they are being passed already but with different keys.
I would just like to know if that is the case I am experiencing its been almost a full day and I cannot figure out a way to pin point the reason behind the 401 response.
Thanks a lot.
EDITED:
Moreover I am also getting nil when accessing current_user or any devise helper after successful sign in on server end.
Here are the rack-cors configuration for my api rails applicaiton as well.
application.rb
config.middleware.use Rack::Cors do
allow do
origins '*'
resource '/cors',
:headers => :any,
:methods => [:post],
:credentials => true,
:max_age => 0
resource '*',
:headers => :any,
:expose => ['access-token', 'expiry', 'token-type', 'uid', 'client'],
:methods => [:get, :post, :options, :delete, :put]
end
end
The headers I get upon inspecting are following:
HTTP_ACCESS_TOKEN
HTTP_CLIENT
HTTP_EXPIRY
HTTP_TOKEN_TYPE
HTTP_UID
These are the headers sent even if I don't mention any headers while configuring the angular2-token package.
I am confused why it lets me login in the first place and later throw an error with a 401 code and response of
{"success":false,"errors":["Invalid login credentials"]}
When I try and manually check token's validation using the following code
this._tokenService.validateToken().subscribe(
res => console.log(res),
error => console.log(error)
);
You should also pass Expiry and Token-type on requests for devise_token_auth to authenticate, something like this:
let headers = new Headers();
headers.append('Content-Type', 'application/json');
headers.append('Uid', this.uid);
headers.append('Client', this.client);
headers.append('Access-Token', this.access_token);
headers.append('Expiry', this.expiry);
headers.append('Token-Type', 'Bearer');
this.http.post('http://my-api.com/', JSON.stringify(resource), {headers: header}).subscribe((res)=>{
#Your Logic Here
});
This example is for generic HTTP requests, but you can apply that rule on your angular token plugin. ie.:
this._tokenService.init({
apiPath: API_PATH,
globalOptions: {
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
"access_token_name": localStorage.getItem('accessToken'),
"client_name": localStorage.getItem('client'),
"uid_name": localStorage.getItem('uid'),
"expiry_name": localStorage.getItem('expiry'),
"token-type_name': 'Bearer'
}
}
});
You have set custom headers name for devise_token_auth? First example works with default configuration, without _name in the end of the headers' names, you should try modifying if that is the case.
After spending a few days on this issue and going through multiple threads of related issues repeatedly posted on related topics I came across the following issue and I realized I have rails 4 and have used rails-api gem to generate my API.
After that I created a rails 5 API with --api option (without rails-api gem) and with devise_token_auth and rack-cors on my api end I was successful in sending authorized request using the angular2-token package. Along with that I was also able to send authorized http post requests with the authorization headers access-token, token-type, expiry, uid as mentioned in the devise_token_auth gem's documentation.
This might not be the exact solution or I may not have pinpointed the cause of the issue but this was what worked for me.

Rails: timeout after doing HTTP POST from controller

Rails 3.1.3, ruby 1.9.3p374
I am trying to POST from a controller (which receives data via POST from client and then does some processing first) to another controller in the app, and am getting Timeout::Error.
I have tried using Net::HTTP (long form below, also did shortcut form):
uri = URI.parse(credit_payments_url)
http = Net::HTTP.new(uri.host, uri.port)
request = Net::HTTP::Post.new(uri.request_uri)
auth_token = params[:authenticity_token]
request.set_form_data({:cc => "test", :authenticity_token => auth_token })
response = http.request(request)
And HTTParty:
auth_token = params[:authenticity_token]
HTTParty.post(credit_payments_url, :body => {:cc => "test", :authenticity_token => auth_token})
In both cases, I get the Timeout::Error, and also see this in the server output:
Started POST "/payments/credit" for 127.0.0.1 at 2013-02-19 17:39:35 -0600
Processing by PaymentsController#credit as HTML
Parameters: {"cc"=>"test", "authenticity_token"=>"px+YzdbEfC5p2i3e5yjNT4EQy4WMA9aEWY/v2tfdFhA="}
WARNING: Can't verify CSRF token authenticity
credit_payments_url is the correct url and there is a corresponding route. I've been getting the CSRF warning so I added :authenticity_token from the original request but the CSRF warning still shows up. I'm not sure if that has anything to do with the POST timing out.
I feel like there may be some basic network or configuration issue causing the POST to not work, but can't quite tell what it is. Any ideas?
First - Probably, you have just one worker, busy in this request, and therefore unable to respond the second request. Try to make the post inside a thread, or use more than one worker.
Second - Why are you posting to the app itself? Why don't you dry the code, extracting the needed code from the other action to a method, and calling it in both places?

Params variable not getting filled with JSON post data....Why?

I had this service working before, with some other fields, but right now i seem not to get it working, and am not quite getting why.
I'm posting the following json to my Rails app (with RestClient 2.4, for the test) :
{
"camp":{
"total": 100,
"number": "epw1f6e"
},
"machine":{
"serial_number": "1234567",
"token": "fONxDN"
}
}
Camp controller :
def create
if is_it_json?
logger.debug params.inspect
machine = Machine.find_by_serial_number(params[:machine][:serial_number])
...
From the logger, I get that params are : {"action"=>"create", "controller"=>"camp"}
Where is the json information??
My log error :
Started POST "/camps" for 127.0.0.1 at 2012-07-15 00:08:21 +0100
Processing by CampsController#create as JSON
WARNING: Can't verify CSRF token authenticity
{"action"=>"create", "controller"=>"camps"}
Completed 500 Internal Server Error in 2ms
NoMethodError (undefined method `[]' for nil:NilClass):
app/controllers/camps_controller.rb:24:in `create'
What might i be doing wrong?
Thank you
After a lot of reading and questioning, i just found out the solution :
The params weren't getting filled because i was missing Headers (I had the Accept, but was missing the Content-type) :
Accept: application/json
Content-type: application/json
Adding the headers solved this issue.
Can't verify CSRF token authenticity {"action"=>"create", "controller"=>"camps"}
Completed 500 Internal Server Error in 2ms
That error is thrown when an invalid (or nonexistent) CSRF token is posted with your json. The CSRF needs to be attached to the header of any posted data. For testing you can disable CSRF tokens by adding the following to your controller (for Rails 3):
protect_from_forgery :except => :create
Do not leave that in your controller when the site goes into production. CSRF tokens prevent CSRF attacks. Refer to the Ruby on Rails Security Guide for more details.
Let me know if that does the trick!

Uploadify and rails 3 authenticity tokens

I'm trying to get a file upload progress bar working in a rails 3 app using uploadify (http://www.uploadify.com) and I'm stuck at authenticity tokens. My current uploadify config looks like
<script type="text/javascript" charset="utf-8">
$(document).ready(function() {
$("#zip_input").uploadify({
'uploader': '/flash/uploadify.swf',
'script': $("#upload").attr('action'),
'scriptData': { 'format': 'json', 'authenticity_token': encodeURIComponent('<%= form_authenticity_token if protect_against_forgery? %>') },
'fileDataName': "world[zip]",
//'scriptAccess': 'always', // Incomment this, if for some reason it doesn't work
'auto': true,
'fileDesc': 'Zip files only',
'fileExt': '*.zip',
'width': 120,
'height': 24,
'cancelImg': '/images/cancel.png',
'onComplete': function(event, data) { $.getScript(location.href) }, // We assume that we can refresh the list by doing a js get on the current page
'displayData': 'speed'
});
});
</script>
But I am getting this response from rails:
Started POST "/worlds" for 127.0.0.1 at 2010-04-22 12:39:44
ActionController::InvalidAuthenticityToken (ActionController::InvalidAuthenticityToken):
Rendered /opt/local/lib/ruby/gems/1.8/gems/actionpack-3.0.0.beta3/lib/action_dispatch/middleware/templates/rescues/_trace.erb (1.0ms)
Rendered /opt/local/lib/ruby/gems/1.8/gems/actionpack-3.0.0.beta3/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (6.6ms)
Rendered /opt/local/lib/ruby/gems/1.8/gems/actionpack-3.0.0.beta3/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb within rescues/layout (12.2ms)
This appears to be because I'm not sending the authentication cookie along with the request. Does anyone know how I can get the values I should be sending there, and how I can make rails read it from HTTP POST rather than trying to find it as a cookie?
Skipping authenticity token checking is not ideal as it opens up XSS attack vectors.
Another way to make this work is described here: http://metautonomo.us/2010/07/09/uploadify-and-rails-3/
Note that you may need to double url encode things. In the example the rails 'u' is being used as well as encodeURLComponent(). Howoever, if you have a more fancy/rails3 type set up and source the session data/authenticity token from meta tags in the page header, you will need to call encodeURLComponent() twice.
This seems to be a bug with rails 3.
https://rails.lighthouseapp.com/projects/8994-ruby-on-rails/tickets/3913
This meant I had to change how I was skipping the authenticity token checking:
Changed from
protect_from_forgery :except => :upload
To
skip_before_filter :verify_authenticity_token, :only => :upload
Which seems to still work fine
well, i figured how to go around that. Is there a form on the view where you want to upload the files. If u do just use jquery to get the value of the hidden authenticity token and pass it into the scriptData var.
var token = ($('input[name=authenticity_token]').val());
scriptData : {'authenticity_token':token}
Hope this works for you.

Resources