I'm new to rails and having a tough time with the concept of protect_from_forgery, from what i understand this method uses :verify_authenticity_token to protect a route. The route I'm using this on is an API route; something like this:
class ApiController < ActionController::API
protect_from_forgery with: :null, only: %i[execute]
before_action :validate_csrf_token, only: %i[execute]
def execute
# action here
end
private
def validate_csrf_token
return true unless request.post?
token = request.headers['X-CSRF-Token']
if token.blank? || !valid_authenticity_token?(token, nil)
render json: { error: 'Invalid CSRF token' }, status: :unprocessable_entity
end
end
end
I also have another controller which i use to get my token from my rails app
class CsrfTokenController < ApplicationController
skip_before_action :verify_authenticity_token
def index
render json: { csrf_token: form_authenticity_token }
end
end
which i send to my ApiController. the first issue i encounter is this error
HTTP Origin header (http://localhost:3020) didn't match request.base_url (http://localhost:3000)
secondly when i perform post requests the token i sent is invalid
error: "Invalid CSRF token"
i can confirm that the token request is the one being sent back when i print the variable.
Is there something i'm missing here, or am i understanding :null_session all wrong?
Edit:
Updated due to incorrect method mentioned for protecting route
What the CSRF protection does is give you a degree of certainty that the request originated from a page rendered by you own server. That's great for classical apps and APIs that are just meant to feed your own Single Page Application with JSON. But if you're creating an API that is designed to be used cross domain and also possibly by server based clients the Rails CSRF protection is irrelevant and actually completely opposed to those requirements.
method uses form_authenticity_token to protect a route
No not really. The way this works is that a unique token is rendered into the HTML of the page (forms and the meta tag) and the same token is stored in the session.
Since the session is stored in an encrypted cookie we have a reasonable degree of certainty that it hasn't be tampered with.
When the user then submits the form your controller checks for a token in the requests body or the X-CSRF-Token
header and raises an exception unless it matches the value provided by the session cookie. This token should only be valid for a single request cycle.
Since cookies are single domain by default you shouldn't actually expect this to work when you're sending a request from a different origin.
See: