fix: Widget DirectUpload CSRF error (#13447)

## Problem
Widget file uploads via ActiveStorage DirectUpload fail on production
with:

```text
ActionController::InvalidAuthenticityToken (Can't verify CSRF token authenticity.)
```

This occurs because `Api::V1::Widget::DirectUploadsController` inherits
from `ActiveStorage::DirectUploadsController` →
`ActiveStorage::BaseController`, which has protect_from_forgery with:
:exception enabled.

While CSRF works on same-origin, it fails in production because the
widget is embedded in an iframe on third-party customer sites
(cross-origin)


## Solution
Skip CSRF verification for the widget direct uploads endpoint - this is
safe because:

- Widget endpoints authenticate via website_token + X-Auth-Token
(token-based auth)
- CSRF protection is designed for session-based auth, not token-based
auth

---------

Co-authored-by: Vishnu Narayanan <iamwishnu@gmail.com>
This commit is contained in:
Mazen Khalil
2026-09-17 00:28:41 +03:00
committed by GitHub
parent eb0d524de2
commit a641b0e4fa
2 changed files with 10 additions and 1 deletions

View File

@@ -1,4 +1,5 @@
class Api::V1::Widget::DirectUploadsController < ActiveStorage::DirectUploadsController
skip_before_action :verify_authenticity_token
include WebsiteTokenHelper
before_action :set_web_widget
before_action :set_contact

View File

@@ -11,13 +11,21 @@ RSpec.describe '/api/v1/widget/direct_uploads', type: :request do
describe 'POST /api/v1/widget/direct_uploads' do
context 'when post request is made' do
around do |example|
original = ActionController::Base.allow_forgery_protection
ActionController::Base.allow_forgery_protection = true
example.run
ensure
ActionController::Base.allow_forgery_protection = original
end
before do
token
contact
payload
end
it 'creates attachment message in conversation' do
it 'creates a blob with a valid widget token and no CSRF token' do
post api_v1_widget_direct_uploads_url,
params: {
website_token: web_widget.website_token,