diff --git a/vaadin-portlet-integration-tests/tests-generic/src/main/java/com/vaadin/flow/portal/streamresource/StreamResourceContent.java b/vaadin-portlet-integration-tests/tests-generic/src/main/java/com/vaadin/flow/portal/streamresource/StreamResourceContent.java
new file mode 100644
index 00000000..3d383547
--- /dev/null
+++ b/vaadin-portlet-integration-tests/tests-generic/src/main/java/com/vaadin/flow/portal/streamresource/StreamResourceContent.java
@@ -0,0 +1,23 @@
+package com.vaadin.flow.portal.streamresource;
+
+import java.io.ByteArrayInputStream;
+
+import com.vaadin.flow.component.html.Anchor;
+import com.vaadin.flow.component.orderedlayout.VerticalLayout;
+import com.vaadin.flow.server.StreamResource;
+
+public class StreamResourceContent extends VerticalLayout {
+
+    static final String FILENAME = "export.xlsx";
+
+    public StreamResourceContent() {
+        StreamResource downloadResource = new StreamResource(FILENAME,
+                () -> new ByteArrayInputStream(new byte[0]));
+        downloadResource.setContentType("application/xls");
+        downloadResource.setHeader("Content-Disposition",
+                "attachment;filename=export.xlsx");
+        Anchor link = new Anchor(downloadResource, "Download File");
+        link.setId("downloadLink");
+        add(link);
+    }
+}
diff --git a/vaadin-portlet-integration-tests/tests-generic/src/main/java/com/vaadin/flow/portal/streamresource/StreamResourcePortlet.java b/vaadin-portlet-integration-tests/tests-generic/src/main/java/com/vaadin/flow/portal/streamresource/StreamResourcePortlet.java
new file mode 100644
index 00000000..44262f99
--- /dev/null
+++ b/vaadin-portlet-integration-tests/tests-generic/src/main/java/com/vaadin/flow/portal/streamresource/StreamResourcePortlet.java
@@ -0,0 +1,7 @@
+package com.vaadin.flow.portal.streamresource;
+
+import com.vaadin.flow.portal.VaadinPortlet;
+
+public class StreamResourcePortlet
+        extends VaadinPortlet<StreamResourceContent> {
+}
diff --git a/vaadin-portlet-integration-tests/tests-generic/src/main/webapp/WEB-INF/portlet.xml b/vaadin-portlet-integration-tests/tests-generic/src/main/webapp/WEB-INF/portlet.xml
index d7c1791a..32b89c02 100644
--- a/vaadin-portlet-integration-tests/tests-generic/src/main/webapp/WEB-INF/portlet.xml
+++ b/vaadin-portlet-integration-tests/tests-generic/src/main/webapp/WEB-INF/portlet.xml
@@ -74,4 +74,15 @@
         </supports>
     </portlet>
 
+    <portlet>
+        <portlet-name>streamresource</portlet-name>
+        <display-name>Flow Portlet with StreamResource download</display-name>
+        <portlet-class>com.vaadin.flow.portal.streamresource.StreamResourcePortlet</portlet-class>
+        <expiration-cache>0</expiration-cache>
+        <supports>
+            <mime-type>text/html</mime-type>
+            <portlet-mode>VIEW</portlet-mode>
+        </supports>
+    </portlet>
+
 </portlet-app>
