thebigk's avatar
Level 13

Accepting Requests from Widget Embedded on Other Website

My app requires ability to create widgets that can be embedded on other websites. I've created a simple iframe that accepts user name and email and then sends POST request to my application. The application then registers the user. The user is redirected to some other page.

Here's the iframe:

<div class="aspect-w-16 aspect-h-9 my-6">
<iframe class="w-full h-full" src="https://wl.test/first-waitlist/widget"allowfullscreen></iframe>
</div>

When I click 'submit' button on the embedded widget, I get a 419 | Page Expired error, which indicates an issue with the csrf token. I'd like to know how to address this issue.

0 likes
4 replies
LaryAI's avatar
Level 58

The 419 | Page Expired error you're encountering is indeed related to CSRF (Cross-Site Request Forgery) protection, which is a security measure to prevent unauthorized commands from being transmitted from a user that the web application trusts. When you're embedding an iframe that submits a POST request to your application, the CSRF token from the parent page (the page where the iframe is embedded) is not present or doesn't match the one expected by your application.

To solve this issue, you have a couple of options:

  1. Disable CSRF Protection for Specific Routes: You can disable CSRF protection for the routes that are used by the widget. This is not recommended for sensitive actions, as it opens up a potential security vulnerability, but it might be acceptable for something like a simple user registration.

    In a Laravel application, you can do this by modifying the VerifyCsrfToken middleware:

    namespace App\Http\Middleware;
    
    use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware;
    
    class VerifyCsrfToken extends Middleware
    {
        /**
         * The URIs that should be excluded from CSRF verification.
         *
         * @var array
         */
        protected $except = [
            'first-waitlist/widget/submit', // Add your route here
        ];
    }
    
  2. CSRF Token in the Iframe: If you want to keep CSRF protection enabled, you need to ensure that the iframe has access to a valid CSRF token when submitting the form. You can pass the CSRF token to the iframe and include it as a hidden input in the form.

    In your Laravel view that generates the iframe content, you can do something like this:

    <form method="POST" action="https://wl.test/first-waitlist/widget/submit">
        @csrf <!-- This blade directive generates a hidden input with the CSRF token -->
        <!-- Your form fields here -->
        <input type="text" name="name">
        <input type="email" name="email">
        <button type="submit">Submit</button>
    </form>
    

    Make sure that the form action points to the correct URL that handles the form submission in your application.

  3. API Token Authentication: If you're building a more complex system and you want to ensure better security, consider using API tokens for authentication. This way, you can authenticate the request from the iframe without relying on CSRF tokens. You would need to set up an API route and use token-based authentication (such as Laravel Sanctum or Passport) to handle the request securely.

    This approach is more complex and requires a proper understanding of API authentication, but it's a more secure and scalable solution for handling requests from external sources.

Choose the approach that best fits your application's security requirements and the complexity you're willing to manage. If you're going for the first or second option, make sure to understand the security implications of disabling CSRF protection or managing CSRF tokens in iframes.

thebigk's avatar
Level 13

Above approach does not work. I have already tried with including @csrf field in the embedded widget. It still throws 419 error.

Apparently, this is because the request is originating from an unknown domain. I can ask for the domain information from the user. But then, how can I whitelist the domain?

Also, I'm open to exploring better, easier options to achieve the desired result. Would really appreciate a response.

thebigk's avatar
Level 13

Updated: I added the route to VerifyCsrfToken middleware in $except array. The solution worked. I wish to know if there are any security concerns I should be aware of.

Would appreciate a response.

bvfi-dev's avatar

@thebigk Sorry for a very late reply, but I stumbled onto this issue as Im also looking for solutions for a 419 error regarding the csrf tokens. I would definitely recommend NOT putting your routes in the $except array. You should put there payment gateway routes, like for stripe or paypal, or similar API requests. For a solution, I would try this. Set the secure to true, if you have valid SSL certificates and your app is hosted on a domain.

1 like

Please or to participate in this conversation.