user1456632
user1456632

Reputation: 678

Rails 5 InvalidAuthenticityToken, but token is present

I am getting ActionController::InvalidAuthenticityToken saving a simple resource..

CSRF meta tags are present:

<meta name="csrf-token" content="Z4fDRsIqCp4cvpCw1Dp6kN7z0uPNF5otp611C80YhUg/oB+AcUy+dz2b5qKyoMMo48LdEvbF3dcBn2d0GqeR+g==" />

And the form's token field:

<input type="hidden" name="authenticity_token" value="bIMZ5cndd/CTgOwjC3quOp02WlvWdDmhdNQCyKb920HIZz2Y8vvNDlTa7d4PKaJ5pUY6QkHKYCqiHikc2rFsyQ==" />

Sessions ID is not persisting between requests, but I understand that this behaviour is intended when CSRF errors occur.

The form's code:

<%= form_for document do |f| %>
  <% if document.errors.any? %>
    <div id="error_explanation">
      <h2><%= pluralize(document.errors.count, "error") %> prohibited this document from being saved:</h2>

      <ul>
      <% document.errors.full_messages.each do |message| %>
        <li><%= message %></li>
      <% end %>
      </ul>
    </div>
  <% end %>

  <div class="actions">
    <%= f.submit %>
  </div>
<% end %>

Actions relevant in the controller:

  def new
    @document = Document.new
  end

  def create
    @document = Document.new(document_params)

    respond_to do |format|
      if @document.save
        format.html { redirect_to @document, notice: 'Document was successfully created.' }
        format.json { render :show, status: :created, location: @document }
      else
        format.html { render :new }
        format.json { render json: @document.errors, status: :unprocessable_entity }
      end
    end
  end

Not sure how to even troubleshoot this, and for obvious reasons, I'm not willing to turn off CSRF protection.

Edit: I'm going through an nginx container as a proxy, maybe my config for that is incorrect? Here is that config:

upstream backend {
    server service:3000;
}

server {
    listen 80 default_server;

    error_page 500 502 503 504 /500.html;
    error_log /dev/stdout info;
    access_log /dev/stdout;

    location / {
        proxy_pass http://backend;
    }
}

Upvotes: 2

Views: 1440

Answers (2)

Hoffmann
Hoffmann

Reputation: 53

I struggled with this issue for days until I finally stumbled on this missing line in my nginx settings:

location @puma { 
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 
    proxy_set_header Host $http_host; 
    proxy_redirect off;
    proxy_set_header X-Forwarded-Proto https;   # Needed to avoid 'WARNING: Can't verify CSRF token authenticity'
    proxy_pass http://puma; 
}

After adding the missing line "proxy_set_header X-Forwarded-Proto https;", all my CSRF token errors quit.

Upvotes: 2

user1456632
user1456632

Reputation: 678

For anyone else running into this behind an nginx proxy, this is resolved by adding proxy configuration to nginx as outlined here:

I was missing these:

proxy_set_header        X-Real_IP       $remote_addr;
proxy_set_header        X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header        X-NginX-Proxy   true;
proxy_set_header        Host            $http_host;
proxy_set_header        Upgrade         $http_upgrade;
proxy_pass_header       Set-Cookie;

Upvotes: 3

Related Questions