diff --git a/vaadin-portlet-integration-tests/tests-generic/src/test/java/com/vaadin/flow/portal/streamresource/StreamResourceIT.java b/vaadin-portlet-integration-tests/tests-generic/src/test/java/com/vaadin/flow/portal/streamresource/StreamResourceIT.java
new file mode 100644
index 00000000..22446fdc
--- /dev/null
+++ b/vaadin-portlet-integration-tests/tests-generic/src/test/java/com/vaadin/flow/portal/streamresource/StreamResourceIT.java
@@ -0,0 +1,68 @@
+package com.vaadin.flow.portal.streamresource;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.openqa.selenium.JavascriptExecutor;
+
+import com.vaadin.flow.component.html.testbench.AnchorElement;
+import com.vaadin.flow.portal.AbstractPlutoPortalTest;
+
+public class StreamResourceIT extends AbstractPlutoPortalTest {
+
+    public StreamResourceIT() {
+        super("tests-generic", "streamresource");
+    }
+
+    @Test
+    public void downloadStreamResource_responseHeadersAreSent() {
+        AnchorElement link = getVaadinPortletRootElement()
+                .$(AnchorElement.class).id("downloadLink");
+        String url = link.getAttribute("href");
+        getDriver().manage().timeouts().setScriptTimeout(15, TimeUnit.SECONDS);
+
+        Map<String, String> headers = downloadAndGetResponseHeaders(url);
+
+        Assert.assertEquals(
+                "attachment;filename=" + StreamResourceContent.FILENAME,
+                headers.getOrDefault("content-disposition", null));
+    }
+
+    /*
+     * Stolen from stackexchange.
+     *
+     * It's not possible to use a straight way to download the link externally
+     * since it will use another session and the link will be invalid in this
+     * session. So either this pure client side way or external download with
+     * cookies copy (which allows preserve the session) needs to be used.
+     */
+    @SuppressWarnings("unchecked")
+    public Map<String, String> downloadAndGetResponseHeaders(String url) {
+        String script = "var url = arguments[0];"
+                + "var callback = arguments[arguments.length - 1];"
+                + "var xhr = new XMLHttpRequest();"
+                + "xhr.open('GET', url, true);"
+                + "xhr.responseType = \"arraybuffer\";" +
+                // force the HTTP response, response-type header to be array
+                // buffer
+                "xhr.onload = function() {"
+                // Get the raw header string "
+                + "  var headers = xhr.getAllResponseHeaders();"
+                // Convert the header string into an array
+                // of individual headers
+                + "  var arr = headers.trim().split(/[\\r\\n]+/);"
+                // Create a map of header names to values
+                + "  var headerMap = {};" + "  arr.forEach(function (line) { "
+                + "    var parts = line.split(': '); "
+                + "    var header = parts.shift().toLowerCase(); "
+                + "    var value = parts.join(': '); "
+                + "    headerMap[header] = value;" + "  }); "
+                + "  callback(headerMap);" + "};" + "xhr.send();";
+        Object response = ((JavascriptExecutor) getDriver())
+                .executeAsyncScript(script, url);
+        return (Map<String, String>) response;
+    }
+}
diff --git a/vaadin-portlet/src/main/java/com/vaadin/flow/portal/PortletStreamResourceHandler.java b/vaadin-portlet/src/main/java/com/vaadin/flow/portal/PortletStreamResourceHandler.java
index 94747520..3c84afec 100644
--- a/vaadin-portlet/src/main/java/com/vaadin/flow/portal/PortletStreamResourceHandler.java
+++ b/vaadin-portlet/src/main/java/com/vaadin/flow/portal/PortletStreamResourceHandler.java
@@ -25,6 +25,7 @@ public void handleRequest(VaadinSession session, VaadinRequest request,
         try {
             setResponseContentType(request, response, streamResource);
             response.setCacheTime(streamResource.getCacheTime());
+            streamResource.getHeaders().forEach(response::setHeader);
             writer = streamResource.getWriter();
             if (writer == null) {
                 throw new IOException(
@@ -56,8 +57,7 @@ public void handleRequest(VaadinSession session, VaadinRequest request,
     }
 
     private void setResponseContentType(VaadinRequest request,
-                                        VaadinResponse response,
-                                        StreamResource streamResource) {
+            VaadinResponse response, StreamResource streamResource) {
         PortletContext context = ((VaadinPortletRequest) request)
                 .getPortletContext();
         try {
@@ -65,8 +65,7 @@ private void setResponseContentType(VaadinRequest request,
                     .apply(streamResource, null));
         } catch (NullPointerException e) {
             response.setContentType(Optional
-                    .ofNullable(
-                            context.getMimeType(streamResource.getName()))
+                    .ofNullable(context.getMimeType(streamResource.getName()))
                     .orElse("application/octet-stream"));
         }
     }
diff --git a/vaadin-portlet/src/test/java/com/vaadin/flow/portal/PortletStreamResourceHandlerTest.java b/vaadin-portlet/src/test/java/com/vaadin/flow/portal/PortletStreamResourceHandlerTest.java
new file mode 100644
index 00000000..99f22d09
--- /dev/null
+++ b/vaadin-portlet/src/test/java/com/vaadin/flow/portal/PortletStreamResourceHandlerTest.java
@@ -0,0 +1,70 @@
+package com.vaadin.flow.portal;
+
+import javax.portlet.MimeResponse;
+import javax.portlet.PortletRequest;
+import javax.portlet.PortletResponse;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import com.vaadin.flow.component.UI;
+import com.vaadin.flow.server.AbstractStreamResource;
+import com.vaadin.flow.server.StreamResource;
+
+import static org.junit.Assert.*;
+
+public class PortletStreamResourceHandlerTest {
+
+    private PortletStreamResourceHandler handler = new PortletStreamResourceHandler();
+    private VaadinPortletSession session;
+    private VaadinPortletService service;
+
+    @Before
+    public void init() {
+        service = Mockito.mock(VaadinPortletService.class);
+        session = new VaadinPortletSession(service) {
+            @Override
+            public boolean hasLock() {
+                return true;
+            }
+
+            @Override
+            public void lock() {
+            }
+
+            @Override
+            public void unlock() {
+            }
+
+            @Override
+            public void checkHasLock() {
+
+            }
+        };
+    }
+
+    @Test
+    public void handleRequest_shouldApplyStreamResourceHeaders()
+            throws IOException {
+        PortletRequest portletRequest = Mockito.mock(PortletRequest.class);
+        VaadinPortletRequest request = new VaadinPortletRequest(portletRequest,
+                service);
+        MimeResponse portletResponse = Mockito.mock(MimeResponse.class);
+        VaadinPortletResponse response = new VaadinPortletResponse(
+                portletResponse, service);
+
+        StreamResource resource = new StreamResource("export.xlsx",
+                () -> new ByteArrayInputStream(new byte[0]));
+        resource.setContentType("application/xls");
+        String headerName = "Content-Disposition";
+        String headerValue = "attachment;filename=export.xlsx";
+        resource.setHeader(headerName, headerValue);
+        handler.handleRequest(session, request, response, resource);
+        Mockito.verify(portletResponse, Mockito.atLeastOnce()).setProperty(headerName, headerValue);
+    }
+
+}
\ No newline at end of file