Blog

Embedding Java apps on websites without third-party cookies

By  
Sami Ekblad
Sami Ekblad
·
On Jul 30, 2024 4:15:56 PM
·

Can you use Vaadin if your site doesn't run on a Java server? Many websites operate on platforms that might not support Java natively. You might have a blog, a static site, or a platform-managed service, but you may still want to leverage Vaadin's powerful features for your web application.

You can host your Vaadin application on a separate Java server or a modern cloud service like AWS, Azure, Google Cloud Platform, or Fly.io. Then, embed your Vaadin application into an HTML element on the page of your primary domain, whether that is made with WordPress, Wix, or Jekyll, or even if it resides on a different domain.

You might already be familiar with Vaadin WebComponentExporter, which allows you to publish Vaadin views or whole applications as simple HTML tags and web components and embed them in your HTML like: <newsletter-subscription></newsletter-subscription>

So far, this is pretty straightforward, but when you deploy your applications in the cloud and different domains, this is what you might see in your browser console: 

This is where you need some extra configuration. The same-origin policy in web application security prevents HTTP requests made via XMLHttpRequest from being sent to different domains. This policy is strict and based on the scheme, hostname, and port number.

So, how can we integrate Vaadin applications into any web page? By enabling CORS, we can securely embed them across different domains. Let's take a look at this in more detail.

What is Cross-Origin Resource Sharing (CORS)?

Cross-Origin Resource Sharing (CORS) is a W3C specification that enables cross-domain communication from the browser. This is needed for Vaadin applications hosted on different servers from where they are embedded. 

To set up CORS for your Vaadin app, it's helpful to understand the Vaadin client-server communication flow. The diagrams below illustrate the normal setup and the CORS multi-domain setup.

 

There are two types of requests from the browser to the server: the initial request (1) that defines the origin domain and event requests (3) for the Vaadin application. Resource requests (2) are not an issue as they do not involve XMLHttpRequest logic.

For a multi-domain setup with CORS, modify the HTTP headers for type 3 requests. This can be achieved by implementing the @WebFilter class service method where these requests are handled.

Server-side headers

Here is a solution for adding CORS in your Vaadin app running Spring Boot. 

The CORS approach involves two types of requests: the preflight OPTIONS request and the actual payload GET and POST requests. This method effectively allows the app to communicate with a domain different from where it is displayed.

@WebFilter(filterName = "Vaadin CORS Filter", asyncSupported = true, urlPatterns = "/*")
public class VaadinCorsFilter extends HttpFilter {

    /* ... */

    @Override
    public void doFilter(HttpServletRequest httpRequest, HttpServletResponse httpResponse, FilterChain filterChain) throws IOException, ServletException {
        String origin = httpRequest.getHeader("Origin");

        // Allowed origin check
        if (isOriginAllowed(origin)) {
            httpResponse.setHeader("Access-Control-Allow-Origin", origin);
            httpResponse.addHeader("Access-Control-Allow-Credentials", "true");
        }

        // Preflight response headers
        if ("options".equalsIgnoreCase(httpRequest.getMethod())) {
            httpResponse.addHeader("Access-Control-Allow-Methods", "GET, POST");
            httpResponse.addHeader("Access-Control-Allow-Headers", "content-type");
            httpResponse.getWriter().flush();
            return;
        }

        filterChain.doFilter(httpRequest, httpResponse);
    }
}

Find the full source code here

And that's it; now you can run your Vaadin applications anywhere, right? Not quite.

Secure session cookie

In 2024, browser third-party cookie restrictions will get tighter, and to keep Vaadin applications running, you need to configure your session cookies correctly. In Java Servlet-based applications, like Vaadin applications, there is typically a JSESSIONID set for session tracking. 

Effectively this means you need to add two extra attributes to the session cookie to make it work: SameSite=None and Secure. As part of the 2024 third-party cookie phaseout in Chrome, there is also a new restriction to add the Partitioned attribute to make embedding applications possible. So in total your HTTP Set-Cookie header should look something like this: 

Set-Cookie: JSESSIONID=CAD...81198C; Path=/; Secure; HttpOnly; SameSite=None; Partitioned

Here is a code snippet for how to upgrade your session cookie in Spring Boot's Tomcat environment.

Embedding the Vaadin application on an HTML page

Let’s move to the easy part: the client-side code needed to add a remote Vaadin application. Here is how you 

<!DOCTYPE html>

<html lang="en">
  <head>
    <!-- Load the Vaadin web component -->
    <script type="module" src="https://your.app.domain/web-component/newsletter-subscription.js"></script>
  </head>

  <body>
    <!-- Use the web component on your page -->
    <newsletter-subscription></newsletter-subscription>
  </body>
</html>

Now you are ready to go. Install your Vaadin application on a Java server as usual, publish it using WebComponentExporter, configure HTTP headers as described here, and add it to any site you choose.

Take it into action

That's all, really. For a real-world example, I used the code above to embed a newsletter subscription form running at vaadin-cors-sample.fly.dev into a separate page, samie.github.io/vaadin-cors-sample.

For further discussion, head to the Vaadin forum. See you there!

Sami Ekblad
Sami Ekblad
Sami Ekblad is one of the original members of the Vaadin team. As a DX lead he is now working as a developer advocate, to help people the most out of Vaadin tools. You can find many add-ons and code samples to help you get started with Vaadin. Follow at – @samiekblad
Other posts by Sami Ekblad