Close
Back

Using CORS with Vaadin

Can I use Vaadin, if my site does not run on a Java server? Let’s say you have a site, a blog or similar on a server that you have no access to, or it even has no Java capabilities, but you would still like to embed and run a Vaadin application there.

To do this you would need to run your Vaadin application on a separate Java server cluster or some popular PaaS cloud service and just  embed a Vaadin application into a DIV element  on the HTML page on different domain.

Note that, running Vaadin from another domain is different from scenario, where you optimize your Vaadin setup, and put your static files like the widget sets, JavaScript files, images and CSS files to a different server for performance reasons. While it is easy with static files, and iframe or a server-side request proxy is ok for some applications, if you just simply want to embed a whole Vaadin application into your HTML from another domain there is a showstopper:

The same-origin policy web application security model states that HTTP requests with XMLHttpRequest have been forbidden for different domains (It is actually even more strict applying to a combination of scheme, hostname, and port number).

However, there is a viable solution to put Vaadin applications on virtually any web page - regardless of domain restrictions.

Solution: Going CORS

Cross-Origin Resource Sharing (CORS) is a W3C specification that allows cross-domain communication from the browser. This is useful with Vaadin when you want to host the application on a different server than it is actually running on. And this is supported by all the modern browsers.

Now, that sounds promising. But, how do I get started with the CORS setup for my Vaadin app?

First of all, it is useful to understand how the Vaadin client-server communication flow goes. This is visualized in the following pictures for the normal setup and CORS multi-domain setup.

 

You can see that there are two types of requests from the browser to the server that we need to consider when remotely embedding a Vaadin application: The initial page request (1.) that defines the origin domain, and event requests (3.) for the Vaadin application. The resource requests (2.) are not a problem here, as they have no XMLHttpRequest logic.

For a multi-domain setup with CORS, we need to modify the HTTP headers for requests of type 3. For this, it is enough to override the Servlet class service method for these types of requests. After all, that is where all the magic happens.

Server-side additions

Here is a very simple solution for a servlet implementation. You can do this in the  same servlet class you would normally use in your Vaadin app.

As you can see the CORS approach actually uses two request types: The so called preflight OPTION-request, and the actual payload POST-requests. Effectively, this approach bypasses the same-origin security restriction, by adding CORS headers for your Vaadin application UIDL requests, and allows the Vaadin app  to communicate to a different domain than where it is actually displayed.

Of course you don’t typically want everyone to be able to embed your application on their site like this. When disabling the cross-site security model, it might allow evil apps to catch the session and exploit XSRF. So you should limit the access only to trusted origin domains.

Embedding the Vaadin application on an HTML page

Let’s get to the client-side modifications and see what you need to do there to enable remote applications.

Basically, this is the same as described in the Book of Vaadin, except that now you can use different domains in your HTML, bootstrap, service and widget set. Just remember to use full URLs instead of relative URIs.

As you can see , you need to modify the XMLHttpRequest in order for the CORS requests to go through with session id: XMLHttpRequest.withCredentials must be set to true. We can use a simple page-wide JavaScript "inherit and override"solution here, although you should that this modification affects all XMLHttpRequests on the page and might have unwanted side effects, if you have some other applications on the same page.

Now you are ready to go. Install your Vaadin application on a Java EE server like before. Create an embedding code with the right URLs and add that to any site you like.

Design your application for CORS

Now, before you go and bypass all the same-origin security in all of your Vaadin applications - just because you can - please note that there are a couple of real-world design decisions you need to make:

  • file:// protocol or scheme is not very well supported. It works in simple cases, but there are places where this scheme is handled differently by the browsers.

  • Do not mix HTTP and HTTPS as it does not work everywhere. For example Google Chrome does not support it at all.

  • Context path does not change anymore, so relying on  VaadinRequest.getContextPath() in your application logic does not make sense anymore. URI fragments can be used instead.

  • However, when navigating with URI fragments, setting and getting them might interfere with the hosting page URI fragments, and also affect the back button navigation.

  • Embedding the same application more than once to the same page works nicely, but embedding applications from different domains and versions does not, because the same bootstrap code is used.

  • JavaScript communication between the hosting page and Vaadin application  can be handled through JavaScript API. This allows publishing methods that can be called from the host page.

  • Know that CSS is not completely isolated and your application might render a bit differently. When styling the application div, the best option is to use the id selector instead of v-app classname.

  • Naturally the  Page.getCurrent() method returns the page we are running on. Remember that Vaadin applications and integration add-ons might also rely on this method for referrer and origin checks, etc.

One good practice can be to keep your “embeddable application UI” separate from the “standalone UI” - and depending on the case: have a separate servlet for these. This way the navigation and path handling can be more reliably built and CORS headers are added only where they need to be. 

Anyway, this is cool! You can have a Vaadin application embedded on any website. :)

A small example

That's all. For the sake of an example,  I used the code above to embed two interactive charts from an external Vaadin application  charts.app.fi/sami/vaadin-community-survey-june-2014  to a separate page at sami.virtuallypreinstalled.com/remote-charts/. It works nicely and feels pretty fast. 

There is a forum post for further discussion. See you there!

 

Comments
Add Comment
Excellent! I'm impressed that a simple forum post I made a while back has been turned into an article with working examples. Thanks you.

As well as a good example, I'm glad you explain the pitfalls.
Posted on 8/27/14 5:32 AM.
Very impressive Sami , thanks for sharing such an insightful article with us !!
And i have to say, the schema you draw is almost self-explaining , my question is, can you tell what tools do you use to draw such beautiful schema ?
Posted on 8/27/14 9:36 AM.
Thanks, everyone. I'm glad to hear you find it useful. There were many people commenting and helping me test this Teemu, Matti and Artur, plus others. While we found some limitations. This could potentially be a huge shift on how apps are used and built.

René, for graphics I just used nice Vaadin-colours and Keynote presentation software.
Posted on 8/28/14 7:04 AM.
There as an alternative way - use servlet Filter
https://gist.github.com/el-mot/ade1c6b31206e04184a5
Posted on 6/12/15 1:42 PM in reply to Sami Ekblad.
Please Sami, can you helpme with this issue?

Font from origin 'http://192.168.20.222:8080' has been blocked from loading by Cross-Origin Resource Sharing policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://192.168.20.222' is therefore not allowed access.

I cant view the fonts.

Thank you.
Posted on 7/22/15 6:02 PM in reply to Sami Ekblad.
That sounds like the CORS headers for font resources are missing for some reason. Are they served separately from somewhere else?
Posted on 7/23/15 9:06 AM in reply to Carlos Zaragoza.
Does not work with IE 11. Works with firefox and chrome (did not test other browsers). Seems like IE does not like 'this.withCredentials'. Any workarounds for IE? Thanks.
Posted on 7/27/15 4:50 PM.
Yes Sami, the server vaadin is in a wildfly and I consume the vaadin app in a Apache server, now are on the same IP, different port, but in the future it's gonna be a different IP.
Posted on 7/29/15 10:05 PM in reply to Sami Ekblad.
I found out that IE wants you to define a P3P headers. You can find more information here: http://stackoverflow.com/questions/389456/cookie-blocked-not-saved-in-iframe-in-internet-explorer
Posted on 8/24/15 9:07 AM in reply to Imran Ahmed.
Sami, so Vaadin cannot function without cookies in CORS setting? This blog is then incorrect and should perhaps be removed as it gives a false hope to users that CORS works with Vaadin.
Posted on 8/30/15 5:17 AM.
There are limitations on browser support, but I wouldn't say it does not work at all. Here are some more details on CORS and withCredentials support IE 10: https://msdn.microsoft.com/library/hh673569(v=vs.85).aspx#cors_xhr
Posted on 11/5/15 3:52 PM in reply to Imran Ahmed.
Hi Sami, great article!
I'm using firefox so I successfully managed GET for .css and font files.
Unfortunately I have a little issue with responsive, it doesn't work and in firebug I saw:
com.vaadin.client.extensions.ResponsiveConnector
WARNING: Can't process styles from http://.../VAADIN/themes/myapptheme/styles.css?v=7.5.8, probably because of cross domain issues: SecurityError: The operation is insecure.

Any idea? Someone solved it?
Thanks
Posted on 11/12/15 9:52 AM in reply to Sami Ekblad.
Hi,
after some searches... the issue is related to firefox security...
my work around is:
put in vaadinBootstrap.js, at the beginning in stylesheet link creation, the following
stylesheet.setAttribute('crossorigin', 'use-credentials');

I hope it help someone and save time.
Posted on 11/13/15 12:34 PM in reply to Andrea Piatti.