<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Carmine Zaccagnino</title>
    <description>The latest articles on Forem by Carmine Zaccagnino (@carminezacc).</description>
    <link>https://forem.com/carminezacc</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F238249%2Fc7fbc412-9dc9-47cd-8495-a9fb223a2d50.png</url>
      <title>Forem: Carmine Zaccagnino</title>
      <link>https://forem.com/carminezacc</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/carminezacc"/>
    <language>en</language>
    <item>
      <title>Does Kubernetes support SELinux?</title>
      <dc:creator>Carmine Zaccagnino</dc:creator>
      <pubDate>Thu, 07 Jul 2022 10:39:56 +0000</pubDate>
      <link>https://forem.com/carminezacc/does-kubernetes-support-selinux-3oop</link>
      <guid>https://forem.com/carminezacc/does-kubernetes-support-selinux-3oop</guid>
      <description>&lt;p&gt;In my &lt;a href="https://carmine.dev/posts/kubernetesclusterfcos/"&gt;previous post about setting up a Kubernetes cluster using Fedora CoreOS nodes&lt;/a&gt; I mentioned the fact that SELinux should not be disabled when creating Kubernetes clusters.&lt;/p&gt;

&lt;p&gt;That is in complete contradiction to what many online tutorials&lt;sup id="fnref1"&gt;1&lt;/sup&gt;&lt;sup id="fnref2"&gt;2&lt;/sup&gt;&lt;sup id="fnref3"&gt;3&lt;/sup&gt;&lt;sup id="fnref4"&gt;4&lt;/sup&gt;&lt;sup id="fnref5"&gt;5&lt;/sup&gt; will tell you. But why is that?&lt;/p&gt;

&lt;h3&gt;
  
  
  Generic "SELinux is just a PITA" myth
&lt;/h3&gt;

&lt;p&gt;One reason is the idea, common among those who might have jumped across to RedHat-based system administration from other distributions, that SELinux breaks things and it's just easier to disable it. It isn't, really, not for servers. Maybe for a workstation that could be an acceptable compromise: you might do unpredictable things on it, so you might end up spending a lot of time troubleshooting a tool that feels like it's getting in the way of your work most of the time without much of a tangible security benefit.&lt;/p&gt;

&lt;p&gt;But servers are different: you use them to perform a job that is somewhat pre-defined: you're either running software directly on it, and you should know what that software is supposed to do with the network and the file system, or you're running containers, in which case what you're doing is still somewhat predictable, and you should regulate to the extent to which the workload is predictable.&lt;/p&gt;

&lt;h3&gt;
  
  
  The "SELinux doesn't work with K8S because kubelet doesn't support it" myth
&lt;/h3&gt;

&lt;p&gt;Another reason that originated this idea that one should disable SELinux for Kubernetes clusters is that Kubernetes specifically doesn't play nice with SELinux because the Kubernetes official kubeadm setup tutorial &lt;a href="https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/install-kubeadm/#installing-kubeadm-kubelet-and-kubectl"&gt;says so in the tab about RedHat-based distributions&lt;/a&gt; which states, talking about disabling SELinux, that&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;This is required to allow containers to access the host filesystem, which is needed by pod networks for example.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Digging deeper, one will find, however, that SELinux is being used by people in production Kubernetes clusters, and there really aren't many issues, at most what is reported is the need to set SELinux labels on a few files and directories on some setups, but other setups may not even require any additional work. You can test this yourself with the &lt;a href="https://carmine.dev/posts/kubernetesclusterfcos/"&gt;example Kubernetes setup tutorial I wrote and mentioned at the start of this post&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As &lt;a href="https://medium.com/cri-o/cri-o-has-builtin-selinux-support-6ff45b707cf0"&gt;Daniel Walsh himself wrote in a blog post&lt;/a&gt;, CRI-O integrates very well with SELinux and prevents dangerous actions like a container loading an old, unmaintained and therefore potentially vulnerable kernel module and breaking out of the isolation. Additionally, the &lt;a href="https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.24/#selinuxoptions-v1-core"&gt;Kubernetes API itself&lt;/a&gt; contains resources to specifically configure SELinux labels for containers. Doesn't sound like something they would do for a tool that "doesn't work with Kubernetes", according to some. Also, &lt;a href="https://github.com/cncf/tag-security/blob/main/security-whitepaper/v2/cloud-native-security-whitepaper.md"&gt;the CNCF security whitepaper&lt;/a&gt; mentions SELinux as a tool that can be used to provide isolation and limit privileges, which is as much as we could expect from an high-level, architecturally-minded document.&lt;/p&gt;

&lt;h3&gt;
  
  
  Kubernetes DOES work with SELinux enabled, so you shouldn't disable it, certainly not before even trying
&lt;/h3&gt;

&lt;p&gt;In conclusion, try things for yourself before giving up on a tool that could end up providing a critical security benefit. If you want to share a story about your own experience with SELinux and Kubernetes, it would be really appreciated in the comments to this post here on dev.to or directly &lt;a href="//mailto:carmine@carminezacc.com"&gt;to my email carmine@carminezacc.com&lt;/a&gt;&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;&lt;a href="https://www.matthiaspreu.com/posts/fedora-coreos-kubernetes-basic-setup/"&gt;https://www.matthiaspreu.com/posts/fedora-coreos-kubernetes-basic-setup/&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;&lt;a href="https://ostechnix.com/install-kubernetes-cluster-using-kubeadm/"&gt;https://ostechnix.com/install-kubernetes-cluster-using-kubeadm/&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn3"&gt;
&lt;p&gt;&lt;a href="https://upcloud.com/resources/tutorials/install-kubernetes-cluster-centos-8"&gt;https://upcloud.com/resources/tutorials/install-kubernetes-cluster-centos-8&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn4"&gt;
&lt;p&gt;&lt;a href="https://docs.oracle.com/en/operating-systems/oracle-linux/kubernetes/kube_ha.html#requirements-selinux-ha"&gt;https://docs.oracle.com/en/operating-systems/oracle-linux/kubernetes/kube_ha.html#requirements-selinux-ha&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn5"&gt;
&lt;p&gt;&lt;a href="https://linoxide.com/setup-kubernetes-kubeadm-centos/"&gt;https://linoxide.com/setup-kubernetes-kubeadm-centos/&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>kubernetes</category>
      <category>security</category>
      <category>linux</category>
      <category>devops</category>
    </item>
    <item>
      <title>Creating a Kubernetes Cluster with Fedora CoreOS 36</title>
      <dc:creator>Carmine Zaccagnino</dc:creator>
      <pubDate>Sat, 02 Jul 2022 08:51:07 +0000</pubDate>
      <link>https://forem.com/carminezacc/creating-a-kubernetes-cluster-with-fedora-coreos-36-j17</link>
      <guid>https://forem.com/carminezacc/creating-a-kubernetes-cluster-with-fedora-coreos-36-j17</guid>
      <description>&lt;p&gt;In this post I'm going to explain how to create a Kubernetes 1.24 cluster on Fedora CoreOS 36 nodes.&lt;/p&gt;

&lt;p&gt;I will assume that, if you're reading this, you already know that Fedora CoreOS is a great choice as a Kubernetes node OS because of both the ease of maintenance provided by RPM-OSTree and Zincati and the really easy way to automate provisioning of new nodes thanks to the use of Butane and Ignition.&lt;/p&gt;

&lt;p&gt;I believe it is necessary to write a tutorial on this because existing tutorials on this topic are somewhat outdated and, in my opinion, fail to address some aspects, even though they're really good in many ways (&lt;a href="https://www.matthiaspreu.com/posts/fedora-coreos-kubernetes-basic-setup/"&gt;the one linked here is very good in my opinion for example&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;In particular, I'm going to show a multi-node cluster that keeps the taint on the control plane and, to give an example that can be directly replicated, I'll provide scripts that aid in creating virtual machines for the nodes using &lt;code&gt;libvirt&lt;/code&gt;. You can, of course, apply just Ignition scripts and node configuration steps to your environment if that's what you're looking to get from this tutorial.&lt;/p&gt;

&lt;h2&gt;
  
  
  Preliminary considerations about container runtimes and SELinux
&lt;/h2&gt;

&lt;p&gt;The aforementioned existing tutorial on creating Kubernetes clusters with Fedora CoreOS chooses to use CRI-O instead of the preinstalled containerd runtime. I believe this choice merits some further attention, even though I agree that it's the correct choice.&lt;/p&gt;

&lt;p&gt;CRI-O's strengths are in added features, particularly the integration with SELinux (but that is disabled in that tutorial) and the fact it's the same runtime used by OpenShift, &lt;a href="https://www.researchgate.net/publication/341483813_Performance_Evaluation_of_Container_Runtimes"&gt;but it is slower than containerd, even if marginally, as the linked paper shows&lt;/a&gt;, so one could be tempted to just stick with containerd.&lt;/p&gt;

&lt;p&gt;My experience with the exact setup that will be shown in this tutorial, even if one disables SELinux by overriding &lt;code&gt;/etc/selinux/config&lt;/code&gt; in the Ignition file, is that the choice to use containerd results in a really unstable and unusable cluster, and that's why I'll be showing steps to install and enable CRI-O instead in this tutorial.&lt;/p&gt;

&lt;p&gt;I &lt;em&gt;will not&lt;/em&gt; be disabling SELinux, on the other hand. That's because, in the current state and for what I've seen, there's no need for that and I'll gladly take the increased security, even if it means having to troubleshoot the few instances in which it gets overzealous, and doing that with &lt;code&gt;setroubleshootd&lt;/code&gt; (that can be installed on Fedora CoreOS using &lt;code&gt;rpm-ostree&lt;/code&gt; as part of the &lt;code&gt;setroubleshoot&lt;/code&gt; package) it's not hard at all.&lt;/p&gt;

&lt;h1&gt;
  
  
  Creating a virtualized Kubernetes cluster using Fedora CoreOS VMs
&lt;/h1&gt;

&lt;p&gt;For the full example, we are going to create a three-node cluster with one control plane and two workers, which is the least demanding sensible (even though it misses out on HA) virtualized setup that even a mid-range laptop could run, as long as it runs a (ideally RedHat-based) Linux distribution with &lt;code&gt;podman&lt;/code&gt;, &lt;code&gt;libvirt&lt;/code&gt; and &lt;code&gt;virt-install&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Another prerequisite is an extracted qcow2 image of Fedora CoreOS, which can be downloaded as an XZ archive from &lt;a href="https://getfedora.org/en/coreos/download?tab=metal_virtualized&amp;amp;stream=stable&amp;amp;arch=x86_64"&gt;the Fedora CoreOS official website&lt;/a&gt;, or retrieved by &lt;code&gt;coreos-installer&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The steps have been tested on x86 systems with Fedora Workstation 36 and Red Hat Enterprise Linux 9 as the host operating system.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create an Ignition script
&lt;/h2&gt;

&lt;p&gt;To inizialize the VM, a JSON Ignition script is used, which can be derived from the following &lt;code&gt;fcos.bu&lt;/code&gt; YAML file using Butane:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Before doing that, generate an SSH key pair using &lt;code&gt;ssh-keygen&lt;/code&gt; or locate an existing one you'd like to use for the VMs we're about to create and replace &lt;code&gt;&amp;lt;PASTE YOUR SSH PUBLIC KEY HERE&amp;gt;&lt;/code&gt; in &lt;code&gt;fcos.bu&lt;/code&gt; with the public key content, all on one line.&lt;/p&gt;

&lt;p&gt;Use the &lt;code&gt;butane&lt;/code&gt; OCI container to generate the Ignition file by running&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
podman run --interactive --rm \
quay.io/coreos/butane:release \
--pretty --strict &amp;lt; fcos.bu &amp;gt; fcos.ign

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Take note of the path of the generated &lt;code&gt;fcos.ign&lt;/code&gt; file, and set it as the value assigned to the &lt;code&gt;IGN_CONFIG&lt;/code&gt; variable in the following file, which I'll refer to as &lt;code&gt;start_fcos.sh&lt;/code&gt; from now on:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;In that file, also change the &lt;code&gt;IMAGE&lt;/code&gt; variable to the path to the downloaded QCOW2 Fedora CoreOS image (e.g. &lt;code&gt;$HOME/Downloads/fedora-coreos-36.20220505.3.2-qemu.x86_64.qcow2&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;In three different terminals or tmux panes or windows run &lt;code&gt;./start_fcos.sh 1&lt;/code&gt;, &lt;code&gt;./start_fcos.sh 2&lt;/code&gt; and &lt;code&gt;./start_fcos.sh 3&lt;/code&gt; to create three nodes called &lt;code&gt;node1&lt;/code&gt;, &lt;code&gt;node2&lt;/code&gt; and &lt;code&gt;node3&lt;/code&gt;. The Virtual Machine Manager (&lt;code&gt;virt-manager&lt;/code&gt;) GUI tool can be used to manage these three VMs after the initial setup.&lt;/p&gt;

&lt;p&gt;Look for lines like&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
Fedora CoreOS 36.20220505.3.2
Kernel 5.17.5-300.fc36.x86_64 on an x86_64 (ttyS0)
SSH host key: SHA256:70h+0L1lAfXChOpmBH1odArSLRCMJY2v9sOM45XThyM (ECDSA)
SSH host key: SHA256:M3Tcq1tebp+uFKAXqo6kD+PWIzzz03ndwreIEhFR5IQ (ED25519)
SSH host key: SHA256:EnywjztiwTBK9nLy47wj/gaus3wgAflI11j2ckXE0QM (RSA)
enp1s0: 192.168.122.146 fe80::cc38:c8c:7c38:c0fc

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;in the three terminals and add the IP addresses to &lt;code&gt;/etc/hosts&lt;/code&gt; on the host system like in this example:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
192.168.122.146 node1
192.168.122.96 node2
192.168.122.87 node3

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;to then be able to more easily access the nodes from the host PC.&lt;/p&gt;

&lt;p&gt;Log in via SSH as the core user on the three nodes (for example in three panes in another &lt;code&gt;tmux&lt;/code&gt; window) using &lt;code&gt;ssh core@node1&lt;/code&gt;, &lt;code&gt;ssh core@node2&lt;/code&gt; and &lt;code&gt;ssh core@node3&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Set the hostname on each node to &lt;code&gt;node1&lt;/code&gt;, &lt;code&gt;node2&lt;/code&gt; and &lt;code&gt;node3&lt;/code&gt; by creating the &lt;code&gt;/etc/hostname&lt;/code&gt; file on each as root, for example like this in the first node (run the two commands one by one or it won't work):&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
sudo -i # become root
echo "node1" &amp;gt; /etc/hostname # set the hostname

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;On the first node (which will be the cluster's control plane) install CRI-O and the required tools to create and manage the cluster with:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
sudo rpm-ostree install kubelet kubeadm kubectl cri-o

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;On the other nodes, only the CRI-O runtime, kubelet and kubeadm are needed, and they can be installed with:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
sudo rpm-ostree install kubelet kubeadm cri-o

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;reboot using &lt;code&gt;sudo systemctl reboot&lt;/code&gt; to apply the hostname change and the updates (Fedora CoreOS uses OSTree which only updates system files on reboot to ensure atomic updates).&lt;/p&gt;

&lt;p&gt;After the reboot, log in to all the nodes again and start CRI-O and kubelet using&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
sudo systemctl enable --now crio kubelet

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Create a &lt;code&gt;clusterconfig.yml&lt;/code&gt; on the control plane just like the following (using &lt;code&gt;vi&lt;/code&gt; in the SSH console for example):&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;and then run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
kubeadm init ––config clusterconfig.yml

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;to initialize the cluster.&lt;/p&gt;

&lt;p&gt;After it's done, configure &lt;code&gt;kubectl&lt;/code&gt; on the control plane by running the suggested commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;~/.kube/config&lt;/code&gt; file can be copied to the host system as well to be able to run &lt;code&gt;kubectl&lt;/code&gt; commands on the host directly instead of logging in to the control plane via SSH.&lt;/p&gt;

&lt;p&gt;Set up Pod networking with &lt;code&gt;kube-router&lt;/code&gt;, which is on the simpler side of CNI plugins without missing out on important features, by running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
kubectl apply -f \
https://raw.githubusercontent.com/cloudnativelabs/kube-router/master/daemonset/kubeadm-kuberouter.yaml

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the other nodes (&lt;code&gt;node2&lt;/code&gt; and &lt;code&gt;node3&lt;/code&gt; in our example) as workers to the cluster by running on each (as root, therefore with &lt;code&gt;sudo&lt;/code&gt;) the &lt;code&gt;kubeadm join&lt;/code&gt; command shown at the end of the &lt;code&gt;kubeadm init&lt;/code&gt; output. If it was lost, you can run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
kubeadm token create –-print-join-command

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;to have kubeadm generate a new token and get a new join command.&lt;/p&gt;

&lt;p&gt;If all was done correctly, the cluster should be ready for action. Confirm this by running &lt;code&gt;kubectl get nodes&lt;/code&gt; and verifying that all three nodes are shown as &lt;em&gt;Ready&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;You can create a test deployment of three NGINX instances with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
kubectl create deployment test --image nginx --replicas 3

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and a Service to be able to access it externally (in a file called &lt;code&gt;testsvc.yml&lt;/code&gt;, for example):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
apiVersion: v1
kind: Service
metadata:
  name: testsvc
spec:
  type: NodePort
  selector:
    app: test
  ports:
    - port: 80
      nodePort: 30001

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;that can be added to the cluster with &lt;code&gt;kubectl create -f testsvc.yml&lt;/code&gt; and that allows us to test that everything works correctly by navigating to &lt;code&gt;node1:30001&lt;/code&gt; with a browser or cURL and verifying we get the NGINX welcome page.&lt;/p&gt;

&lt;h1&gt;
  
  
  Next steps
&lt;/h1&gt;

&lt;p&gt;I have a few containers and Kubernetes example files of varying complexity in a &lt;a href="https://github.com/carzacc/thesis-files"&gt;GitHub repository (github.com/carzacc/thesis-files)&lt;/a&gt;, maybe you'll find something of interest there to complement reading the official Kubernetes documentation.&lt;/p&gt;

&lt;p&gt;In particular, &lt;a href="https://github.com/carzacc/thesis-files/tree/main/3/morra"&gt;in the README for directory &lt;code&gt;3/morra&lt;/code&gt;&lt;/a&gt; I show an example deployment of a REST API that interacts with a Redis store and a MySQL cluster. For production applications, remember to use namespaces and create accounts that follow the principle of least privilege.&lt;/p&gt;

&lt;p&gt;In the past, I've been very happy to write tutorials after having a topic requested or suggested in an email. In those cases, they were Flutter tutorial ideas. The same could happen with Kubernetes as well, so &lt;a href="//mailto:carmine@carminezacc.com"&gt;feel free to write to me at carmine@carminezacc.com to ask anything&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I have a blog at &lt;a href="https://carmine.dev"&gt;carmine.dev&lt;/a&gt;, too, where you can also find &lt;a href="https://carmine.dev/posts/kubernetesclusterfcos/"&gt;this post&lt;/a&gt;!&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>devops</category>
      <category>linux</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>One year of Programming Flutter, DevTalk and a 35% discount on the book!</title>
      <dc:creator>Carmine Zaccagnino</dc:creator>
      <pubDate>Tue, 23 Feb 2021 17:18:51 +0000</pubDate>
      <link>https://forem.com/carminezacc/one-year-of-programming-flutter-devtalk-and-a-35-discount-on-the-book-3c4n</link>
      <guid>https://forem.com/carminezacc/one-year-of-programming-flutter-devtalk-and-a-35-discount-on-the-book-3c4n</guid>
      <description>&lt;p&gt;&lt;a href="https://pragprog.com/titles/czflutr/programming-flutter/"&gt;It's been a year since the Pragmatic Programmers published Programming Flutter, my Flutter book&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;There have been many people saying great things about it, and many more asking me to guide them through the Flutter journey they started by reading my book.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://carmine.dev"&gt;My blog&lt;/a&gt; and my presence on dev.to is designed to help with common things people want to do with Flutter, but if you have any question, &lt;a href="//mailto:carmine@carminezacc.com"&gt;in addition to emailing me at carmine@carminezacc.com&lt;/a&gt;, you can post about issues with the book or questions about Flutter &lt;a href="https://devtalk.com/books/programming-flutter"&gt;on its DevTalk page&lt;/a&gt;, where you can also find a 35% discount on the price of the book.&lt;/p&gt;

&lt;p&gt;I will resume publishing tutorials on dev.to and &lt;a href="https://carmine.dev"&gt;on my blog&lt;/a&gt; over the next few weeks.&lt;/p&gt;

</description>
      <category>flutter</category>
      <category>books</category>
    </item>
    <item>
      <title>The Current State of Flutter for the Web</title>
      <dc:creator>Carmine Zaccagnino</dc:creator>
      <pubDate>Tue, 17 Nov 2020 20:03:46 +0000</pubDate>
      <link>https://forem.com/carminezacc/the-current-state-of-flutter-for-the-web-20bl</link>
      <guid>https://forem.com/carminezacc/the-current-state-of-flutter-for-the-web-20bl</guid>
      <description>&lt;p&gt;Long time no see! It's been a while since I've last posted something on my blog, and that's been for several reasons, with the bottom line being that I've run out of ideas and haven't really had the time to sit down and think about great blog post ideas.&lt;/p&gt;

&lt;p&gt;I'm coming back with a post that's going to be a little shallower than usual, but that I find to be important nonetheless.&lt;/p&gt;

&lt;p&gt;If you don't follow me on Twitter, you might have missed &lt;a href="https://www.smashingmagazine.com/author/carmine-zaccagnino/"&gt;the two articles I've written for Smashing Magazine on Flutter for Web and desktop.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Those were introductions and tutorials which didn't mention the current state of Flutter for the Web much, and this post is here to give an overview of just that.&lt;/p&gt;

&lt;p&gt;It's split in two parts, each answering a question:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;How hard is it to make it work?&lt;/li&gt;
&lt;li&gt;How well does it work?&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  How hard is it to make it work?
&lt;/h1&gt;

&lt;p&gt;This section is going to overlap with the first of my Smashing Magazine articles, but just a little bit.&lt;/p&gt;

&lt;p&gt;First of all, Flutter Web development is not available on the stable channel, and this means you need to switch to the &lt;em&gt;beta&lt;/em&gt; channel. In addition to that, you need to run the&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ flutter config --enable-web
~~~

command to enable Web development, but you probably already knew all of that. Still, I can't really take anything for granted when I'm writing to the whole of the Internet, and I'm already making it hard enough to understand what I'm talking about to people who don't even know what the heck Flutter is, and if that's you I know a book you should read. Ask me about that, or maybe just take a look at [my Twitter @carminezacc](https://twitter.com/carminezacc) or [my blog at carmine.dev](https://carmine.dev).

Anyway, after you've done that the Web browser will become a device Flutter will try to use to debug and you will be able to run `flutter build web` to get a bundle delivered to the `build` folder containing what the browser needs to show your beautiful Web app to your users, in particular your Dart code will be compiled to JS and the `index.html` file will be built based on the `index.html` in the `web` directory, which is the Web equivalent of the `android` and `ios` directories: you can modify it to change the app name and favicon, for example.

One thing you might not know is that Flutter for the Web has another build target: a WASM target using Skia running on WebGL.

# How well does it work?

That build target is as experimental as it gets, and it currently causes some very severe rendering issues on some clients that means it's completely not fit for a production app that's meant to be used on devices that you don't have complete control over.

On the other hand, the Skia target is the one that will usually cause fewer issues overall with the app and will give a more predictable, mobile-like behaviour on the devices it works well on.

Just use the JS target if you need to support any device.

Talking about how well the app works, I also have to mention that the initial loading time can be quite slow, and you may find it unacceptable, so check it out with something simpler before you invest too much time into a project.

Also, `TextField`s sometimes don't get in focus again right away when clicking on them after they go out of focus.

There are some general usability tradeoffs that need to be kept in mind, especially when running the Web app on desktop devices. You won't get a scrollbar from the browser because Flutter handles scrolling itself, so you need to create a scrollbar yourself, perhaps aided by something like the [draggable_scrollbar package on Pub](https://pub.dev/packages/draggable_scrollbar).

Another one is that text isn't even selectable by default. You can use `SelectableText` instead of `Text` to fix that, but the users still won't be able to copy the text so it's not going to cut it for a blog or other text-rich websites.

An easily fixable drawback is the lack of routing. Even named routes don't really cut it if you show content from a database on different pages: everything is still passed under the hood and not through the URL. That's very easily fixable using the [fluro package](https://pub.dev/packages/fluro).

In general, you'll have to think about other differences  between mobile apps and websites, for example clicking and dragging has the same effect as tapping and dragging on a mobile device, and Flutter doesn't allow you to handle scrollwheel scrolling events differently than dragging events.

Also, if you use cookies, remember to use the `BrowserClient` and to set [the `withCredentials` option](https://pub.dev/documentation/http/latest/browser_client/BrowserClient/withCredentials.html) to `true`, otherwise they won't be stored for subsequent requests.

# Conclusion

Flutter can be used successfully to build Web apps, but it's still got a few drawbacks. It's up to you to decide whether or not it's a good fit for your next project but, whatever you decide, remember that Flutter is still in very quick development and the situation may get better at any point.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>flutter</category>
      <category>webdev</category>
      <category>dart</category>
    </item>
    <item>
      <title>Securely Storing JWTs in (Flutter) Web Apps</title>
      <dc:creator>Carmine Zaccagnino</dc:creator>
      <pubDate>Wed, 29 Apr 2020 13:50:26 +0000</pubDate>
      <link>https://forem.com/carminezacc/securely-storing-jwts-in-flutter-web-apps-2nal</link>
      <guid>https://forem.com/carminezacc/securely-storing-jwts-in-flutter-web-apps-2nal</guid>
      <description>&lt;p&gt;I recently wrote &lt;a href="https://carmine.dev/posts/jwtauth/" rel="noopener noreferrer"&gt;a post about how to implement JWT Authorization in Flutter apps&lt;/a&gt;. I only considered the use case of writing a mobile app, so I recommended the use of the &lt;code&gt;flutter_secure_storage&lt;/code&gt; package to store the tokens.&lt;/p&gt;

&lt;p&gt;As it later emerged, some people wanted to use that tutorial as a guide for Flutter Web apps. &lt;code&gt;flutter_secure_storage&lt;/code&gt; doesn't work for Web apps.&lt;/p&gt;

&lt;p&gt;This first post about this topic will simply look to address that, later I'll post a more general overview of what needs to be taken in consideration when writing cross-platform apps in Flutter, including a deeper dive into storage on the different platforms. This will be more of a hands-on tutorial like the ones I previously posted, whereas the other one will be more of an opinion/overview post that I hope will help understand the thinking that is required before trying to deploy on multiple platforms.&lt;/p&gt;

&lt;p&gt;For the sake of keeping each post focused, I'll keep this one more practical and focused on how to make that example work on the Web.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Basic, Compromising, Simple Approach
&lt;/h1&gt;

&lt;p&gt;The simple solution to that problem that will work on every platform is to use the &lt;code&gt;shared_preferences&lt;/code&gt; package, which uses &lt;code&gt;SharedPreferences&lt;/code&gt; on Android, &lt;code&gt;NSUserDefaults&lt;/code&gt; on iOS and &lt;code&gt;localStorage&lt;/code&gt; on the Web.&lt;/p&gt;

&lt;p&gt;This is actually only one half of a solution, as using &lt;code&gt;localStorage&lt;/code&gt; means that the value can be retrieved by any JS (or Dart code compiled to JS like Flutter Web code) on your page. This means you have to be extra careful with user input to avoid XSS attacks, and that comes into play especially if you have non-Flutter Web content on the same domain (which can access the same &lt;code&gt;localStorage&lt;/code&gt;), which can access the same data.&lt;/p&gt;

&lt;p&gt;Also, you need to keep in mind that the user can actually very easily access the token through JavaScript, so if their end gets compromised in any way that token can be easily read.&lt;/p&gt;

&lt;p&gt;This should already give you an idea of the kind of issues you might have to deal with when writing cross-platform apps. Also, especially &lt;code&gt;NSUserDefaults&lt;/code&gt; on iOS is not supposed to be used for sensitive information (nor is &lt;code&gt;SharedPreferences&lt;/code&gt; actually), so you should use &lt;code&gt;flutter_secure_storage&lt;/code&gt; on those platforms anyway, and at that point you can just use &lt;code&gt;dart:html&lt;/code&gt; directly for the Web part and skip having &lt;code&gt;shared_preferences&lt;/code&gt; as a dependency entirely.&lt;/p&gt;

&lt;h1&gt;
  
  
  The Better Approach
&lt;/h1&gt;

&lt;p&gt;&lt;code&gt;flutter_secure_storage&lt;/code&gt; on mobile should be your first and only choice. It uses the proper Keychain API on iOS and it encrypts the data, stores the encrypted data in &lt;code&gt;SharedPreferences&lt;/code&gt; and the cryptographic key is stored in the Android KeyStore, which is a safe approach.&lt;/p&gt;

&lt;p&gt;On the Web though, you need to use a Web-based solution, so you need to think about our Flutter app as if it was any old boring HTML, CSS and JavaScript website.&lt;/p&gt;

&lt;p&gt;The place where tokens are stored in Web apps are &lt;code&gt;httpOnly&lt;/code&gt; cookies, which are sent to the backend automatically along with each request, but aren't accessible by JavaScript.&lt;/p&gt;

&lt;p&gt;The issue with that is that &lt;em&gt;automatically&lt;/em&gt; part. It makes you vulnerable to CSRF, which is an attack that sends requests to your server from one of your users clients when they visit a page that isn't yours. GET requests are particularly vulnerable because a GET request query is just a link that can be clicked by your users.&lt;/p&gt;

&lt;p&gt;This can be prevented by having another token (which shouldn't be the same token you use for authorization, obviously, but it can be generated based on that) that is stored in &lt;code&gt;localStorage&lt;/code&gt; (so only your website's code can access it) and send that along with each request in a dedicated header.&lt;/p&gt;

&lt;p&gt;You still MUST NOT be vulnerable to XSS because, even though your token can't be read, an attacker can still send requests through your own page, take your CSRF token, and bypass your CSRF protection entirely, but at least the JWT isn't in their hands so they haven't permanently stolen your user's identity. Escape all user-provided data before ever doing anything with it both on the front-end if you have another website running and on the back-end when you put data in a database: many libraries to interact with databases have that feature built-in, you just need to use them properly instead of just concatenating strings. If you really have to use string concatenation because of your stack, remember to sanitize the input before doing anything with it.&lt;/p&gt;

&lt;p&gt;Now, let's get hands-on and see the code needed to make everything work!&lt;/p&gt;

&lt;h1&gt;
  
  
  Putting It In Practice
&lt;/h1&gt;

&lt;p&gt;If you're new to my posts (and there will be a few of you), you might not be aware of &lt;a href="https://carmine.dev/posts/jwtauth/" rel="noopener noreferrer"&gt;my earlier post&lt;/a&gt; about JWT authentication with Flutter and Node (which supposed you were writing a mobile app), which I'll use as a starting point, and that you therefore should at least be aware of in case something confuses you. I won't be starting from scratch here.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Node Side
&lt;/h2&gt;

&lt;p&gt;Before we can build the app, we need to get the backend API straight. Remember, I won't explain the stuff I already covered in my previous post. The starting point is this repository&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/carzacc" rel="noopener noreferrer"&gt;
        carzacc
      &lt;/a&gt; / &lt;a href="https://github.com/carzacc/jwt-tutorial-backend" rel="noopener noreferrer"&gt;
        jwt-tutorial-backend
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Backend for a blog post about User Authentication+JWT authorization with Node and Flutter
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;
.

&lt;p&gt;The code we're going to end up with is in this repository&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/carzacc" rel="noopener noreferrer"&gt;
        carzacc
      &lt;/a&gt; / &lt;a href="https://github.com/carzacc/jwt-tutorial-backend-web" rel="noopener noreferrer"&gt;
        jwt-tutorial-backend-web
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;
.

&lt;p&gt;The usual Node imports and the signup route don't require any changes:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;The login route, though, is where the &lt;em&gt;fun part&lt;/em&gt; starts (you're reading this because you find this all fun, don't you?). The way I'm going to do this is the following: I'm going to generate two tokens: an &lt;em&gt;access&lt;/em&gt; token and a an &lt;em&gt;anti-CSRF&lt;/em&gt; token, and we're going to send the first as a cookie and the second in the response body. I'm not setting the &lt;code&gt;Secure&lt;/code&gt; flag because this code isn't meant for production, but that should be set in production code given that your app would run with TLS in a production environment:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;The data route needs to get both values, one in the cookies and one as a header in order to work:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;and here is the entire &lt;code&gt;index.js&lt;/code&gt;:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;h2&gt;
  
  
  The Flutter Side
&lt;/h2&gt;

&lt;p&gt;On the Flutter side, the starting point is this repository&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/carzacc" rel="noopener noreferrer"&gt;
        carzacc
      &lt;/a&gt; / &lt;a href="https://github.com/carzacc/jwt-tutorial-flutter" rel="noopener noreferrer"&gt;
        jwt-tutorial-flutter
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      https://carmine.dev/posts/jwtauth/
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;
.

&lt;p&gt;The code we're going to end up with is in this repository&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev.to%2Fassets%2Fgithub-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/carzacc" rel="noopener noreferrer"&gt;
        carzacc
      &lt;/a&gt; / &lt;a href="https://github.com/carzacc/jwt_tutorial_flutter_web" rel="noopener noreferrer"&gt;
        jwt_tutorial_flutter_web
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;
.

&lt;p&gt;The approach is going to be the following, in order to make it as obvious as possible we're actually building a Web app: the JWT is going to be in the cookies, so it's beyond our control, whereas we're going to store the anti-CSRF token in the &lt;code&gt;localStorage&lt;/code&gt; directly using &lt;code&gt;dart:html&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This means that we are going to add to our imports &lt;code&gt;import 'dart:html' show window;&lt;/code&gt; and take out the &lt;code&gt;flutter_secure_storage&lt;/code&gt; dependency given that we are not using it:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;&lt;code&gt;MyApp&lt;/code&gt; is, as always, where we decide whether we need to show the data page or the login page. In order to change as little as possible from the original, I switched the &lt;code&gt;home&lt;/code&gt; from a &lt;code&gt;FutureBuilder&lt;/code&gt; to a &lt;code&gt;Builder&lt;/code&gt; (we don't need &lt;code&gt;Future&lt;/code&gt;s in the case of HTML &lt;code&gt;localStorage&lt;/code&gt;) and moving from calling a &lt;code&gt;jwtOrEmpty&lt;/code&gt; getter to generating our very own &lt;code&gt;csrfTokenOrEmpty&lt;/code&gt;. The rest stays the same: if it's expired, the access token has expired too, so we need the user to log in again, if we don't have one we need to show the user the login page:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;The &lt;code&gt;LoginPage&lt;/code&gt; gets changes in the callback to log in, as that needs to store the JWT to local storage too.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;window.localStorage&lt;/code&gt; can be accessed just like any &lt;code&gt;Map&lt;/code&gt; like you see in the following snippet we're going to use in the login page:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

var username = _usernameController.text;
var password = _passwordController.text;
var jwt = await attemptLogIn(username, password);
if(jwt != null) {
  window.localStorage["csrf"] = jwt;
  Navigator.push(
  context,
  MaterialPageRoute(
    builder: (context) =&amp;gt; HomePage.fromBase64(jwt)
  )
);


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;I kept the variable names as they were for maximum comparability with the previous post.&lt;/p&gt;

&lt;p&gt;here's the entire &lt;code&gt;LoginPage&lt;/code&gt;:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;The data (home) page is going to be the simplest one, as all that needs to change is the name of the header at which we send the anti-CSRF token, given that the access token is sent along with the request as a cookie automatically and the rest it taken care of by the backend:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;Here's the full &lt;code&gt;main.dart&lt;/code&gt; for that:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;In order to make that Flutter app look and behave nicer on bigger screens and browsers in general, you might want to check out &lt;a href="https://www.smashingmagazine.com/2020/04/responsive-web-desktop-development-flutter/" rel="noopener noreferrer"&gt;the tutorial on responsive and Web development with Flutter I wrote for Smashing Magazine&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Onwards: Your Next Steps
&lt;/h1&gt;

&lt;p&gt;You might have found this post useful, and perhaps you'd like to see more Flutter content from me. What you can do is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://twitter.com/carminezacc" rel="noopener noreferrer"&gt;follow me on Twitter @carminezacc&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://carmine.dev/newsletter/" rel="noopener noreferrer"&gt;subscribe to my newsletter&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;check out &lt;a href="https://carmine.dev" rel="noopener noreferrer"&gt;my blog at carmine.dev&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;check out &lt;a href="https://pragprog.com/book/czflutr/programming-flutter" rel="noopener noreferrer"&gt;my book&lt;/a&gt;, for which paperback copies are available in many places, including Amazon (when and if they deliver given the current pandemic).&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>webdev</category>
      <category>dart</category>
      <category>security</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Flutter Notifications Without Firebase</title>
      <dc:creator>Carmine Zaccagnino</dc:creator>
      <pubDate>Sat, 28 Mar 2020 14:03:15 +0000</pubDate>
      <link>https://forem.com/carminezacc/flutter-notifications-without-firebase-33d2</link>
      <guid>https://forem.com/carminezacc/flutter-notifications-without-firebase-33d2</guid>
      <description>&lt;p&gt;We are going to discuss how to display notifications using the &lt;code&gt;flutter_local_notifications&lt;/code&gt; plugin.&lt;/p&gt;

&lt;p&gt;As always with these posts, you can be sure you've got all of the basic knowledge you need by reading &lt;a href="https://pragprog.com/book/czflutr/programming-flutter"&gt;my Flutter book&lt;/a&gt;, but not all of you like that way of learning, so I'll list the topics which are considered prerequisites for this post.&lt;/p&gt;

&lt;p&gt;For the local notifications part, you need to know the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;basics of Flutter app development, including knowledge of basic Material Design widgets, but also UI composition and basic state management;&lt;/li&gt;
&lt;li&gt;asynchronous programming with &lt;code&gt;Stream&lt;/code&gt;s and listening to them (&lt;code&gt;StreamSubscription&lt;/code&gt;);&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The backend for our app will be &lt;a href="https://carmine.dev/posts/flutterwebsockets/"&gt;the one we wrote for the previous post in the series&lt;/a&gt;. The app itself will be based on that, so I highly recommend you read the last part of that post if you want to understand how we've got topics a fully working example app at the end of this post. One way or another, here's the GitHub repository with the example Flutter code:&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--566lAguM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/carzacc"&gt;
        carzacc
      &lt;/a&gt; / &lt;a href="https://github.com/carzacc/flutter_notifications_example"&gt;
        flutter_notifications_example
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Flutter app sending notifications used for a carmine.dev blog post about Flutter local notifications
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;p&gt;and, for your convenience, here's the repo for the Node.js backend code:&lt;/p&gt;


&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--566lAguM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/carzacc"&gt;
        carzacc
      &lt;/a&gt; / &lt;a href="https://github.com/carzacc/websocketsbackend"&gt;
        websocketsbackend
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Backend for a Flutter app used as example code in a carmine.dev blog post about WebSockets
    &lt;/h3&gt;
  &lt;/div&gt;
&lt;/div&gt;


&lt;h1&gt;
  
  
  The flutter_local_notifications Package
&lt;/h1&gt;

&lt;p&gt;In Flutter apps, you can show notifications to the user while the app is running using &lt;a href="https://pub.dev/packages/flutter_local_notifications"&gt;the &lt;code&gt;flutter_local_notifications&lt;/code&gt; package&lt;/a&gt;. It is fairly easy to use.&lt;/p&gt;

&lt;h2&gt;
  
  
  Initializing the Plugin
&lt;/h2&gt;

&lt;p&gt;Before being able to use the plugin, you need to initialize it. This requires two different configuration steps: Android configuration and iOS configuration. Even though this is platform-specific, this is all done in Dart code. More specifically, plugin initialization works the following way:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;FlutterLocalNotificationsPlugin notifications = FlutterLocalNotificationsPlugin();
AndroidInitializationSettings androidInit = /* ... */;
IOSInitializationSettings iOSInit = /* ... */;
var initSettings = InitializationSettings(androidInit, iOSInit);
notifications.initialize(initSettings);
~~~

Now we are going to focus on `AndroidInitializationSettings` and `IOSInitializationSettings`.

## Android Initialization Settings

Android configuration requires the creation of a drawable asset to use as the app icon displayed in the notification. To do that in Android Studio, get to the `android/app/src/main/res/drawable` directory in the left *Project* panel, right-click, and select New-&amp;gt;Vector Asset. This will guide you through the creation of a drawable vector asset.

Take note of its name because, in order to initialize the `flutter_notifications` package, you need an `AndroidInitializationSettings` object, which is created in the following way:

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;var androidInit = AndroidInitializationSettings('name_of_the_drawable');&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
## iOS Initialization Settings

The configuration for iOS is at the same time simpler and harder: there is no required argument, but there are a bunch of optional ones, which are fine to be left to default values and that you can find on the [official API reference for the package](https://pub.dev/documentation/flutter_local_notifications/latest/flutter_local_notifications/IOSInitializationSettings-class.html). By default, it will ask the user to give permission to the app to show notifications when the plugin is initialized.

This means you can get a simple {% raw %}`IOSInitializationSettings` with default settings with

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;var iOSInit = IOSInitializationSettings();&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
## Showing Notifications

The notifications can be shown with {% raw %}`plugin.show(id, title, body, NotificationDetails);`.

`title` and `body` are self-explanatory, `id` can just be set to 0.

`NotificationDetails` is constructed with ` NotificationDetails(AndroidNotificationDetails android, IOSNotificationDetails iOS) `. The required (positonal) arguments for the `AndroidNotificationDetails` constructor are `AndroidNotificationDetails(String channelId, String channelName, String channelDescription)`, whereas the `IOSNotificationDetails` constructor has no required parameters. Both take many optional named arguments, which I won't cover here (also because I can't be sure they will stay the same for long and we won't use them in this tutorial), but that you should check out on the official API reference for the plugin ([click here to see the options for iOS](https://pub.dev/documentation/flutter_local_notifications/latest/flutter_local_notifications/IOSNotificationDetails-class.html) and [here for those for Android](https://pub.dev/documentation/flutter_local_notifications/latest/flutter_local_notifications/AndroidNotificationDetails-class.html)).

The `AndroidNotificationDetails` constructor requires all of the arguments Android requires to show notifications. More specifically, Android Oreo (8.0, API level 26) and successive releases allows users to have different settings for different notification channels originating from the same app. The `channelId` can be any integer, you use the same number for notifications to be sent on the same channel and you use different numbers for different channels. `channelName` and `channelDescription` are names the user will use to differentiate your app's channels, so they should be descriptive of the purpose of each notification channel if you plan to use multiple channels (e.g. a social networking app could have a channel for follow requests, one for direct messages received, one for likes to posts, etc.).

Here's what the app-level notification settings look like:

![](https://carmine.dev/img/notificationsettingschannel.png)

and here's what the channel-specific settings look like:

![](https://carmine.dev/img/notificationsettingsapp.png)

Here's an example, where `notifications` is the `FlutterLocalNotificationsPlugin` object:

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;void showNotification(String title, String body) {&lt;br&gt;
  notifications.show(0, title, body, NotificationDetails(&lt;br&gt;
    AndroidNotificationDetails(&lt;br&gt;
      "my_app_channel_id_0",&lt;br&gt;
      "User-Visible Notification Channel Title",&lt;br&gt;
      "Useful, user-visible description of the notification channel"&lt;br&gt;
    ),&lt;br&gt;
    IOSNotificationDetails()&lt;br&gt;
  ));&lt;br&gt;
}&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
# Using It In The App

This second part of the post is going to be about using the plugin in an app, more specifically changing [the app we built in the previous post](https://www.carmine.dev/posts/flutterwebsockets/) to also display notifications to the user. If you don't want to read that but still want the code we are starting from here's the GitHub repo of the previous post's app:

{% github carzacc/websockets_flutter no-readme %}

whereas this is the one for the app we'll build in this post:

{% github carzacc/flutter_notifications_example no-readme %}

## Importing

First of all, add {% raw %}`flutter_local_notifications` to the `dependencies` in `pubspec.yaml`:

&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;

&lt;p&gt;and import it at the start of &lt;code&gt;main.dart&lt;/code&gt;. You'll  notice we are also importing the status codes for the WebSocket library, which we'll need when we close the connection to the server in the &lt;code&gt;dispose()&lt;/code&gt; method of the &lt;code&gt;State&lt;/code&gt; of the &lt;code&gt;AnnouncementPage&lt;/code&gt;:&lt;/p&gt;

&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;h2&gt;
  
  
  Summary of The Changes
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;AnnouncementPage&lt;/code&gt; becomes a &lt;code&gt;StatefulWidget&lt;/code&gt;, we don't use a &lt;code&gt;StreamBuilder&lt;/code&gt;, instead we wait for new data, change what's displayed and also show a notifications. here's the entire &lt;code&gt;AnnouncementPage&lt;/code&gt; and &lt;code&gt;AnnouncementPageState&lt;/code&gt; that we'll analyze in more detail in the next section of the post:&lt;/p&gt;

&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;

&lt;p&gt;One of the changes you need to keep in mind is that we now have a &lt;code&gt;text&lt;/code&gt; &lt;code&gt;String&lt;/code&gt; variable that we will update as we get data from the server, and that &lt;code&gt;text&lt;/code&gt; is what's going to be displayed on the user's screen.&lt;/p&gt;
&lt;h2&gt;
  
  
  Using the Plugin
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;flutter_local_notifications&lt;/code&gt; package has to be initialized. This can be done in multiple places. You could to do it in &lt;code&gt;main&lt;/code&gt; and have a global variable to be able to access the notifications plugin from anhywhere within the app without having to use &lt;code&gt;InheritedWidget&lt;/code&gt;s or the &lt;code&gt;Provider&lt;/code&gt;. In our case, though, we don't really need that, as there really is only one widget that's going to cause notifications to be displayed, which is our app's &lt;code&gt;AnnouncementPage&lt;/code&gt;. What we need to do is define a &lt;code&gt;StreamSubscription&lt;/code&gt; that listens for changes in the stream received from the &lt;code&gt;WebSocket&lt;/code&gt; and, if there are any, both updates the &lt;code&gt;AnnouncementPage&lt;/code&gt; to show the new announcement (by calling &lt;code&gt;initState&lt;/code&gt; and setting the &lt;code&gt;text&lt;/code&gt; variable) and displays a notification.&lt;/p&gt;

&lt;p&gt;All of this is done in the &lt;code&gt;initState&lt;/code&gt; method:&lt;/p&gt;

&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;h2&gt;
  
  
  The New &lt;code&gt;build&lt;/code&gt; Method
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;build&lt;/code&gt; method now simply needs to display the &lt;code&gt;text&lt;/code&gt; we already get using the &lt;code&gt;StreamSubscription&lt;/code&gt;, without requiring the use of a &lt;code&gt;StreamBuilder&lt;/code&gt;. If the connection hasn't been established yet, which would mean &lt;code&gt;text&lt;/code&gt; is still &lt;code&gt;null&lt;/code&gt;, we display a &lt;code&gt;CircularProgressIndicator&lt;/code&gt; as we did when we used a &lt;code&gt;StreamBuilder&lt;/code&gt; and we had no data yet. Given that the nickname is now defined inside the &lt;code&gt;AnnouncementPage&lt;/code&gt; &lt;code&gt;StatefulWidget&lt;/code&gt; definition, we need to access it using the &lt;code&gt;this.nickname&lt;/code&gt; syntax in the &lt;code&gt;onPressed&lt;/code&gt; callback for the &lt;code&gt;FloatingActionButton&lt;/code&gt; that sends announcements.&lt;/p&gt;

&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;h2&gt;
  
  
  The &lt;code&gt;dispose&lt;/code&gt; Method
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;dispose()&lt;/code&gt; method needs to close the &lt;code&gt;WebSocket&lt;/code&gt;, letting the server know it's being closed and freeing resources on both ends of the connection, and &lt;code&gt;cancel&lt;/code&gt;s the &lt;code&gt;StreamSubscription&lt;/code&gt; because it's not necessary anymore to listen for new announcements.&lt;/p&gt;

&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;h2&gt;
  
  
  Wrapping It Up
&lt;/h2&gt;

&lt;p&gt;That's it! The app now sends notifications when it gets new announcements (including when it's the one generating them, but for this app this is intended)!&lt;/p&gt;

&lt;p&gt;The entire &lt;code&gt;main.dart&lt;/code&gt; is going to be the following:&lt;/p&gt;

&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;h1&gt;
  
  
  Receiving Notifications in The Background
&lt;/h1&gt;

&lt;p&gt;People have complained that I focused on Firebase too much in my book, so I'm trying to compensate here on my blog by focusing on more traditional backend implementations and ways to do things.&lt;/p&gt;

&lt;p&gt;One caveat is that, for example, the only way to be able to send notifications to closed apps on both Android and iOS is to use &lt;a href="https://firebase.google.com/docs/cloud-messaging"&gt;Firebase Cloud Messaging&lt;/a&gt;, which can send notifications directly to Android devices (what used to be called Cloud to Device Messaging and then Google Cloud Messaging) and uses the Apple Push Notification Service to send notifications to iOS devices.&lt;/p&gt;
&lt;h1&gt;
  
  
  Onwards
&lt;/h1&gt;

&lt;p&gt;You can now &lt;a href="https://carmine.dev/newsletter"&gt;subscribe to my newsletter&lt;/a&gt; to get email updates about new posts and, as always you can &lt;a href="https://twitter.com/carminezacc"&gt;follow me on Twitter&lt;/a&gt; if you are active on there and want to be updated, and remember to &lt;a href="https://pragprog.com/book/czflutr/programming-flutter"&gt;check out my Flutter book&lt;/a&gt; in case you haven't yet.&lt;br&gt;
&lt;/p&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>dart</category>
      <category>android</category>
      <category>ios</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Subscribe to my newsletter!</title>
      <dc:creator>Carmine Zaccagnino</dc:creator>
      <pubDate>Tue, 17 Mar 2020 11:38:07 +0000</pubDate>
      <link>https://forem.com/carminezacc/subscribe-to-my-newsletter-p58</link>
      <guid>https://forem.com/carminezacc/subscribe-to-my-newsletter-p58</guid>
      <description>&lt;p&gt;You can subscribe to my blog's newsletter at &lt;a href="https://carmine.dev/newsletter"&gt;carmine.dev/newsletter&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;At the moment it's more a mailing list I'll use to send handcrafted emails about new posts, and at the moment I'm not even doing input validation as I can filter the emails manually when I send the email since I don't expect a huge amount of subscribers (I'd be very glad to be proven wrong, though). In case you're wondering, you can't do an SQL injection attack on that form. I'm lazy but I'm not mad, and being vulnerable to SQL injection in 2020 is a sign madness and recklessness, not ignorance.&lt;/p&gt;

&lt;p&gt;For that I've built  a little Flutter web app using Cupertino Widgets so that, when I want to show people what Flutter for the Web looks like, I also have a demo of that given that my &lt;a href="https://carminezacc.com"&gt;carminezacc.com&lt;/a&gt; Flutter home page uses Material Design widgets.&lt;/p&gt;

&lt;p&gt;Check it out at &lt;a href="https://carmine.dev/newsletter"&gt;carmine.dev/newsletter&lt;/a&gt; and subscribe if you'd love to receive emails about new Flutter tutorials I'll post! As always, &lt;a href="https://twitter.com/carminezacc"&gt;follow me on Twitter&lt;/a&gt; if you prefer to get new posts delivered to you that way.&lt;/p&gt;

</description>
      <category>dart</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Two-Way, Real-Time Communication with WebSockets in Flutter Apps (+ Node backend Implementation)</title>
      <dc:creator>Carmine Zaccagnino</dc:creator>
      <pubDate>Thu, 05 Mar 2020 18:06:03 +0000</pubDate>
      <link>https://forem.com/carminezacc/two-way-real-time-communication-with-websockets-in-flutter-apps-node-backend-implementation-3od1</link>
      <guid>https://forem.com/carminezacc/two-way-real-time-communication-with-websockets-in-flutter-apps-node-backend-implementation-3od1</guid>
      <description>&lt;p&gt;Hi everyone, in this post I'm going to show you how to use WebSockets in Flutter apps and write a Node backend to test the app.&lt;/p&gt;

&lt;p&gt;In this post we’re not going to worry about authentication/authorization, as that was the focus &lt;a href="https://carmine.dev/posts/jwtauth/"&gt;of the previous post in the series&lt;/a&gt;. As always, this is meant for people with a decent understanding of the basics of Flutter. I've &lt;a href="https://pragprog.com/book/czflutr/programming-flutter"&gt;written a book about Flutter&lt;/a&gt; that will get you up to speed reasonably quickly and with ease but, in case you really need to do this now and either don't like learning from the book or don't want to read the whole thing, here's the concepts I'm going to suppose you know how to use in order to follow this post:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;basic structure of a Flutter app (&lt;code&gt;MaterialApp&lt;/code&gt;, &lt;code&gt;Scaffold&lt;/code&gt;, &lt;code&gt;Column&lt;/code&gt;, definition of custom widgets etc.);&lt;/li&gt;
&lt;li&gt;getting input from the user using a &lt;code&gt;TextField&lt;/code&gt; and managing it with a &lt;code&gt;TextEditingController&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;basic navigation using &lt;code&gt;Navigator.push&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;asynchronous programming with &lt;code&gt;Stream&lt;/code&gt;s and the usage of the &lt;code&gt;StreamBuilder&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  WebSocket and Socket.io
&lt;/h2&gt;

&lt;p&gt;This post is about WebSockets. It won't be about Socket.IO, which might be the focus of another post. WebSocket is a protocol (just like HTTP) and there are some packages and libraries to use it directly, but a very popular alternative to doing that is using Socket.io, which is a library that may or may not use WebSocket as its communication protocol, given that it has its own real-time communication engine that is used in case there is no way to establish a WebSocket-based connection.&lt;/p&gt;

&lt;p&gt;The way Socket.io does it is rather the other way around, using its own engine to initiate the connection, &lt;em&gt;upgrading&lt;/em&gt; to WebSocket if it's possible. This is of particular importance to web developers, whose apps may run on browsers that don't support the WebSocket API, even though this is less and less of a concern as time passes. The main difference you would notice in the example in a  tutorial is that Socket.io supports server broadcasting by default, meaning you don't have to manually iterate over the connected clients to send the message to each, as that is a feature of Socket.io itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  What We're Going to Build
&lt;/h2&gt;

&lt;p&gt;A very common application for WebSockets is building a chat app. That's a very good example but, in my view, it's not a great example for a blog post, unless what one wants to teach is how to build a chat app and not how to  use WebSockets. I used the example of a chat app in my book to show how to use Firebase, but that was to show as many aspects of Flutter and Firebase as possible in one example, and it is a cool example.&lt;/p&gt;

&lt;p&gt;What I'm going to do in this post, though, is show you everything you need to know in order to build a real time app, leaving the rest to you and avoid showing how to interact with a specific database, how to build a very specific complex user interface: the example is simply going to be an app showing the latest message sent by an user as an announcement to every connected user.&lt;/p&gt;

&lt;h2&gt;
  
  
  WebSockets in Flutter
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;web_socket_channel&lt;/code&gt; Dart WebSocket package is Google-developed and very easy to use. That's what we're going to use in this post.&lt;/p&gt;

&lt;h3&gt;
  
  
  Opening a Connection
&lt;/h3&gt;

&lt;p&gt;A connection can be opened by creating an object of class &lt;code&gt;WebSocketChannel&lt;/code&gt;, and you can connect to a WebSocket server by using the &lt;code&gt;WebSocketChannel.connect&lt;/code&gt; contructor: &lt;code&gt;channel = WebSocketChannel.connect(URI);&lt;/code&gt; where &lt;code&gt;URI&lt;/code&gt; is an &lt;code&gt;Uri&lt;/code&gt;, that you could get from a &lt;code&gt;String&lt;/code&gt; containing an URL (something like &lt;code&gt;ws://myserver.mydomain.com:3000&lt;/code&gt;) by using &lt;code&gt;Uri.parse(URL)&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Sending and Receiving Data
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;WebSocketChannel.stream&lt;/code&gt; is used to listen for messages. As the name implies, it's a &lt;code&gt;Stream&lt;/code&gt;, which is exactly the best data type for incoming data from a WebSocket. It returns any new messages coming from the WebSocket as soon as they are received.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;WebSocketChannel.sink&lt;/code&gt; is used to send messages. As the name implies, it's a &lt;code&gt;StreamSink&lt;/code&gt;. If you've read my book or have worked with the Firebase Cloud Firestore before, this is used in a similar way to the &lt;code&gt;Firestore&lt;/code&gt;'s &lt;code&gt;CollectionReference&lt;/code&gt; object: &lt;code&gt;WebSocketChannel.sink.add(data)&lt;/code&gt; sends data through the WebSocket.&lt;/p&gt;

&lt;h3&gt;
  
  
  Closing the Connection
&lt;/h3&gt;

&lt;p&gt;If &lt;code&gt;channel&lt;/code&gt; is the &lt;code&gt;WebSocketChannel&lt;/code&gt;, you can close the connection using&lt;code&gt;channel.sink.close(statusCode);&lt;/code&gt;. A list of status codes is available in &lt;code&gt;web_socket_channel&lt;/code&gt;'s &lt;code&gt;status.dart&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  @override
  void dispose() {
    super.dispose();
    channel.sink.close(statusCodes.goingAway);
  }
~~~

## Building an Example App

You can find the complete source code for this app [on this GitHub repository](https://github.com/carzacc/websockets_flutter).

Let's start with the `pubspec.yaml`, which needs to have as a dependency the `web_socket_channel` package:

&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;

&lt;p&gt;In &lt;code&gt;lib/main.dart&lt;/code&gt; we're going to import &lt;code&gt;package:web_socket_channel/web_socket_channel.dart&lt;/code&gt; to use the &lt;code&gt;WebSocketChannel&lt;/code&gt;, then we set the server IP and port, and then start an app that has as its home page a class called &lt;code&gt;FauxLoginPage&lt;/code&gt;:&lt;/p&gt;

&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;h3&gt;
  
  
  The FauxLoginPage
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;FauxLoginPage&lt;/code&gt; is going to be, as the name implies, a &lt;em&gt;fake&lt;/em&gt; login page: it's not going to be a proper login page for the user to authenticate, but just a page for the user to set an username. As I wrote above, we're not going to worry about authentication because that was the focus of the previous post. If you know how to use &lt;code&gt;TextField&lt;/code&gt;s (and especially if you're familiar with the Firebase chat app example in my book, which has a login page that works a bit like this one but actually authenticates the user) this is all going to be self-explanatory and simple:&lt;/p&gt;

&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;AnnouncementPage&lt;/code&gt; is going to simply be a &lt;code&gt;StatelessWidget&lt;/code&gt;: we're going to let a &lt;code&gt;StreamBuilder&lt;/code&gt; take care of the changes in values returned by the &lt;code&gt;Stream&lt;/code&gt; of data from the WebSocket. Below the text coming from the WebSocket, we're going to have a &lt;code&gt;TextField&lt;/code&gt; that allows the user to send a message. We convert the data to a string so that it could technically be anything, and be shown to the user &lt;em&gt;as is&lt;/em&gt;, to make debugging easier:&lt;/p&gt;

&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;

&lt;p&gt;The entire &lt;code&gt;main.dart&lt;/code&gt; is going to be the following, then:&lt;/p&gt;

&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;h2&gt;
  
  
  Building the Backend for the App
&lt;/h2&gt;

&lt;p&gt;We're going to build the backend for the app with Node.js and the &lt;a href="https://www.npmjs.com/package/ws"&gt;&lt;code&gt;ws&lt;/code&gt; npm package&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  The ws Package
&lt;/h3&gt;

&lt;p&gt;There's a very popular and easy-to-use WebSocket client/server &lt;a href="https://www.npmjs.com/package/ws"&gt;package for Node called simply &lt;em&gt;ws&lt;/em&gt;&lt;/a&gt;, so you can install it using&lt;/p&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;$ npm install ws&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
You can start a WebSocket server that listens to a given port with the following code:{% raw %}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;var server = new WebSocket.Server(&lt;br&gt;
  {&lt;br&gt;
    port: port,&lt;br&gt;
  }&lt;br&gt;
);&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
you can wait for a connection and define a callback to be ran when a client connects with the following code:{% raw %}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;server.on('connection', function connection(client) {&lt;br&gt;
    // code to execute when a client connects&lt;br&gt;
});&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
This gives us a {% raw %}`client` object we can use to send messages to the connected WebSocket client using `client.send()`:

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;client.send(msg);&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
We can also listen for messages sent by the client over the WebSocket and run a function when that happens:{% raw %}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;client.on('message', function incoming(message) {&lt;br&gt;
    // code to execute when a message is received&lt;br&gt;
});&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
An useful member of the {% raw %}`server` object is `server.clients`, which is an array of the connected clients. This means we can send a message to each connected client with the following:

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;for(var cl of server.clients) {&lt;br&gt;
  cl.send(message);&lt;br&gt;
}&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
### Implementing the Backend

You can find source code for the backend at [this GitHub repository](https://github.com/carzacc/websocketsbackend).

The first thing we need is to import the *ws* package:

{% gist https://gist.github.com/carzacc/430d50943715dfbde2bd2082992af9a3 file=imports.js %}

Then set a port and start the WebSocket server:

{% gist https://gist.github.com/carzacc/430d50943715dfbde2bd2082992af9a3 file=startserver.js %}

let's also define a default message to send to the client the first time:

{% gist https://gist.github.com/carzacc/430d50943715dfbde2bd2082992af9a3 file=letmsg.js %}

When a client connects for the first time, we send them that message so the client has something to display to the user when they connect:

{% gist https://gist.github.com/carzacc/430d50943715dfbde2bd2082992af9a3 file=connection.js %}

Now, let's handle the reception of a message:

{% gist https://gist.github.com/carzacc/430d50943715dfbde2bd2082992af9a3 file=onmessage.js %}

What we should do is broadcast the received message to all connected clients:

{% gist https://gist.github.com/carzacc/430d50943715dfbde2bd2082992af9a3 file=broadcast.js %}

If we also log to console each received message the final {% raw %}`index.js` is the following:

&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;

&lt;p&gt;As always, if you enjoyed this post, consider &lt;a href="https://twitter.com/carminezacc"&gt;following me on Twitter @carminezacc&lt;/a&gt;.&lt;/p&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>node</category>
      <category>dart</category>
      <category>ios</category>
      <category>android</category>
    </item>
    <item>
      <title>User Authentication + JWT Authorization With Flutter and Node</title>
      <dc:creator>Carmine Zaccagnino</dc:creator>
      <pubDate>Tue, 18 Feb 2020 15:37:55 +0000</pubDate>
      <link>https://forem.com/carminezacc/user-authentication-jwt-authorization-with-flutter-and-node-176l</link>
      <guid>https://forem.com/carminezacc/user-authentication-jwt-authorization-with-flutter-and-node-176l</guid>
      <description>&lt;p&gt;&lt;em&gt;Cover Photo by James Sutton on Unsplash&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The series of posts about advanced networking topics applied to Flutter apps continues. As always, this is meant for people who already have a good understanding of Flutter and know how to use Flutter widgets and the basics of the &lt;code&gt;http&lt;/code&gt; library.&lt;/p&gt;

&lt;p&gt;That's the kind of stuff you can learn by reading &lt;a href="https://carmine.dev/programmingflutter/"&gt;my Flutter book&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;In particular, this post supposes you know how to make HTTP requests, how to use the most basic widgets (&lt;code&gt;Scaffold&lt;/code&gt;, &lt;code&gt;Column&lt;/code&gt;, &lt;code&gt;Text&lt;/code&gt;, &lt;code&gt;FlatButton&lt;/code&gt;, etc.) and that you know how to use a &lt;code&gt;TextField&lt;/code&gt; with a &lt;code&gt;TextEditingController&lt;/code&gt;, the basics of asynchronous functions and &lt;code&gt;Future&lt;/code&gt;s and how to use them with a &lt;code&gt;FutureBuilder&lt;/code&gt;, how to display dialogs and how to work with JSON.&lt;/p&gt;

&lt;p&gt;You can learn about them online too, if you hate books. I won't be judging you.&lt;/p&gt;

&lt;p&gt;Regarding the backend, I'm going to suppose you know about how to use the Express Node.js framework, and that you know how to use basic SQL commands like &lt;code&gt;CREATE&lt;/code&gt;, &lt;code&gt;INSERT&lt;/code&gt;, and &lt;code&gt;SELECT&lt;/code&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  What We’re Going to Build
&lt;/h1&gt;

&lt;p&gt;The app we’re going to build is the simplest example of an app that requires authentication: it allows anyone to sign up, and any logged in user can access a piece of data. We’re going to implement the back-end with Node and the front-end with Flutter.&lt;/p&gt;

&lt;h1&gt;
  
  
  What is JWT
&lt;/h1&gt;

&lt;p&gt;JWT  (JSON Web Token) is a standard that specifies a very secure way to transmit session tokens between an user-accessible front-end (that we’ll write using Flutter) and a back-end (that we’ll write using Node).&lt;/p&gt;

&lt;p&gt;Unlike a more traditional user session implementations, in which the session token is stored both on the server and on the client, the client sends the token along with every request and the server can check whether a session exists with that token for that user and decide whether to grant access based on that and what the user is actually allowed to do.&lt;/p&gt;

&lt;p&gt;JWT is different. The server doesn’t store the token: at the time of authentication, it sends a signed token, but it doesn’t store it, instead relying on the signature it attaches to the token (obtained either with RSA, ECDSA or HMAC with SHA256 usually), which allows it to verify both the authenticity of the token and whether it was tampered with.&lt;/p&gt;

&lt;p&gt;This means the token's payload can contain both data the front-end needs, since it can be freely accessed by it, and data (like the user name/ID and/or an expiration date) the server needs to validate the request and the token.&lt;/p&gt;

&lt;p&gt;The actual structure of the JWT is made of three base64-encoded strings separated by a &lt;code&gt;.&lt;/code&gt; character: the first contains information needed to verify the signature, the second contains the payload, the third contains the signature.&lt;/p&gt;

&lt;h2&gt;
  
  
  Analyzing an Example
&lt;/h2&gt;

&lt;p&gt;I've taken an example of a JWT generated by the backend we'll build as an example in this post. It is &lt;code&gt;eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VybmFtZSI6InVzZXJuYW1lIiwiaWF0IjoxNTgxOTY2MzkxLCJleHAiOjE1ODMyNjIzOTF9.IDXKR0PknG96OyVgRf7NEX1olzhhLAiwE_-v-uMbOK0&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you pay attention, you'll notice there are two dots. The first (&lt;code&gt;eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9&lt;/code&gt;) can be decoded to ASCII to &lt;code&gt;{"alg":"HS256","typ":"JWT"}&lt;/code&gt;, which is a JSON object, which can be formatted like this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "alg": "HS256",
  "typ": "JWT"
}
~~~

`HS256` is short for `HMAC`+`SHA256`, and `typ` is quite self-explanatory, it tells us what the string we're looking at is.

The second string (`eyJ1c2VybmFtZSI6InVzZXJuYW1lIiwiaWF0IjoxNTgxOTY2MzkxLCJleHAiOjE1ODMyNjIzOTF9`) can be decoded and formatted to:

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;{&lt;br&gt;
  "username": "username",&lt;br&gt;
  "iat": 1581966391,&lt;br&gt;
  "exp": 1583262391&lt;br&gt;
}&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
This is a JWT for an user called {% raw %}`username`, issued at (`iat`) second 1581966391 after the Unix epoch (the 17th of February 2020 at 19:06) and that expires at (`exp`) second 1583262391 (03/03/2020 at the same time as when it was created).

The third string is just the signature obtained as an HMAC with SHA256.

# Our API Interface

Our backend is going to have three routes:

* `/signup`, which accepts POST requests in urlencoded format, containing two self-explanatory text fields: an *username* field and a *password* field and either responds with status code 201 if it was able to create the user, or status code 409 if it wasn't; 
* `/login`, which accepts POST requests in urlencoded format and accepts the same fields as `/signup`, and either responds with status code 200 and the JWT in the body of the response, or with status code 401 if there is no user with the given username and password;
* `/data`, which accepts GET requests, which must have a JWT attached to the `Authorization` request header, and which will either return the "secret data" only authenticated users can access (with status code 200) or a response with status code 401, meaning the JWT is invalid or has expired.

# Implementing the Front-End App with Flutter

You can find the code for this Flutter app [on GitHub by clicking here](https://github.com/carzacc/jwt-tutorial-flutter).

## Using The flutter_secure_storage Package

The *flutter_secure_storage* package is very easy to use: it's simply key-value pair storage, but using iOS's Keychain directly or by encrypting the data, storing the encrypted data in Android's Shared Preferences.

You can write the *myvalue* and associate it to the *mykey* key using it by using `storage.write()` in the following way:

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;var storage = FlutterSecureStorage();&lt;br&gt;
storage.write(key: "mykey", value: "myvalue");&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
{% raw %}`storage.write` is asynchronous (it has a return type of `Future&amp;lt;void&amp;gt;`), so you should use `await` if you need to pause execution while it executes.

You can read the value associated to the *mykey* key by using `storage.read()`, which is also asynchronous, so you need to wait for it to return in order to be able to read the value.

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;var storage = FlutterSecureStorage();&lt;br&gt;
var value = await storage.read(key: "mykey");&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
You can use {% raw %}`storage.delete()` to delete a value (it's also asynchronous):

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;var storage = FlutterSecureStorage();&lt;br&gt;
storage.delete(key: "mykey");&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
Two methods exist, called {% raw %}`readAll()` and `deleteAll()` (both asynchronous), which respectively return a `Map` of all the stored values and delete all of the stored values.

## Implementation

The Flutter app doesn’t need to be particularly complicated to be able to work with JWT: it’s mostly about writing an authentication flow, storing the JWT token and sending it with each request.

In addition to that, for this example we’ll check whether the token has expired on the front-end and we’ll show the username after the user logs in, so we’ll actually have to decode the payload. 
We are going to store the JWT using the *flutter_secure_storage* package, which is the simplest way to access the secure storage interfaces provided by iOS and Android from a Flutter app.

Here are two screenshots of what we want to achieve:

![](https://carmine.dev/img/Screenshot_1581601687.png)

![](https://carmine.dev/img/Screenshot_1581601694.png)

Add the *flutter_secure_storage* and *http* packages to the app's dependencies in `pubspec.yaml`:

 &lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;

&lt;p&gt;Then, set the minimum supported Android version to SDK level 18 (Android 4.3) because that's required by &lt;em&gt;flutter_secure_storage&lt;/em&gt;.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
&lt;br&gt;
  &lt;br&gt;
&lt;/div&gt;

&lt;p&gt;Create the usual &lt;code&gt;lib/main.dart&lt;/code&gt;, import the packages, initialize a &lt;code&gt;FlutterSecureStorage&lt;/code&gt; object and insert the IP and port where the Node server backend will be running, so that we can use that going forward without having to change anything else from the example code I provided:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
&lt;br&gt;
  &lt;br&gt;
&lt;/div&gt;
&lt;h2&gt;
  
  
  The Structure of Our Flutter App
&lt;/h2&gt;

&lt;p&gt;The structure of our Flutter app is going to be the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the &lt;code&gt;MyApp&lt;/code&gt; class, which is going to check whether the user has previously logged in, and decide whether to run the &lt;code&gt;LoginPage&lt;/code&gt; or the &lt;code&gt;HomePage&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;the &lt;code&gt;LoginPage&lt;/code&gt; is where we are going to allow the user to log in or sign up;&lt;/li&gt;
&lt;li&gt;the &lt;code&gt;HomePage&lt;/code&gt; is where we are going to show the user the &lt;em&gt;secret data&lt;/em&gt; that can only be accessed by logged-in users. The &lt;code&gt;HomePage&lt;/code&gt; needs to be able to be constructed from either just the JWT Base 64 string&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  Creating a Log-In Page
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;MaterialApp&lt;/code&gt; object we're launching is called &lt;code&gt;MyApp&lt;/code&gt;, but we'll worry about that later, given that it needs to check whether we're already logged in, and then choose whether to display a log-in page or the home page.&lt;/p&gt;

&lt;p&gt;That's a bit boring to worry about now, let's build some UI and create a log-in page!&lt;/p&gt;

&lt;p&gt;The log-in page itself will be a &lt;code&gt;StatelessWidget&lt;/code&gt; called &lt;code&gt;LoginPage&lt;/code&gt;:&lt;/p&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;class LoginPage extends StatelessWidget {&lt;br&gt;
}&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
The nature of the login page and our implementation means we are going to make extensive use of dialogs. This means we'll create a helper method in order to make everything more succint:{% raw %}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;void displayDialog(BuildContext context, String title, String text) =&amp;gt; &lt;br&gt;
    showDialog(&lt;br&gt;
      context: context,&lt;br&gt;
      builder: (context) =&amp;gt;&lt;br&gt;
        AlertDialog(&lt;br&gt;
          title: Text(title),&lt;br&gt;
          content: Text(text)&lt;br&gt;
        ),&lt;br&gt;
    );&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
We'll also create methods that attempt to login and signup the user, and they're very simple POST requests, as we saw earlier on when we talked about our app's API interface.

We'll return a string for the login method, which will be {% raw %}`null` in case of an error (i.e. wrong username/password) and the JWT if the authentication process succeded:

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Future attemptLogIn(String username, String password) async {&lt;br&gt;
  var res = await http.post(&lt;br&gt;
    "$SERVER_IP/login",&lt;br&gt;
    body: {&lt;br&gt;
      "username": username,&lt;br&gt;
      "password": password&lt;br&gt;
    }&lt;br&gt;
  );&lt;br&gt;
  if(res.statusCode == 200) return res.body;&lt;br&gt;
  return null;&lt;br&gt;
}&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
The sign-up method doesn't actually have to return anything useful to the app, so we can just return the status code and deal with that later to establish whether the operation was successuful or not:{% raw %}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Future attemptSignUp(String username, String password) async {&lt;br&gt;
  var res = await http.post(&lt;br&gt;
    '$SERVER_IP/signup',&lt;br&gt;
    body: {&lt;br&gt;
      "username": username,&lt;br&gt;
      "password": password&lt;br&gt;
    }&lt;br&gt;
  );&lt;br&gt;
  return res.statusCode;&lt;br&gt;&lt;br&gt;
}&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
Here comes the fun part!{% raw %}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;@override&lt;br&gt;
Widget build(BuildContext context) =&amp;gt;&lt;br&gt;
  Scaffold(&lt;br&gt;
    appBar: AppBar(title: Text("Log In")),&lt;br&gt;
    body: /* TODO:INSERT BODY HERE */&lt;br&gt;
  );&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
what's the {% raw %}`body` going to be? A `Column` with two `TextFields` that allow the user to insert username and password and two `FlatButton`s: one to log in and one to sign up. We'll also add some padding around it given that it looks horrible to my eyes without it:

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;body: Padding(&lt;br&gt;
  padding: EdgeInsets.all(8.0),&lt;br&gt;
  child: Column(&lt;br&gt;
    children: [&lt;br&gt;
      TextField(&lt;br&gt;
        controller: _usernameController,&lt;br&gt;
        decoration: InputDecoration(&lt;br&gt;
          labelText: 'Username'&lt;br&gt;
        ),&lt;br&gt;
      ),&lt;br&gt;
      TextField(&lt;br&gt;
        controller: _passwordController,&lt;br&gt;
        obscureText: true,&lt;br&gt;
        decoration: InputDecoration(&lt;br&gt;
          labelText: 'Password'&lt;br&gt;
        ),&lt;br&gt;
        FlatButton(&lt;br&gt;
          child: Text("Log In"),&lt;br&gt;
          onPressed: /* TODO:HANDLE LOG IN &lt;em&gt;/&lt;br&gt;
        ),&lt;br&gt;
        FlatButton(&lt;br&gt;
          child: Text("Sign Up"),&lt;br&gt;
          onPressed: /&lt;/em&gt; TODO:HANDLE SIGN UP */&lt;br&gt;
        )&lt;br&gt;
      )&lt;br&gt;
    ]&lt;br&gt;
  )&lt;br&gt;
)&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
The {% raw %}`labelText` in the `InputDecoration` is the nicest looking way to tell users what each `TextField` is for.

Define the `_usernameController` and `_passwordController` `TextEditingController`s  somewhere in the class definition, like this:

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;final TextEditingController _usernameController = TextEditingController();&lt;br&gt;
final TextEditingController _passwordController = TextEditingController();&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
Let's worry about the function to handle logging in, which needs to call the {% raw %}`attemptLogIn` method with the `username` and `password` taken from the `TextEditingController`s, then check the JWT returned by the `attemptLogIn` method. If it is `null`, we need to display a dialog to inform the user we were unable to log them in. If it isn't, we can switch to the `HomePage` and save the JWT:

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;onPressed: () async {&lt;br&gt;
  var username = _usernameController.text;&lt;br&gt;
  var password = _passwordController.text;&lt;/p&gt;

&lt;p&gt;var jwt = await attemptLogIn(username, password);&lt;br&gt;
  if(jwt != null) {&lt;br&gt;
    storage.write(key: "jwt", value: jwt);&lt;br&gt;
    Navigator.push(&lt;br&gt;
      context,&lt;br&gt;
      MaterialPageRoute(&lt;br&gt;
        builder: (context) =&amp;gt; HomePage.fromBase64(jwt)&lt;br&gt;
      )&lt;br&gt;
    );&lt;br&gt;
  } else {&lt;br&gt;
    displayDialog(context, "An Error Occurred", "No account was found matching that username and password");&lt;br&gt;
  }&lt;br&gt;
},&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
The function that handles sign-up is going to be complicated by the checking of a few conditions.

We are going to check on the front-end that the user doesn't try to use un username or password less than 4 characters long. This should also be done on the back-end, but this tutorial focuses more on Flutter than it does on Node, so we're just going to do this on the front-end.

If those two inputs are valid, we are going to attempt to sign up, and check the response. If we get HTTP status code 201, it means the user was created and we can simply tell the user to log in with those credentials.

If we get HTTP status code 409, it means the username is already in use, and we can tell that to the user. If the response's status code is neither 409 nor 201, the request failed (probably because of a network error or an internal server error), we just tell the user an unknown error occurred:{% raw %}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;onPressed: () async {&lt;br&gt;
  var username = _usernameController.text;&lt;br&gt;
  var password = _passwordController.text;&lt;/p&gt;

&lt;p&gt;if(username.length &amp;lt; 4) &lt;br&gt;
    displayDialog(context, "Invalid Username", "The username should be at least 4 characters long");&lt;br&gt;
  else if(password.length &amp;lt; 4) &lt;br&gt;
    displayDialog(context, "Invalid Password", "The password should be at least 4 characters long");&lt;br&gt;
  else{&lt;br&gt;
    var res = await attemptSignUp(username, password);&lt;br&gt;
    if(res == 201)&lt;br&gt;
      displayDialog(context, "Success", "The user was created. Log in now.");&lt;br&gt;
    else if(res == 409)&lt;br&gt;
      displayDialog(context, "That username is already registered", "Please try to sign up using another username or log in if you already have an account.");&lt;br&gt;&lt;br&gt;
    else {&lt;br&gt;
      displayDialog(context, "Error", "An unknown error occurred.");&lt;br&gt;
    }&lt;br&gt;
  }&lt;br&gt;
},&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
The entire {% raw %}`LoginPage` definition looks like this in the end:

 &lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;h2&gt;
  
  
  Creating an Home Page
&lt;/h2&gt;

&lt;p&gt;We already know what we need as constructors for the &lt;code&gt;HomePage&lt;/code&gt;. Getting the payload from the base64 JWT string should be pretty self-explanatory if you understood the section at the start of this post about the structure of a JWT, and you only need to keep in mind that base64.decode needs a padded base64 string, and that can be obtained with &lt;code&gt;base64.normalize()&lt;/code&gt;:&lt;/p&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;class HomePage extends StatelessWidget {&lt;br&gt;
  HomePage(this.jwt, this.payload);&lt;/p&gt;

&lt;p&gt;factory HomePage.fromBase64(String jwt) =&amp;gt;&lt;br&gt;
    HomePage(&lt;br&gt;
      jwt,&lt;br&gt;
      json.decode(&lt;br&gt;
        ascii.decode(&lt;br&gt;
          base64.decode(base64.normalize(jwt.split(".")[1]))&lt;br&gt;
        )&lt;br&gt;
      )&lt;br&gt;
    );&lt;/p&gt;

&lt;p&gt;final String jwt;&lt;br&gt;
  final Map payload;&lt;br&gt;
}&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
Instead of {% raw %}`ascii.decode`, use `utf8.decode` if you want to support non-ASCII characters. Thanks to @bisquits in the comments for noticing this, since it's really important!

### The HomePage's build() method

The `HomePage` widget itself is going to be made of a `FutureBuilder` that waits for the GET request to the server to get the data, and then either displays it or some text informing the user an error has occurred, if that is the case:

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;@override&lt;br&gt;
Widget build(BuildContext context) =&amp;gt;&lt;br&gt;
  Scaffold(&lt;br&gt;
    appBar: AppBar(title: Text("Secret Data Screen")),&lt;br&gt;
    body: Center(&lt;br&gt;
      child: FutureBuilder(&lt;br&gt;
        future: http.read('$SERVER_IP/data', headers: {"Authorization": jwt}),&lt;br&gt;
        builder: (context, snapshot) =&amp;gt;&lt;br&gt;
          snapshot.hasData ?&lt;br&gt;
          Column(&lt;br&gt;
            children: [&lt;br&gt;
              Text("${payload['username']}, here's the data:"),&lt;br&gt;
              Text(snapshot.data, style: Theme.of(context).textTheme.display1)&lt;br&gt;
            ],&lt;br&gt;
          )&lt;br&gt;
          :&lt;br&gt;
          snapshot.hasError ? Text("An error occurred") : CircularProgressIndicator()&lt;br&gt;
      ),&lt;br&gt;
    ),&lt;br&gt;
  );&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
The {% raw %}`HomePage` class definition is, therefore, the following:

 &lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;h2&gt;
  
  
  Creating the MyApp Class
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;MyApp&lt;/code&gt; class is the class that gets run when the app starts. It needs to check whether it already has a JWT and, if it has one, it should check whether it is valid, whether it has expired and, based on that, decide whether to ask the user to log in or whether to show them the home page. We are going to need to create a method called &lt;code&gt;jwtOrEmpty()&lt;/code&gt;&lt;/p&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Future get jwtOrEmpty async {&lt;br&gt;
  var jwt = await storage.read(key: "jwt");&lt;br&gt;
  if(jwt == null) return "";&lt;br&gt;
  return jwt;&lt;br&gt;
}&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
That's because the {% raw %}`FutureBuilder`'s `snapshot.hasData` parameter that gets passed to the `builder` function would return `false` if it were to receive a `null` value, which would be the case if the JWT were non-existent. This is unwanted because we would have no way of distinguishing the case in which we are still waiting for the `Future` to return and the case in which there is no JWT. Having this second case return an empty string instead of `null` fixes the issue.

All that's left to do is to create a `build()` method, which should return a `MaterialApp` (that's the whole point of the `MyApp` class) that, after getting the JWT and checking it, either shows the user the login page or the home page based on the criteria I described earlier.

All of that ends up in the following class definition:

 &lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;h1&gt;
  
  
  Implementing the Back-End with Node
&lt;/h1&gt;

&lt;p&gt;You can find the code for this Node backend &lt;a href="https://github.com/carzacc/jwt-tutorial-backend"&gt;on GitHub by clicking here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The Node back-end is where most of it happens: we need to create rules for login, logout and some sort of data to access. We are going to store users in an SQLite database to keep things simple for this example.&lt;/p&gt;
&lt;h2&gt;
  
  
  Choosing How to Sign the Token
&lt;/h2&gt;

&lt;p&gt;The token can be signed using either a method based on public key cryptography (for example using RSA or ECDSA) or by relying on hashing the concatenation of the secret key and the message (called a &lt;em&gt;payload&lt;/em&gt; in JWT terms) with any hashing algorithm (usually sha256). The latter concept has been expanded into a full standard for generation of a digital signature (called HMAC) that is protected against collisions and length extension attacks, about which you can find more information &lt;a href="https://en.wikipedia.org/wiki/HMAC"&gt;on Wikipedia&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For this example, that’s what we will use: HMAC with SHA256. That’s because it’s easier for a quick example for a blog post because we have greater freedom with our choice of private key. When building a real app, you should obviously consider the advantages and disadvantages of this approach based on your needs and the requirements your apps needs to meet. For this post we’ll use a short and simple string as a key, that’s not how it’s supposed to be done: it should ideally be a generated pseudorandom (and particularly long) key, just like any RSA or ECDSA key generated with OpenSSL, otherwise you’re making it very easy for attackers to crack your private key and generate their own JWT tokens your back-end will think are genuine, allowing them to pretend they’re logged in as any user, completely breaking your website’s security.&lt;/p&gt;
&lt;h3&gt;
  
  
  Safety First!
&lt;/h3&gt;

&lt;p&gt;In other words, this is an example meant to be as easy to follow as possible and you must take the appropriate precautions when it comes to choosing or generating a private key. Since we’re talking about security precautions, you should obviously use TLS for communications between front-end and back-end in production. Also, salt the passwords before hashing them if you really want to play it safe.&lt;/p&gt;
&lt;h2&gt;
  
  
  Building the Back-End
&lt;/h2&gt;

&lt;p&gt;These are the libraries we are going to use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://expressjs.com/"&gt;Express&lt;/a&gt;, which is what we are going to use as a Web framework;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.npmjs.com/package/jsonwebtoken"&gt;&lt;em&gt;jsonwebtoken&lt;/em&gt;&lt;/a&gt;, which simplifies greatly the process of creating JSON Web Tokens;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.npmjs.com/package/sqlite3"&gt;the &lt;em&gt;sqlite3&lt;/em&gt; SQLite Node driver&lt;/a&gt; to create and access the SQLite database where we are going to store our users' data;&lt;/li&gt;
&lt;li&gt;Node's built-in &lt;em&gt;crypto&lt;/em&gt; library to hash the password to store in the SQLite database.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Using the jsonwebtoken Library
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;jsonwebtoken&lt;/code&gt; NPM package is very, very easy to use. It provides us with three functions, once imported with &lt;code&gt;jwt = require("jsonwebtoken")&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;jwt.sign(payload, key, options)&lt;/code&gt;, which returns a JWT containing the &lt;code&gt;payload&lt;/code&gt; and signed using the &lt;code&gt;key&lt;/code&gt;, optionally you could also add a callback at the end of the argument list and it would be ran asynchronously, but we're not going to use that feature for our simple example, the default algorithm used for generating the signature is &lt;code&gt;RS256&lt;/code&gt; (RSA signature with SHA256);&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;jwt.verify(token, key)&lt;/code&gt;, which returns the decoded payload if the JWT is valid, and throws an error if it isn't, it also optionally takes some options and a callback just like &lt;code&gt;jwt.sign()&lt;/code&gt;, but we're going to provide neither of them;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;jwt.decode(token)&lt;/code&gt;, which decodes the payload without verifying the validity, we're not going to use this one at all.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, if your payload is &lt;code&gt;{username: "myusername"}&lt;/code&gt; and the private key is stored in the variable &lt;code&gt;privKey&lt;/code&gt; and you want to create a JWT using the provided RSA private key that is valid for two hours, you can run&lt;/p&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;let jwt = jwt.sign({username: "myusername"}, privKey, {expiresIn: "2h"} );&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
and then, if {% raw %}`pubKey` is the corresponding RSA public key, you can run

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;let jwt = jwt.verify({username: "myusername"}, pubKey);&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
In our example we are going to use just one secret key (stored in a variable called {% raw %}`KEY`), so we are going to generate the JWT as an HMAC with SHA256 (*HS256*) and have it expire after 15 days, which means we are going to generate the JWT with:

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;let jwt = jwt.sign({username: "myusername"}, KEY, {expiresIn: "15d", algorithm: "HS256"});&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
I recommend you look at the documentation for the package on the NPM page for a more complete list of options. I'm not writing an API reference here, I'm trying to make you understand how to implement this.

### A Quick Introduction to the sqlite3 Node SQLite Driver

The sqlite3 Node SQLite Driver doesn't come with too many bells and whistles. There are other packages that provide different interfaces, this is the most basic one and it's perfect for a very basic and simple example that really shouldn't require a huge {% raw %}`node_modules` directory or particularly complicated.

After importing the library with `sqlite = require("sqlite3")`, you can initialize a connection to a database stored in a file called *filename.db* with:

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;let db = new sqlite.Database("filename.db");&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
The functions we are going to use are:

* {% raw %}`db.get(query, function(err, row) {})`, which runs the `query` and passes to the provided callback the first row returned as the `row` argument and any errors as the `err` argument;
* `db.run(query)`, which runs the given query, without returning any results, this is used for commands such as `CREATE` and `INSERT` and you can pass a callback to be called in case of errors.

Two other functions exist called `db.all()` and `db.each()` which respectively pass all of the rows as an array to the callback and call the callback for each row returned, only passing one at a time. We would need to use such functions if we wanted, for example, to check whether a log-in attempt failed because the password was wrong, even though the given username exists in the database.

#### Query Parameters

The queries can contain parameters, which can optionally be passed as an array, so they can replace `?` characters found in the query string. This will sanitize the strings before substituting them, not making you vulnerable to SQL injection. For example, the following two calls to `db.each` are equivalent:

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;db.each("SELECT * FROM Users WHERE username='carmine'", function(err, row) {&lt;br&gt;
  console.log(row);&lt;br&gt;
});&lt;br&gt;
~~~&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;db.each("SELECT * FROM Users WHERE username=?", ['carmine'], function(err, row) {
  console.log(row);
});
~~~

### Installing Dependencies

As always, create a Node project with

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;$ npm init&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
and install the packages I listed above with{% raw %}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;$ npm install --save express jsonwebtoken sqlite3&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
### Initial Config

We are going to import all of the libraries into our code and set the secret key (a very unsafe one, but this is just an example) and initialize the database connection:

 {% gist https://gist.github.com/carzacc/ab1f598a313806a02dc401d52a10df6b file=initialConfig.js %}

### Initializing the Database

You can do this either directly using the SQLite or any other tool of your choice or by creating this Node.js file and running it:

 {% gist https://gist.github.com/carzacc/13453b285f265bfa3606f271d2601eb4 %}

### Implementing Sign-Up

Signing users up is simple and has nothing to do with how we manage authorization: we're not logging them in, which means we just need to check whether they have already signed up. If they haven't, we sign them up by adding them to our database. We are going to use the Express built-in urlencoded middleware to parse the body of the request and we're going to log everything to the server console:

 {% gist https://gist.github.com/carzacc/ab1f598a313806a02dc401d52a10df6b file=signup.js %}

Logging in is all about looking in the database for the user who is trying to log in, generating a JWT and returning it if we find it, and returning an error if we don't:

 {% gist https://gist.github.com/carzacc/ab1f598a313806a02dc401d52a10df6b file=login.js %}

Verifying the token is very easy with the Node library we are using, meaning the {% raw %}`/data` route is written very quickly and painlessly, remembering that a failure in verifying the JWT will result in an error being thrown:

 &lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;

&lt;p&gt;As usual, we take the port to run the server on from the environment variable &lt;code&gt;PORT&lt;/code&gt; and, if that fails, we set it to 3000 and run the server:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
&lt;br&gt;
  &lt;br&gt;
&lt;/div&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>dart</category>
      <category>node</category>
      <category>security</category>
      <category>android</category>
    </item>
    <item>
      <title>Uploading a File to a Server from Flutter Using a Multi-Part (form-data) POST Request</title>
      <dc:creator>Carmine Zaccagnino</dc:creator>
      <pubDate>Sun, 02 Feb 2020 20:56:04 +0000</pubDate>
      <link>https://forem.com/carminezacc/advanced-flutter-networking-part-1-uploading-a-file-to-a-rest-api-from-flutter-using-a-multi-part-form-data-post-request-2ekm</link>
      <guid>https://forem.com/carminezacc/advanced-flutter-networking-part-1-uploading-a-file-to-a-rest-api-from-flutter-using-a-multi-part-form-data-post-request-2ekm</guid>
      <description>&lt;p&gt;My Flutter book is pretty light on advanced HTTP networking topics, focusing instead on giving a more well-rounded approach that, when it comes to networking, explains how to use the http networking package for basic requests, shows an example of an app that makes GET requests, and then goes a bit more specific with Firebase.&lt;/p&gt;

&lt;p&gt;My blog is here for those who need more than that, and the first topic I'm going to cover is how to upload a file using a multi-part/form-data POST request.&lt;/p&gt;

&lt;p&gt;You can find all of the code contained in this example in &lt;a href="https://github.com/carzacc/form-data-post"&gt;this GitHub repository&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is a Multi-Part POST Request
&lt;/h2&gt;

&lt;p&gt;Usually, the body of a POST request is made of textual key-value pairs. With a multipart POST request, you can also include files with binary content (images, various documents, etc.), in addition to the regular text values.&lt;/p&gt;

&lt;h2&gt;
  
  
  Making Multi-Part POST Requests with Flutter's HTTP Library
&lt;/h2&gt;

&lt;p&gt;This little section is going to focus on one thing: creating a function that, given a file path and an URL, is able to send that file to that URL with that multipart POST request.&lt;/p&gt;

&lt;p&gt;The next section is going to focus on how to build an app that lets the user insert the URL to which to send the request, pick an image and send it to the server, getting back the status of the request.&lt;/p&gt;

&lt;p&gt;This means we're not going to worry about dependencies in this section. All you need to know for this section is that we've got this at the top of our &lt;code&gt;main.dart&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import 'package:http/http.dart' as http;
~~~

This allows us to *create* (not send) a multipart POST request using

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;var req = http.MultipartRequest('POST', Uri.parse(url));&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
This {% raw %}`req` object has a member `Map` called `fields` for textual values and a `List` called `files` to which you can add `MultipartFiles`.

### The MultipartFile

The most important element of this whole thing is the `MultipartFile`. It can be constructed in a few ways:

* the default `MultipartFile(key, stream, length)` constructor, which you can use if you need to create the file from a `Stream` of bytes of which we know the length;
* the `MultipartFile.fromBytes(key, bytes)` factory method, which attaches a file obtained from a `List` of bytes;
* the `MultipartFile.fromString(key, string)` factory method, which attaches a text file containing the string passed to it;
* the `MultipartFile.fromPath(key, path)` factory method, which attaches the file found at the given path.

In case you’re wondering, *bytes* simply means *integers*. That’s all a byte is. An 8-bit integer value. A list of integers, coupled with an encoding (that can usually be inferred with the help of the extension that’s part of the file name) is all you need to get images, documents, videos, music or text.

If you're using one of the first two constructors for the `MultipartFile`, remember to set a filename using the specific named `filename` argument, as not doing that will cause issues with our back-end.

Here are a few examples: if you have a file and a path to it, here’s how you create a multipart POST request and attach that file to the request:

* Using the default constructor you could write a function like the following:

&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
 

&lt;ul&gt;
&lt;li&gt;Using&lt;code&gt;MultipartFile.fromBytes()&lt;/code&gt; you could write a function like the following:&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
 

&lt;ul&gt;
&lt;li&gt;Using&lt;code&gt;MultipartFile.fromPath()&lt;/code&gt; you could write a function like the following:&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
 
&lt;h3&gt;
  
  
  Adding Regular Text Fields
&lt;/h3&gt;

&lt;p&gt;You could add regular text fields to a Multipart POST requests simply by adding, after settomg initialized the &lt;code&gt;MultipartRequest&lt;/code&gt; object, an item in the &lt;code&gt;fields&lt;/code&gt; member &lt;code&gt;Map&lt;/code&gt;:&lt;/p&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;var request = http.MultipartRequest('POST', Uri.parse(url));&lt;br&gt;
request.fields['key'] = 'value';&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
## Building an App Around That

Now, to see it in action, let's write an app that allows the user to insert an URL, pick an image, and then upload the image to the server at that URL. We'll write the very simple back-end code required to accept files this way in Node after we're done with the app. Feel free to skip ahead if you're more interested in that.

Let's start, as we must, with an evaluation of the dependencies and the {% raw %}`pubspec.yaml` file. We'll use two packages from Dart Pub: the `image_picker` Flutter package that will handle the image selection dialog for us, about which [I wrote a tutorial on Medium a year ago (not part of the metered paywall in case you're wondering)](https://medium.com/@carminezaccagnino/taking-and-or-using-pictures-in-flutter-apps-using-the-image-picker-package-b8e366654a0) and the [Dart `http` package](https://pub.dev/packages/http) that provides the networking features we need.

Add both the dependencies in `pubspec.yaml` (check the GitHub repo I linked at the start of the post if you don't know how to do that) and import them both into the `lib/main.dart` file along with the usual Flutter Material Design API:

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;import 'package:flutter/material.dart';&lt;br&gt;
import 'package:http/http.dart' as http;&lt;br&gt;
import 'package:image_picker/image_picker.dart';&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
### The Start Page

Now let's think about the actions the user needs to take in our app: in order to upload images, we first need an URL, so let's show a screen that allows the user to set the URL first, and then we allow them to upload images. We'll call this first screen {% raw %}`StartPage`. This is the usual Flutter code used to initialize an app, this tutorial really is meant for those who don't need much explanation as to what it does and why (that's more the realm of introductory tutorials and books like the one I've written):

&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
 

&lt;p&gt;We use a &lt;code&gt;TextEditingController&lt;/code&gt; to let the user both submit the value from the Android keyboard or press our cusdtom &lt;code&gt;FlatButton&lt;/code&gt; below the &lt;code&gt;TextField&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  The Upload Page
&lt;/h3&gt;

&lt;p&gt;Here's the code for the upload page, I'll explain it down below after the code:&lt;/p&gt;

&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
 

&lt;p&gt;&lt;code&gt;uploadImage()&lt;/code&gt; is the simplest of the functions we saw earlier to upload images: we use &lt;code&gt;MultipartFile.fromPath()&lt;/code&gt; directly and return the status string of the request. That's going to be the &lt;code&gt;state&lt;/code&gt; variable, which is what is shown in the middle of the screen to the user. The URL is the one we get from the &lt;code&gt;StartPage&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;FloatingActionButton&lt;/code&gt; is fairly simple: &lt;code&gt;ImagePicker.pickImage()&lt;/code&gt; shows the familiar image picking screen to the user returns (through a &lt;code&gt;Future&lt;/code&gt;) the path to the file the user picks.&lt;/p&gt;

&lt;p&gt;We use that (as part of the floating action button's  &lt;code&gt;onPressed&lt;/code&gt; callback) together with the URL passed by the &lt;code&gt;StartPage&lt;/code&gt; to call the &lt;code&gt;uploadImage&lt;/code&gt; function and re-render the view using &lt;code&gt;setState&lt;/code&gt; to show the &lt;code&gt;state&lt;/code&gt; of the request to the user.&lt;/p&gt;
&lt;h2&gt;
  
  
  Writing a Simple Back-End in Node to Handle Multi-Part POST Requests
&lt;/h2&gt;

&lt;p&gt;For this section, the tools we're going to use are Node, Express and Multer. There's not going to be much code involved, this is a fairly simple affair.&lt;/p&gt;

&lt;p&gt;First of all, install Node and NPM according to the instructions for your operating system on &lt;a href="https://nodejs.org/en/"&gt;Node’s official website&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;After that, create a directory, run the command&lt;/p&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;$ npm init&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
and fill out to your preference the choices given to you (the default values are fine in case of doubt)

and then{% raw %}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;$ npm --save install express multer&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
Create a file called {% raw %}`index.js` with the following content:

&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
 

&lt;p&gt;As you can see it's not much code, but I'm going to explain it nonetheless.&lt;/p&gt;

&lt;p&gt;The first 4 lines are simply dealing with dependencies: the first three are straight-up imports of dependencies, whereas line 4 sets up the Multer middleware (the one that handles file uploads) to save uploaded files to the &lt;code&gt;uploads&lt;/code&gt; directory.&lt;/p&gt;

&lt;p&gt;Line 6 instantiates an Express server object, as the Express API documentation requires.&lt;/p&gt;
&lt;h3&gt;
  
  
  Creating an Express Rule for Handling Multipart POST requests
&lt;/h3&gt;

&lt;p&gt;After that, on lines 8 to 19, we define a rule for incoming POST requests to the &lt;code&gt;/upload&lt;/code&gt; path (in other words, it responds to POST requests sent to &lt;code&gt;&amp;amp;lt;server IP&amp;amp;gt;:&amp;amp;lt;port&amp;amp;gt;/upload&lt;/code&gt;), it takes one file on the &lt;code&gt;picture&lt;/code&gt; key, and it fires the callback function we defined as &lt;code&gt;(req, res) {...}&lt;/code&gt; in the lines 8 to 19.&lt;/p&gt;

&lt;p&gt;The callback prints to the console the name of the file that was received (on line 9), it then renames the file to the original file name.&lt;/p&gt;

&lt;p&gt;It does that on lines 10 to 16 by creating, as is done using Node's &lt;code&gt;fs&lt;/code&gt; interface, streams (much like &lt;code&gt;FILE*&lt;/code&gt; variables in C) that allow our script to read from an input file (&lt;code&gt;req.file.path&lt;/code&gt; is the path Multer saved the received file to) and write to an output file (using the passed &lt;code&gt;req.file.originalname&lt;/code&gt;, which is the filename specified in the POST request by the sender, which is our Flutter app). When this is finished (lines 13 to 16) we delete (&lt;code&gt;unlinkSync&lt;/code&gt;) the temporary file created by Multer (which has a name that ensures there aren't two files with the same name but doesn't even keep the same extension as the original file) and send back a response saying everything was OK.&lt;/p&gt;

&lt;p&gt;If an error happens (often because no file name was specified, on line 17) we will inform the sender of that.&lt;/p&gt;

&lt;p&gt;On lines 22 and 23 we start the server on the port specified by the &lt;code&gt;PORT&lt;/code&gt; environment variable or on port 3000 if no port was specified using environment variables.&lt;/p&gt;

&lt;p&gt;That's it.&lt;/p&gt;
&lt;h2&gt;
  
  
  Making Our Example Work
&lt;/h2&gt;

&lt;p&gt;To use the example code, start the server by running &lt;code&gt;node index.js&lt;/code&gt;. Then, fire up the Flutter app on a phone/emulator, get your PC's local IP (if the phone is connected to the same local network or it's running on an emulator) to substitute to &lt;code&gt;&amp;amp;lt;server_ip&amp;amp;gt;&lt;/code&gt; in &lt;code&gt;http://&amp;amp;lt;server_ip&amp;amp;gt;:3000/upload&lt;/code&gt;, which is what you need to type into the &lt;code&gt;TextField&lt;/code&gt; in the app. For example, if your PC's IP is &lt;code&gt;192.168.1.2&lt;/code&gt;, you'd type in &lt;code&gt;http://192.168.1.2:3000/upload&lt;/code&gt;. After that, press the &lt;code&gt;+&lt;/code&gt; icon, pick an image, and you'll see the Node script will print out a message like &lt;code&gt;Received image_picker&amp;amp;lt;gibberish&amp;amp;gt;.jpg&lt;/code&gt;. By opening the &lt;code&gt;uploads&lt;/code&gt; subdirectory in the directory where you have the back-end Node script, you'll find a file called &lt;code&gt;image_picker&amp;amp;lt;gibberish&amp;amp;gt;.jpg&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;I hope you found this tutorial useful and I invite you to tell me what topic I should cover next.&lt;br&gt;
&lt;/p&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

</description>
      <category>android</category>
      <category>ios</category>
      <category>dart</category>
      <category>node</category>
    </item>
    <item>
      <title>The Early Adopter Conundrum and Reacting to Comments</title>
      <dc:creator>Carmine Zaccagnino</dc:creator>
      <pubDate>Wed, 25 Dec 2019 00:25:44 +0000</pubDate>
      <link>https://forem.com/carminezacc/the-early-adopter-conundrum-and-reacting-to-comments-l8m</link>
      <guid>https://forem.com/carminezacc/the-early-adopter-conundrum-and-reacting-to-comments-l8m</guid>
      <description>&lt;p&gt;&lt;em&gt;When you love new stuff but don't really &lt;br&gt;
 want to lose old stuff you write this kind of stuff. It's about tech stuff that's old and tech stuff that's new.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;If you asked me a month ago, the term &lt;em&gt;early adopter&lt;/em&gt; would have been a term I could identify myself with, especially when it comes to technology and computing.&lt;/p&gt;

&lt;p&gt;For example, as is evident if you read any amount of the stuff I write, I'm a big proponent of &lt;a href="https://carmine.dev/posts/flutterdesktopweb/"&gt;Flutter&lt;/a&gt; as an app development framework and have been for quite some time.&lt;/p&gt;

&lt;p&gt;That's all well and good but, especially when it comes to Linux, I sometimes really like holding onto old and proven stuff. Not really on the desktop, I jumped on the Wayland bandwagon early enough and it has only caused me very minor issues in the early days and now I only go back to X.org the few (not always so few actually) times I'm lazy enough to build some GUI software I need to run as admin for it to work (I know about PolicyKit/polkit, but it's just easier to not bother with it at all when I don't have to).&lt;/p&gt;

&lt;p&gt;The fact that sometimes that can interfere with being a credible early adopter came to light when I wrote &lt;a href="https://fedoramagazine.org/make-sysadmin-work-on-fedora-easier-with-screen/"&gt;an article for the Fedora Magazine about the &lt;code&gt;screen&lt;/code&gt; command line utility&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It was on a topic among the ones they were looking for someone to write and, since I always use screen, I thought many other people may find it useful to have an article explain the most important features &lt;code&gt;screen&lt;/code&gt; offers and how to use them.&lt;/p&gt;

&lt;p&gt;A few minutes after it was online, it started getting comments on how &lt;code&gt;screen&lt;/code&gt; was outdated and &lt;code&gt;tmux&lt;/code&gt; was much better, suggesting people to forget about screen completely.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;tmux&lt;/code&gt; is newer and it's more likely to be updated in the future and it's seeing more active development, but &lt;code&gt;screen&lt;/code&gt; is still a solid option and it offers a lot of features.&lt;/p&gt;

&lt;p&gt;As one of the commenters pointed out, &lt;code&gt;tmux&lt;/code&gt; lacks (and may never have), among other things, support for terminals over serial connections, so if your backup in case you can't connect to a machine in any other way is serial knowing &lt;code&gt;screen&lt;/code&gt; may be &lt;em&gt;more&lt;/em&gt; useful to you than learning &lt;code&gt;tmux&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;But that's not even my point. Why should I have to forget &lt;code&gt;screen&lt;/code&gt; in order to learn &lt;code&gt;tmux&lt;/code&gt;? And by that I don't just mean that I can use both as the difference in feature sets makes one easier to use or better than the other depending on the circumstance. I could argue that most of the people who use &lt;code&gt;screen&lt;/code&gt; don't even have to learn &lt;code&gt;tmux&lt;/code&gt;: except for the comment section on that post, I've never heard people calling &lt;code&gt;screen&lt;/code&gt; &lt;em&gt;unstable&lt;/em&gt; and tmux is not much easier to use than it for most of what sysadmins do with &lt;code&gt;screen&lt;/code&gt;. It's always worked and it might keep working indefinitely.&lt;/p&gt;

&lt;p&gt;This begs a question though, bringing us back to the start of this post. What about the early adopter thing? Why am I bothered by people commenting on my Flutter posts on dev.to telling people they're fine using React Native?&lt;/p&gt;

&lt;p&gt;It's because they're telling people who want to learn Flutter not to do it because they are too lazy to even learn the basics of Flutter themselves. They're saying Flutter is going to fail. I'm not saying any of that about tmux. I'm not doing any of that. Before this post, I haven't even written about tmux anywhere: I actually &lt;em&gt;use it&lt;/em&gt;. Not as much as screen, though.&lt;/p&gt;

&lt;p&gt;I'm not hating on any technology (publicly, at least, I privately express stronger opinions on &lt;em&gt;some&lt;/em&gt; software development frameworks/tools) because I don't believe it's of any benefit to society for me to tell you to ignore X and Y: I want to tell you all how amazing Flutter is and that's all.&lt;/p&gt;

&lt;p&gt;I've got to be clear on this, though: with this post I don't actually mean to say those comments on my posts telling me how much of a fool I am for being a fan of some old or new technology shouldn't exist. I love answering them and would much prefer a civil back-and-forth to a single inflammatory comment with no follow-up.&lt;/p&gt;

&lt;p&gt;That said, if anyone's reading around the time I'm writing this, I wish all of you will be able to work with whatever technology you prefer, perhaps learn something new and exciting, and reach your goals in the coming year 2020. &lt;/p&gt;

</description>
      <category>linux</category>
      <category>android</category>
      <category>ios</category>
      <category>writing</category>
    </item>
    <item>
      <title>Google's Flutter Framework Could Change Software Forever by Bridging Mobile, Desktop, Web and Embedded</title>
      <dc:creator>Carmine Zaccagnino</dc:creator>
      <pubDate>Mon, 18 Nov 2019 17:45:03 +0000</pubDate>
      <link>https://forem.com/carminezacc/google-s-flutter-framework-could-change-software-forever-by-bridging-mobile-desktop-web-and-embedded-563j</link>
      <guid>https://forem.com/carminezacc/google-s-flutter-framework-could-change-software-forever-by-bridging-mobile-desktop-web-and-embedded-563j</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rx4EsWMI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://venturebeat.com/wp-content/uploads/2019/05/flutter-mobile-desktop-web-embedded.png%3Fw%3D578%26strip%3Dall" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rx4EsWMI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://venturebeat.com/wp-content/uploads/2019/05/flutter-mobile-desktop-web-embedded.png%3Fw%3D578%26strip%3Dall" alt="" width="578" height="289"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Google is known for moonshot projects. Often they're just that, without much hope of being brought to fruition in the near future. But Flutter is not one of those: it's here now and it works, wonderfully.&lt;/p&gt;

&lt;h1&gt;
  
  
  How Flutter Was Born: Bridging Mobile Platforms
&lt;/h1&gt;

&lt;p&gt;Flutter was released back in 2017 as a mobile development framework aiming to seamlessly bridge Android and iOS development without taking away any control over the hardware and low-level operating system features from the hands of the software developer, like many other frameworks do. It got lots of attention because Google showed impressive performance results, which are achieved thanks to the use of a low-level rendering engine that doesn't rely on the operating system's native interface elements like similar technologies such as Facebook's React Native do.&lt;/p&gt;

&lt;p&gt;It also got so much attention because it is being pointed to as the primary way of developing apps for Google's upcoming Fuchsia OS, which is set to replace Google's current operating systems. Developers also loved the top-notch developer tools allowing, among other things, to instantly preview the result of changes to the code without having to compile the app.&lt;/p&gt;

&lt;p&gt;In addition to being one of the main topics of many conferences dedicated to Dart, the Google-developed programming language used to develop Flutter apps, Flutter has been discussed, presented and advertised for a significant amount of time at Google I/O ever since Flutter's initial release in 2017, and we saw that especially in 2018, when Flutter was really being pushed by Google in anticipation of its 1.0 release in late 2018.&lt;/p&gt;

&lt;h1&gt;
  
  
  Leaping into the Future: Bridging Desktop, Mobile, Web and Embedded
&lt;/h1&gt;

&lt;p&gt;Google I/O 2019 went one step further: experimental support for desktop and web platforms was released, setting forward a vision for a world in which a piece of software doesn't have to be exclusive to one platform: it doesn't matter what platform you need to support if Flutter is powering your app: it doesn’t matter whether they’re phones, tablets, computers, TVs or embedded devices.&lt;/p&gt;

&lt;h2&gt;
  
  
  Notable Examples of Flutter Use
&lt;/h2&gt;

&lt;p&gt;Flutter is not just a big tech preview: it is being used in production today by big companies. Google themselves recently released the official app for Google Stadia, their well-known upcoming game streaming platform. Google also lists companies such as eBay, BMW, AliBaba, Tencent and other companies worth several billion dollars as Flutter users and one of the early adopters of Flutter in early 2018 was the Hamilton musical's app.&lt;/p&gt;

&lt;p&gt;Away from mobile platforms, "The New York Times" has built some of its web-based digital puzzles in Flutter, that you can see at &lt;a href="https://www.nytimes.com/games/prototype/kenken"&gt;this link&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  Why Flutter Is So Important
&lt;/h1&gt;

&lt;p&gt;Flutter is reality and it ought to be exciting for everyone: it could be about to bring down the last of the barriers stopping us from forgetting about the underlying interface entirely and think of applications in a way that is only dependent on the choices of the programmer and the requests of the users.&lt;/p&gt;

&lt;h2&gt;
  
  
  What You Can Do With It
&lt;/h2&gt;

&lt;p&gt;You might be wondering what exactly you can expect to be built with it. The answer can be found in more than one way: the first is by taking an inductive approach, looking at what has been built with Flutter.&lt;/p&gt;

&lt;p&gt;The most obvious example is something like the Hamilton app I mentioned above as the first major app using Flutter because it’s what most people think of when talking about a typical Flutter app. It’s an app that takes up-to-date information from the Internet and shows the information to the user with an unique aesthetic style in multiple layers, mixing everything from news-like sections to trivia quizzes.&lt;/p&gt;

&lt;p&gt;This is a mix of some of the most common features in mobile apps, but we can highlight Flutter’s flexibility further: it has control over the screen, so games with custom graphics and animations (like the New York Times puzzle linked above) can be built with it, with the same framework that implements easy-to-use classes for all of the components of Material Design and the iOS design language.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Low-Level Interfaces: C++, Swift/Objective-C and Java/Kotlin
&lt;/h3&gt;

&lt;p&gt;So Flutter can do anything visually. But we haven't talked about what it can do with the hardware and low-level OS interfaces. To find that out, we are going to take the deductive approach.&lt;/p&gt;

&lt;p&gt;The short answer is: anything a native app can do, and the reason for that is that Android Flutter apps can run Java/Kotlin or native C++ code just like regular Android SDK apps, Flutter iOS or macOS apps can run native Swift or Objective-C code and Linux apps can run native C++.&lt;/p&gt;

&lt;p&gt;To any programmer, this simply means that the app has full access to the device's capabilities. An example of that is a project of mine that aims to build a Flutter app that can manage filesystems on Linux by interfacing with Stratis, a Red Hat-developed storage management utility.&lt;/p&gt;

&lt;p&gt;Flutter is even starting to be considered by Linux GUI developers as a potential solution to the inconsistency among different desktop environments, and the people in charge of putting together Linux distributions are taking note and starting to consider putting some effort into making Flutter desktop support even better.&lt;/p&gt;

&lt;h1&gt;
  
  
  Looking Onward
&lt;/h1&gt;

&lt;p&gt;Flutter's unparalleled flexibility means there will be no duplication of effort in software development teams, increasing their productivity and eliminating any feature gap between versions of the same app developed for different platforms.&lt;/p&gt;

&lt;p&gt;This is revolutionary and is already taking over market share in the mobile world, all that’s left to see is whether it can adapt and succeed on the other platforms, but with Google behind it and after seeing how many companies are investing heavily into it, it looks like it will change the way software is developed, making it easier for everyone to find high-quality software for any platform, be it a phone, a tablet, a computer or even a completely different kind of device, such as a car’s infotainment system, a smart home device or a smart TV. &lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;        &amp;lt;img src="https://imagery.pragprog.com/products/578/czflutr_xlargebeta.jpg?1560360708" alt="..."&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;      &amp;lt;div class="col-md-8 text-center text-md-left"&amp;gt;
        &amp;lt;h3 class="mt-0"&amp;gt;Get a Complete 300-page Introduction to Flutter!&amp;lt;/h3&amp;gt;
        &amp;lt;p&amp;gt;I’m so excited about Flutter I wrote a book about it called Programming Flutter with the Pragmatic Bookshelf.&amp;lt;/p&amp;gt;

      &amp;lt;a href="https://pragprog.com/book/czflutr/programming-flutter"&amp;gt;Check it Out Here&amp;lt;/a&amp;gt;

      &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

</description>
      <category>android</category>
      <category>ios</category>
      <category>opensource</category>
      <category>dart</category>
    </item>
  </channel>
</rss>
