{"componentChunkName":"component---src-templates-blog-list-template-js","path":"/engineering/25","result":{"data":{"allMarkdownRemark":{"edges":[{"node":{"excerpt":"Motivation Maps are an effective, intuitive way to understand data in some use-cases. Interactive web maps can help us visualize the data…","fields":{"slug":"/engineering/visualizing-data-using-leaflet-and-netlify/"},"html":"<h2 id=\"motivation\" style=\"position:relative;\"><a href=\"#motivation\" aria-label=\"motivation permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Motivation</h2>\n<p>Maps are an effective, intuitive way to understand data in some use-cases. Interactive web maps can help us visualize the data better and derive better insights.</p>\n<p>Different map visualizations can highlight different aspects of a dataset. Heatmaps, Choropleth maps and Clustering maps are frequently used for this purpose.</p>\n<p>In this blog, I shall go over using a powerful JavaScript library to build a web map and deploy it on Netlify.</p>\n<h2 id=\"using-leaflet\" style=\"position:relative;\"><a href=\"#using-leaflet\" aria-label=\"using leaflet permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Using Leaflet</h2>\n<p>The Leaflet is a great library for implementing interactive web maps as it provides many UI features, like smooth canvas panning, zooming, mouse events, and all the involved work in animations, which one would otherwise have to implement from scratch.</p>\n<blockquote>\n<p>Leaflet is the leading open-source JavaScript library for mobile-friendly interactive maps. Weighing just about 39 KB of JS, it has all the mapping features most developers ever need.</p>\n<p><em>source: leafletjs.com</em></p>\n</blockquote>\n<p><img src=\"/7efc920eb3f4c7321711cf133a19b18c/leaflet.webp\" alt=\"Leaflet Logo\"></p>\n<p>We can include Leaflet in our application by including the CSS stylesheet and the JS file from the unpkg CDN. Let's start building the application by starting with the following code at the project root. Create a file named <code>index.html</code> and put the following markup in it. The map shall be rendered in <code>div#mapid</code>.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"html\" data-index=\"0\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">&lt;!--</span><span class=\"mtk12\">index</span><span class=\"mtk1\">.</span><span class=\"mtk12\">html</span><span class=\"mtk1\">--&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">&lt;!</span><span class=\"mtk12\">DOCTYPE</span><span class=\"mtk1\"> </span><span class=\"mtk12\">html</span><span class=\"mtk1\">&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">html</span><span class=\"mtk1\"> </span><span class=\"mtk12\">lang</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;en&quot;</span><span class=\"mtk17\">&gt;</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">head</span><span class=\"mtk17\">&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">meta</span><span class=\"mtk1\"> </span><span class=\"mtk12\">charset</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;UTF-8&quot;</span><span class=\"mtk17\">&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">meta</span><span class=\"mtk1\"> </span><span class=\"mtk12\">name</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;viewport&quot;</span><span class=\"mtk1\"> </span><span class=\"mtk12\">content</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;width=device-width, initial-scale=1.0&quot;</span><span class=\"mtk17\">&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">title</span><span class=\"mtk17\">&gt;</span><span class=\"mtk1\">MapViz</span><span class=\"mtk17\">&lt;/</span><span class=\"mtk4\">title</span><span class=\"mtk17\">&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">link</span><span class=\"mtk1\"> </span><span class=\"mtk12\">rel</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;stylesheet&quot;</span><span class=\"mtk1\"> </span><span class=\"mtk12\">href</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;https://unpkg.com/leaflet/dist/leaflet.css&quot;</span><span class=\"mtk1\"> </span><span class=\"mtk17\">/&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">style</span><span class=\"mtk17\">&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">      #mapid </span><span class=\"mtk4\">{</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk12\">position</span><span class=\"mtk1\">: </span><span class=\"mtk12\">fixed</span><span class=\"mtk1\">;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk12\">width</span><span class=\"mtk1\">: </span><span class=\"mtk7\">100</span><span class=\"mtk1\">%;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk12\">height</span><span class=\"mtk1\">: </span><span class=\"mtk7\">100</span><span class=\"mtk1\">%;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk12\">top</span><span class=\"mtk1\">: </span><span class=\"mtk7\">0</span><span class=\"mtk1\">;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk12\">left</span><span class=\"mtk1\">: </span><span class=\"mtk7\">0</span><span class=\"mtk1\">;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">      </span><span class=\"mtk4\">}</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk17\">&lt;/</span><span class=\"mtk4\">style</span><span class=\"mtk17\">&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk17\">&lt;/</span><span class=\"mtk4\">head</span><span class=\"mtk17\">&gt;</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">body</span><span class=\"mtk17\">&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">div</span><span class=\"mtk1\"> </span><span class=\"mtk12\">id</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;mapid&quot;</span><span class=\"mtk17\">&gt;&lt;/</span><span class=\"mtk4\">div</span><span class=\"mtk17\">&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">script</span><span class=\"mtk1\"> </span><span class=\"mtk12\">defer</span><span class=\"mtk1\"> </span><span class=\"mtk12\">src</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;https://unpkg.com/leaflet/dist/leaflet.js&quot;</span><span class=\"mtk17\">&gt;&lt;/</span><span class=\"mtk4\">script</span><span class=\"mtk17\">&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk17\">&lt;/</span><span class=\"mtk4\">body</span><span class=\"mtk17\">&gt;</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk17\">&lt;/</span><span class=\"mtk4\">html</span><span class=\"mtk17\">&gt;</span></span></code></pre>\n<p>Now, we gather a link to the GeoJSON file for metro stations in Washington D.C., that we shall be visualizing, from the <a href=\"https://docs.mapbox.com/help/glossary/geojson/\">MapBox documentation</a>. It should look similar to the following:</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"\" data-index=\"1\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">https://docs.mapbox.com/help/data/stations.geojson</span></code></pre>\n<p>Create a new JavaScript file named <code>script.js</code> in the same directory as the HTML file. Include this file in the web page by adding the following line to it.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"html\" data-index=\"2\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">&lt;!--</span><span class=\"mtk12\">index</span><span class=\"mtk1\">.</span><span class=\"mtk12\">html</span><span class=\"mtk1\">--&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  ...</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">body</span><span class=\"mtk17\">&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    ...</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">script</span><span class=\"mtk1\"> </span><span class=\"mtk12\">defer</span><span class=\"mtk1\"> </span><span class=\"mtk12\">src</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;https://unpkg.com/leaflet/dist/leaflet.js&quot;</span><span class=\"mtk17\">&gt;&lt;/</span><span class=\"mtk4\">script</span><span class=\"mtk17\">&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">script</span><span class=\"mtk1\"> </span><span class=\"mtk12\">src</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;script.js&quot;</span><span class=\"mtk17\">&gt;&lt;/</span><span class=\"mtk4\">script</span><span class=\"mtk17\">&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk17\">&lt;/</span><span class=\"mtk4\">body</span><span class=\"mtk17\">&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  ...</span></span></code></pre>\n<p>In <code>script.js</code>, we can use the Fetch API to make an AJAX request and get the data as a response to a <code>GET</code> request using promises and take a look at what we are dealing with.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"js\" data-index=\"3\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk3\">// script.js</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">let</span><span class=\"mtk1\"> </span><span class=\"mtk12\">data</span><span class=\"mtk1\"> = {};</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">const</span><span class=\"mtk1\"> </span><span class=\"mtk12\">dataUrl</span><span class=\"mtk1\"> = </span><span class=\"mtk8\">&#39;https://cors-anywhere.herokuapp.com/https://docs.mapbox.com/help/data/stations.geojson&#39;</span><span class=\"mtk1\">;</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk11\">fetch</span><span class=\"mtk1\">(</span><span class=\"mtk12\">dataUrl</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  .</span><span class=\"mtk11\">then</span><span class=\"mtk1\">(</span><span class=\"mtk12\">response</span><span class=\"mtk1\"> </span><span class=\"mtk4\">=&gt;</span><span class=\"mtk1\"> </span><span class=\"mtk12\">response</span><span class=\"mtk1\">.</span><span class=\"mtk11\">json</span><span class=\"mtk1\">())</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  .</span><span class=\"mtk11\">then</span><span class=\"mtk1\">(</span><span class=\"mtk12\">data</span><span class=\"mtk1\"> </span><span class=\"mtk4\">=&gt;</span><span class=\"mtk1\"> </span><span class=\"mtk10\">console</span><span class=\"mtk1\">.</span><span class=\"mtk11\">log</span><span class=\"mtk1\">(</span><span class=\"mtk12\">data</span><span class=\"mtk1\">))</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  .</span><span class=\"mtk11\">catch</span><span class=\"mtk1\">(</span><span class=\"mtk12\">err</span><span class=\"mtk1\"> </span><span class=\"mtk4\">=&gt;</span><span class=\"mtk1\"> </span><span class=\"mtk10\">console</span><span class=\"mtk1\">.</span><span class=\"mtk11\">error</span><span class=\"mtk1\">(</span><span class=\"mtk12\">err</span><span class=\"mtk1\">));</span></span></code></pre>\n<p>We can take a look at the data in the Developer Console. We observe that it is a JavaScript object. The various properties associated with the data can be viewed by checking the individual features.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"js\" data-index=\"4\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">{</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk8\">&quot;type&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;FeatureCollection&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk8\">&quot;features&quot;</span><span class=\"mtk1\">: [</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    ...</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">      </span><span class=\"mtk8\">&quot;geometry&quot;</span><span class=\"mtk12\">:</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk8\">&quot;type&quot;</span><span class=\"mtk12\">:</span><span class=\"mtk1\"> </span><span class=\"mtk8\">&quot;Point&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk8\">&quot;coordinates&quot;</span><span class=\"mtk12\">:</span><span class=\"mtk1\"> [-</span><span class=\"mtk7\">76.9750541388</span><span class=\"mtk1\">, </span><span class=\"mtk7\">38.8410857803</span><span class=\"mtk1\">]</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">      },</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">      </span><span class=\"mtk8\">&quot;type&quot;</span><span class=\"mtk12\">:</span><span class=\"mtk1\"> </span><span class=\"mtk8\">&quot;Feature&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">      </span><span class=\"mtk8\">&quot;properties&quot;</span><span class=\"mtk12\">:</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk8\">&quot;description&quot;</span><span class=\"mtk12\">:</span><span class=\"mtk1\"> </span><span class=\"mtk8\">&quot;Southern Ave&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk8\">&quot;marker-symbol&quot;</span><span class=\"mtk12\">:</span><span class=\"mtk1\"> </span><span class=\"mtk8\">&quot;rail-metro&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk8\">&quot;title&quot;</span><span class=\"mtk12\">:</span><span class=\"mtk1\"> </span><span class=\"mtk8\">&quot;Southern Ave&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk8\">&quot;url&quot;</span><span class=\"mtk12\">:</span><span class=\"mtk1\"> </span><span class=\"mtk8\">&quot;http://www.wmata.com/rider_tools/pids/showpid.cfm?station_id=107&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk8\">&quot;lines&quot;</span><span class=\"mtk12\">:</span><span class=\"mtk1\"> [</span><span class=\"mtk8\">&quot;Green&quot;</span><span class=\"mtk1\">],</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk8\">&quot;address&quot;</span><span class=\"mtk12\">:</span><span class=\"mtk1\"> </span><span class=\"mtk8\">&quot;1411 Southern Avenue, Temple Hills, MD 20748&quot;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">      }</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    },</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    ...</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  ]</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">}</span></span></code></pre>\n<p>Before we begin adding the layers to our map, we need to instantiate a Leaflet <code>map</code> object with the DOM ID of the map container and center it on our point of interest at a specified initial zoom level.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"js\" data-index=\"5\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk4\">const</span><span class=\"mtk1\"> </span><span class=\"mtk12\">map</span><span class=\"mtk1\"> = </span><span class=\"mtk12\">L</span><span class=\"mtk1\">.</span><span class=\"mtk11\">map</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&#39;mapid&#39;</span><span class=\"mtk1\">).</span><span class=\"mtk11\">setView</span><span class=\"mtk1\">([</span><span class=\"mtk7\">38.8977</span><span class=\"mtk1\">, -</span><span class=\"mtk7\">77.0365</span><span class=\"mtk1\">], </span><span class=\"mtk7\">15</span><span class=\"mtk1\">);</span></span></code></pre>\n<p>As we need a base map (the base layer) for our map, we can use one that is provided by Mapbox. In order to use that, you need a Mapbox API access token that you can create on <a href=\"https://account.mapbox.com/\">their portal</a>.</p>\n<p>The following snippet instantiates a <code>tileLayer</code> object and adds it to our map:</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"js\" data-index=\"6\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk12\">L</span><span class=\"mtk1\">.</span><span class=\"mtk11\">tileLayer</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&#39;https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}?access_token={accessToken}&#39;</span><span class=\"mtk1\">, {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">attribution:</span><span class=\"mtk1\"> </span><span class=\"mtk8\">&#39;Map data &copy; &lt;a href=&quot;https://www.openstreetmap.org/&quot;&gt;OpenStreetMap&lt;/a&gt; contributors, &lt;a href=&quot;https://creativecommons.org/licenses/by-sa/2.0/&quot;&gt;CC-BY-SA&lt;/a&gt;, Imagery © &lt;a href=&quot;https://www.mapbox.com/&quot;&gt;Mapbox&lt;/a&gt;&#39;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">maxZoom:</span><span class=\"mtk1\"> </span><span class=\"mtk7\">18</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">id:</span><span class=\"mtk1\"> </span><span class=\"mtk8\">&#39;mapbox/streets-v11&#39;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">tileSize:</span><span class=\"mtk1\"> </span><span class=\"mtk7\">512</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">zoomOffset:</span><span class=\"mtk1\"> -</span><span class=\"mtk7\">1</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">accessToken:</span><span class=\"mtk1\"> </span><span class=\"mtk8\">&#39;your_mapbox_api_access_token&#39;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">}).</span><span class=\"mtk11\">addTo</span><span class=\"mtk1\">(</span><span class=\"mtk12\">map</span><span class=\"mtk1\">);</span></span></code></pre>\n<p>We can use the following snippet to parse the GeoJSON and add it to the map.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"js\" data-index=\"7\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk12\">L</span><span class=\"mtk1\">.</span><span class=\"mtk11\">geoJSON</span><span class=\"mtk1\">(</span><span class=\"mtk12\">data</span><span class=\"mtk1\">).</span><span class=\"mtk11\">addTo</span><span class=\"mtk1\">(</span><span class=\"mtk12\">map</span><span class=\"mtk1\">);</span></span></code></pre>\n<p>Replace the code in <code>script.js</code> with the following, and refresh the web page:</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"js\" data-index=\"8\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk4\">let</span><span class=\"mtk1\"> </span><span class=\"mtk12\">data</span><span class=\"mtk1\"> = {};</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">const</span><span class=\"mtk1\"> </span><span class=\"mtk12\">dataUrl</span><span class=\"mtk1\"> = </span><span class=\"mtk8\">&#39;https://cors-anywhere.herokuapp.com/https://docs.mapbox.com/help/data/stations.geojson&#39;</span><span class=\"mtk1\">;</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">const</span><span class=\"mtk1\"> </span><span class=\"mtk12\">map</span><span class=\"mtk1\"> = </span><span class=\"mtk12\">L</span><span class=\"mtk1\">.</span><span class=\"mtk11\">map</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&#39;mapid&#39;</span><span class=\"mtk1\">).</span><span class=\"mtk11\">setView</span><span class=\"mtk1\">([</span><span class=\"mtk7\">38.8977</span><span class=\"mtk1\">, -</span><span class=\"mtk7\">77.0365</span><span class=\"mtk1\">], </span><span class=\"mtk7\">15</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk12\">L</span><span class=\"mtk1\">.</span><span class=\"mtk11\">tileLayer</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&#39;https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}?access_token={accessToken}&#39;</span><span class=\"mtk1\">, {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">attribution:</span><span class=\"mtk1\"> </span><span class=\"mtk8\">&#39;Map data &copy; &lt;a href=&quot;https://www.openstreetmap.org/&quot;&gt;OpenStreetMap&lt;/a&gt; contributors, &lt;a href=&quot;https://creativecommons.org/licenses/by-sa/2.0/&quot;&gt;CC-BY-SA&lt;/a&gt;, Imagery © &lt;a href=&quot;https://www.mapbox.com/&quot;&gt;Mapbox&lt;/a&gt;&#39;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">maxZoom:</span><span class=\"mtk1\"> </span><span class=\"mtk7\">18</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">id:</span><span class=\"mtk1\"> </span><span class=\"mtk8\">&#39;mapbox/streets-v11&#39;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">tileSize:</span><span class=\"mtk1\"> </span><span class=\"mtk7\">512</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">zoomOffset:</span><span class=\"mtk1\"> -</span><span class=\"mtk7\">1</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">accessToken:</span><span class=\"mtk1\"> </span><span class=\"mtk8\">&#39;your_mapbox_api_access_token&#39;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">}).</span><span class=\"mtk11\">addTo</span><span class=\"mtk1\">(</span><span class=\"mtk12\">map</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk11\">fetch</span><span class=\"mtk1\">(</span><span class=\"mtk12\">dataUrl</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  .</span><span class=\"mtk11\">then</span><span class=\"mtk1\">(</span><span class=\"mtk12\">response</span><span class=\"mtk1\"> </span><span class=\"mtk4\">=&gt;</span><span class=\"mtk1\"> </span><span class=\"mtk12\">response</span><span class=\"mtk1\">.</span><span class=\"mtk11\">json</span><span class=\"mtk1\">())</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  .</span><span class=\"mtk11\">then</span><span class=\"mtk1\">(</span><span class=\"mtk12\">data</span><span class=\"mtk1\"> </span><span class=\"mtk4\">=&gt;</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk12\">L</span><span class=\"mtk1\">.</span><span class=\"mtk11\">geoJSON</span><span class=\"mtk1\">(</span><span class=\"mtk12\">data</span><span class=\"mtk1\">).</span><span class=\"mtk11\">addTo</span><span class=\"mtk1\">(</span><span class=\"mtk12\">map</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  })</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  .</span><span class=\"mtk11\">catch</span><span class=\"mtk1\">(</span><span class=\"mtk12\">err</span><span class=\"mtk1\"> </span><span class=\"mtk4\">=&gt;</span><span class=\"mtk1\"> </span><span class=\"mtk10\">console</span><span class=\"mtk1\">.</span><span class=\"mtk11\">error</span><span class=\"mtk1\">(</span><span class=\"mtk12\">err</span><span class=\"mtk1\">));</span></span></code></pre>\n<p>As the dataset contains <code>Point</code> features, markers will be added at the respective coordinates. Our web page will now look like the following:</p>\n<p><img src=\"/c9f8918ca84e4084cdde9b01eb30f2ad/mapInitial.webp\" alt=\"Map with Markers\"></p>\n<p>We can show tooltips upon clicking on the markers by modifying the code as follows, to include some custom HTML using the properties in the feature, in the popup:</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"js\" data-index=\"9\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk3\">// script.js</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  ...</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk11\">fetch</span><span class=\"mtk1\">(</span><span class=\"mtk12\">dataUrl</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  .</span><span class=\"mtk11\">then</span><span class=\"mtk1\">(</span><span class=\"mtk12\">response</span><span class=\"mtk1\"> </span><span class=\"mtk4\">=&gt;</span><span class=\"mtk1\"> </span><span class=\"mtk12\">response</span><span class=\"mtk1\">.</span><span class=\"mtk11\">json</span><span class=\"mtk1\">())</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  .</span><span class=\"mtk11\">then</span><span class=\"mtk1\">(</span><span class=\"mtk12\">data</span><span class=\"mtk1\"> </span><span class=\"mtk4\">=&gt;</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk12\">L</span><span class=\"mtk1\">.</span><span class=\"mtk11\">geoJSON</span><span class=\"mtk1\">(</span><span class=\"mtk12\">data</span><span class=\"mtk1\">, {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">      </span><span class=\"mtk11\">onEachFeature</span><span class=\"mtk12\">:</span><span class=\"mtk1\"> </span><span class=\"mtk4\">function</span><span class=\"mtk1\"> (</span><span class=\"mtk12\">feature</span><span class=\"mtk1\">, </span><span class=\"mtk12\">layer</span><span class=\"mtk1\">) {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk12\">layer</span><span class=\"mtk1\">.</span><span class=\"mtk11\">bindPopup</span><span class=\"mtk1\">(</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">          </span><span class=\"mtk8\">&#39;&lt;h4&gt;&#39;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">          + </span><span class=\"mtk12\">feature</span><span class=\"mtk1\">.</span><span class=\"mtk12\">properties</span><span class=\"mtk1\">.</span><span class=\"mtk12\">title</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">          + </span><span class=\"mtk8\">&#39;&lt;/h4&gt;&#39;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">          + </span><span class=\"mtk8\">&#39;&lt;p&gt;&#39;</span><span class=\"mtk1\"> </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">          +  </span><span class=\"mtk12\">feature</span><span class=\"mtk1\">.</span><span class=\"mtk12\">properties</span><span class=\"mtk1\">.</span><span class=\"mtk12\">address</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">          + </span><span class=\"mtk8\">&#39;&lt;/p&gt;&#39;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        );</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">      }</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    }).</span><span class=\"mtk11\">addTo</span><span class=\"mtk1\">(</span><span class=\"mtk12\">map</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  })</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  .</span><span class=\"mtk11\">catch</span><span class=\"mtk1\">(</span><span class=\"mtk12\">err</span><span class=\"mtk1\"> </span><span class=\"mtk4\">=&gt;</span><span class=\"mtk1\"> </span><span class=\"mtk10\">console</span><span class=\"mtk1\">.</span><span class=\"mtk11\">error</span><span class=\"mtk1\">(</span><span class=\"mtk12\">err</span><span class=\"mtk1\">));</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  ...</span></span></code></pre>\n<p>Uupon clicking any marker, we will now see the following popup:</p>\n<p><img src=\"/d9a6e0e68d17fb7cdd0e12d87710ef35/mapPopup.webp\" alt=\"Map with Popups\"></p>\n<p>We can also customize the marker icon using the <code>pointToLayer</code> option of the <code>geoJSON</code> constructor as follows:</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"js\" data-index=\"10\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk3\">// scripts.js</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  ...</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">L</span><span class=\"mtk1\">.</span><span class=\"mtk11\">geoJSON</span><span class=\"mtk1\">(</span><span class=\"mtk12\">data</span><span class=\"mtk1\">, {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">      </span><span class=\"mtk11\">pointToLayer</span><span class=\"mtk12\">:</span><span class=\"mtk1\"> </span><span class=\"mtk4\">function</span><span class=\"mtk1\"> (</span><span class=\"mtk12\">feature</span><span class=\"mtk1\">, </span><span class=\"mtk12\">coords</span><span class=\"mtk1\">) {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> </span><span class=\"mtk12\">L</span><span class=\"mtk1\">.</span><span class=\"mtk11\">marker</span><span class=\"mtk1\">(</span><span class=\"mtk12\">coords</span><span class=\"mtk1\">, {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">          </span><span class=\"mtk12\">icon:</span><span class=\"mtk1\"> </span><span class=\"mtk4\">new</span><span class=\"mtk1\"> </span><span class=\"mtk10\">L</span><span class=\"mtk1\">.</span><span class=\"mtk10\">Icon</span><span class=\"mtk1\">({</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk12\">iconSize:</span><span class=\"mtk1\"> [</span><span class=\"mtk7\">30</span><span class=\"mtk1\">, </span><span class=\"mtk7\">30</span><span class=\"mtk1\">],</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk12\">iconAnchor:</span><span class=\"mtk1\"> [</span><span class=\"mtk7\">15</span><span class=\"mtk1\">, </span><span class=\"mtk7\">15</span><span class=\"mtk1\">],</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk12\">popupAnchor:</span><span class=\"mtk1\"> [</span><span class=\"mtk7\">1</span><span class=\"mtk1\">, -</span><span class=\"mtk7\">24</span><span class=\"mtk1\">],</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk12\">iconUrl:</span><span class=\"mtk1\"> </span><span class=\"mtk8\">&#39;https://cdn.iconscout.com/icon/free/png-256/metro-subway-underground-train-railway-engine-emoj-symbol-30744.webp&#39;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">          })</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        });</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">      },</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">      </span><span class=\"mtk11\">onEachFeature</span><span class=\"mtk12\">:</span><span class=\"mtk1\"> </span><span class=\"mtk4\">function</span><span class=\"mtk1\"> (</span><span class=\"mtk12\">feature</span><span class=\"mtk1\">, </span><span class=\"mtk12\">layer</span><span class=\"mtk1\">) {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk12\">layer</span><span class=\"mtk1\">.</span><span class=\"mtk11\">bindPopup</span><span class=\"mtk1\">(</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">          </span><span class=\"mtk8\">&#39;&lt;h4&gt;&#39;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">          + </span><span class=\"mtk12\">feature</span><span class=\"mtk1\">.</span><span class=\"mtk12\">properties</span><span class=\"mtk1\">.</span><span class=\"mtk12\">title</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">          + </span><span class=\"mtk8\">&#39;&lt;/h4&gt;&#39;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">          + </span><span class=\"mtk8\">&#39;&lt;p&gt;&#39;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">          + </span><span class=\"mtk12\">feature</span><span class=\"mtk1\">.</span><span class=\"mtk12\">properties</span><span class=\"mtk1\">.</span><span class=\"mtk12\">address</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">          + </span><span class=\"mtk8\">&#39;&lt;/p&gt;&#39;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        );</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">      }</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    }).</span><span class=\"mtk11\">addTo</span><span class=\"mtk1\">(</span><span class=\"mtk12\">map</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    ...</span></span></code></pre>\n<p>Our updated web page will now look like the following:</p>\n<p><img src=\"/d40f991754a9a42ad009adce6c048fe1/mapIcon.webp\" alt=\"Map with Custom Icon\"></p>\n<p>Now, we can move on to deploy this web page on Netlify.</p>\n<h2 id=\"deploying-on-netlify\" style=\"position:relative;\"><a href=\"#deploying-on-netlify\" aria-label=\"deploying on netlify permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Deploying on Netlify</h2>\n<p>Netlify is an awesome platform to host your web applications. It also offers many other features such as serverless functions.</p>\n<p><img src=\"/ff0c5f52e4df420ed6d72e2e1aadcc07/netlify.webp\" alt=\"Netlify Logo\"></p>\n<p>Once you have pushed your web page to a Git repository, hosted either on GitHub, GitLab or BitBucket, navigate to <a href=\"https://app.netlify.com\">Netlify</a> and click on the <strong>New Site from Git</strong> button.</p>\n<p><img src=\"/0a99824fbd69eb99c04d16316448f05b/netlifySigningUp.webp\" alt=\"Starting with Netlify\"></p>\n<p>Next, select your Git provider and your repository:</p>\n<p><img src=\"/cd777ecec352e4ac8c0aa3849788b084/gitRepo.webp\" alt=\"Git Provider Selection\"></p>\n<p><img src=\"/9b6e31356e117401e9c79c2d54e36047/repoSelection.webp\" alt=\"Git Respository Selection\"></p>\n<p>Go ahead with the defaults, and now your site shall be published on Netlify, and all future pushes should result in a Netlify deployment:</p>\n<p><img src=\"/9875f707227b97720d89714f152c4b92/deployment.webp\" alt=\"Netlify Deployment\"></p>\n<p>Nice! Now we have a web map, even though a very basic one, live! Check out the <a href=\"https://leafletjs.com/reference.html\">Leaflet documentation</a> for more!</p>\n<h2 id=\"source-code\" style=\"position:relative;\"><a href=\"#source-code\" aria-label=\"source code permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Source Code</h2>\n<p>Demonstration: <a href=\"https://priceless-poincare-9647e3.netlify.app/\">Priceless Poincare</a></p>\n<p>GitHub: <a href=\"https://github.com/sudiptog81/leaflet-netlify-starter\">leaflet netlify starter</a></p>\n<style class=\"grvsc-styles\">\n  .grvsc-container {\n    overflow: auto;\n    -webkit-overflow-scrolling: touch;\n    padding-top: 1rem;\n    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));\n    padding-bottom: 1rem;\n    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));\n    border-radius: 8px;\n    border-radius: var(--grvsc-border-radius, 8px);\n    font-feature-settings: normal;\n  }\n  \n  .grvsc-code {\n    display: inline-block;\n    min-width: 100%;\n  }\n  \n  .grvsc-line {\n    display: inline-block;\n    box-sizing: border-box;\n    width: 100%;\n    padding-left: 1.5rem;\n    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));\n    padding-right: 1.5rem;\n    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));\n  }\n  \n  .grvsc-line-highlighted {\n    background-color: var(--grvsc-line-highlighted-background-color, transparent);\n    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, transparent);\n  }\n  \n  .dark-default-dark {\n    background-color: #1E1E1E;\n    color: #D4D4D4;\n  }\n  .dark-default-dark .mtk1 { color: #D4D4D4; }\n  .dark-default-dark .mtk12 { color: #9CDCFE; }\n  .dark-default-dark .mtk17 { color: #808080; }\n  .dark-default-dark .mtk4 { color: #569CD6; }\n  .dark-default-dark .mtk8 { color: #CE9178; }\n  .dark-default-dark .mtk7 { color: #B5CEA8; }\n  .dark-default-dark .mtk3 { color: #6A9955; }\n  .dark-default-dark .mtk11 { color: #DCDCAA; }\n  .dark-default-dark .mtk10 { color: #4EC9B0; }\n  .dark-default-dark .mtk15 { color: #C586C0; }\n</style>","frontmatter":{"date":"October 14, 2020","updated_date":null,"description":"Let's visualize geospatial data on the web using Leaflet and host it on Netlify!","title":"Visualizing Data using Leaflet and Netlify","tags":["GIS","Serverless","JavaScript"],"pinned":null,"coverImage":{"childImageSharp":{"fluid":{"aspectRatio":2.0618556701030926,"src":"/static/f09ca52cdb62e663db2958fa17ee7f4a/58556/map.webp","srcSet":"/static/f09ca52cdb62e663db2958fa17ee7f4a/61e93/map.webp 200w,\n/static/f09ca52cdb62e663db2958fa17ee7f4a/1f5c5/map.webp 400w,\n/static/f09ca52cdb62e663db2958fa17ee7f4a/58556/map.webp 800w,\n/static/f09ca52cdb62e663db2958fa17ee7f4a/99238/map.webp 1200w,\n/static/f09ca52cdb62e663db2958fa17ee7f4a/42314/map.webp 1366w","sizes":"(max-width: 800px) 100vw, 800px"}}},"author":{"id":"Sudipto Ghosh","github":"sudiptog81","avatar":null}}}},{"node":{"excerpt":"Introduction The Secure Enclave is a hardware-based key manager that’s isolated from the main processor to provide an extra layer of…","fields":{"slug":"/engineering/secure-enclave-ios-app/"},"html":"<h2 id=\"introduction\" style=\"position:relative;\"><a href=\"#introduction\" aria-label=\"introduction permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Introduction</h2>\n<p>The Secure Enclave is a hardware-based key manager that’s isolated from the main processor to provide an extra layer of security. Using a secure enclave, we can create the key, securely store the key, and perform operations with the key. Thus makes it difficult for the key to be compromised. </p>\n<p>We usually save data persistently in the app using UserDefaults, Keychain, Core Data or SQLite.\nFor example, To save the session of logged in user, we save username and password. But this process puts our data at high-security risk. So it's always recommended to store sensitive data in an encrypted format. But again, it's a challenge to secure keys used in encryption/decryption.</p>\n<p><img src=\"/52c5d8e0a1d8ee7238f2080cc0689c39/image2.webp\" alt=\"Secure Enclave\"></p>\n<p>Now here <strong>Secure Enclave</strong> comes in the role. </p>\n<p>In this blog, we will use Secure Enclave to generate key pair and use those in encryption/decryption of sensitive data further.</p>\n<p>Here I will create a wrapper to generate key pair using Secure Enclave and use them to encrypt/decrypt sensitive data. And also a viewcontroller to show how to use a wrapper to get encrypted and decrypted data.\nYou may implement wrapper's methods as common methods and use wherever needed in the project. But its recommended to use a separate wrapper for handling communication with Secure Enclave.</p>\n<h2 id=\"wrapper\" style=\"position:relative;\"><a href=\"#wrapper\" aria-label=\"wrapper permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Wrapper</h2>\n<p> I have created .h and .m files named as SecEnclaveWrapper as a subclass of NSObject.\nIn .h file I am declaring function for being accessible from other classes like: </p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"objective-c\" data-index=\"0\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk3\">/**</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk3\">Return encrypted value of data using kSecKeyAlgorithmECIESEncryptionStandardX963SHA256AESGCM algo</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk3\">*/</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">- (</span><span class=\"mtk10\">NSData</span><span class=\"mtk1\"> *_Nonnull)encryptData:(</span><span class=\"mtk10\">NSData</span><span class=\"mtk1\"> *_Nonnull)data ;</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk3\">/**</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk3\">Return decryrpted data of encrypted data  using kSecKeyAlgorithmECIESEncryptionStandardX963SHA256AESGCM algo</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk3\">*/</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">- (</span><span class=\"mtk10\">NSData</span><span class=\"mtk1\"> *_Nonnull)decryptData:(</span><span class=\"mtk10\">NSData</span><span class=\"mtk1\"> *_Nonnull)data ;</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk3\">/**</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk3\">Return an initialized instance of the wrapper</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk3\">*/</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">- (</span><span class=\"mtk4\">instancetype</span><span class=\"mtk1\">)init;</span></span></code></pre>\n<p>Then in .m file, define the following methods as : </p>\n<p>The method <code>init</code> initializes and returns the object of this wrapper class. And 'encryptData' and 'decryptData' method return encrypted data and decrypted data of encrypted data, respectively.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"objective-c\" data-index=\"1\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">- (</span><span class=\"mtk4\">instancetype</span><span class=\"mtk1\">)init {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    self = [super init];</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk15\">if</span><span class=\"mtk1\">(![self lookupPublicKeyRef] || ![self lookupPrivateKeyRef])</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        [self generatePasscodeKeyPair];</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> self;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">}</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">- (</span><span class=\"mtk10\">NSData</span><span class=\"mtk1\"> *)encryptData:(</span><span class=\"mtk10\">NSData</span><span class=\"mtk1\"> *)data {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk15\">if</span><span class=\"mtk1\"> (data && </span><span class=\"mtk12\">data</span><span class=\"mtk1\">.</span><span class=\"mtk12\">length</span><span class=\"mtk1\">) {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        CFDataRef cipher = </span><span class=\"mtk11\">SecKeyCreateEncryptedData</span><span class=\"mtk1\">(publicKeyRef, kSecKeyAlgorithmECIESEncryptionStandardX963SHA256AESGCM, (CFDataRef)data, </span><span class=\"mtk4\">nil</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> (__bridge </span><span class=\"mtk10\">NSData</span><span class=\"mtk1\"> *)cipher;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    } </span><span class=\"mtk15\">else</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> </span><span class=\"mtk4\">nil</span><span class=\"mtk1\">;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    }</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">}</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">- (</span><span class=\"mtk10\">NSData</span><span class=\"mtk1\">*)decryptData:(</span><span class=\"mtk10\">NSData</span><span class=\"mtk1\"> *)data {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk15\">if</span><span class=\"mtk1\">(data && </span><span class=\"mtk12\">data</span><span class=\"mtk1\">.</span><span class=\"mtk12\">length</span><span class=\"mtk1\">){</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        CFDataRef plainData = </span><span class=\"mtk11\">SecKeyCreateDecryptedData</span><span class=\"mtk1\">(privateKeyRef, kSecKeyAlgorithmECIESEncryptionStandardX963SHA256AESGCM, (CFDataRef)data, </span><span class=\"mtk4\">nil</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">return</span><span class=\"mtk1\">  (__bridge </span><span class=\"mtk10\">NSData</span><span class=\"mtk1\"> *)plainData;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    }</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk15\">else</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> </span><span class=\"mtk4\">nil</span><span class=\"mtk1\">;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    }</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">}</span></span></code></pre>\n<p>The 'lookupPublicKeyRef' method below will lookup keychain for public key &#x26; 'lookupPrivateKeyRef' method search for the private key and return key if found.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"objective-c\" data-index=\"2\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">- (SecKeyRef) lookupPublicKeyRef</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">{</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk10\">OSStatus</span><span class=\"mtk1\"> sanityCheck = noErr;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk10\">NSData</span><span class=\"mtk1\"> *tag;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk4\">id</span><span class=\"mtk1\"> keyClass;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk15\">if</span><span class=\"mtk1\"> (publicKeyRef != </span><span class=\"mtk4\">NULL</span><span class=\"mtk1\">) {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk3\">// if already resides in memory, return</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> publicKeyRef;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    }</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    tag = [kPublicKeyName dataUsingEncoding:NSUTF8StringEncoding];</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    keyClass = (__bridge </span><span class=\"mtk4\">id</span><span class=\"mtk1\">) kSecAttrKeyClassPublic;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk10\">NSDictionary</span><span class=\"mtk1\"> *queryDict = @{</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        (__bridge </span><span class=\"mtk4\">id</span><span class=\"mtk1\">) kSecClass : (__bridge </span><span class=\"mtk4\">id</span><span class=\"mtk1\">) kSecClassKey,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        (__bridge </span><span class=\"mtk4\">id</span><span class=\"mtk1\">) kSecAttrKeyType : (__bridge </span><span class=\"mtk4\">id</span><span class=\"mtk1\">) kSecAttrKeyTypeEC,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        (__bridge </span><span class=\"mtk4\">id</span><span class=\"mtk1\">) kSecAttrApplicationTag : tag,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        (__bridge </span><span class=\"mtk4\">id</span><span class=\"mtk1\">) kSecAttrKeyClass : keyClass,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        (__bridge </span><span class=\"mtk4\">id</span><span class=\"mtk1\">) kSecReturnRef : (__bridge </span><span class=\"mtk4\">id</span><span class=\"mtk1\">) kCFBooleanTrue</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    };</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk3\">//else look key in keychain and return</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    sanityCheck = </span><span class=\"mtk11\">SecItemCopyMatching</span><span class=\"mtk1\">((__bridge CFDictionaryRef) queryDict, (CFTypeRef *) &publicKeyRef);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk15\">if</span><span class=\"mtk1\"> (sanityCheck != errSecSuccess) {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk11\">NSLog</span><span class=\"mtk1\">(</span><span class=\"mtk8\">@&quot;Error trying to retrieve key from server.  sanityCheck: %d&quot;</span><span class=\"mtk1\">, (</span><span class=\"mtk4\">int</span><span class=\"mtk1\">)sanityCheck);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    }</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> publicKeyRef;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">}</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">- (SecKeyRef) lookupPrivateKeyRef</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">{</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    CFMutableDictionaryRef getPrivateKeyRef = newCFDict;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk11\">CFDictionarySetValue</span><span class=\"mtk1\">(getPrivateKeyRef, kSecClass, kSecClassKey);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk11\">CFDictionarySetValue</span><span class=\"mtk1\">(getPrivateKeyRef, kSecAttrKeyClass, kSecAttrKeyClassPrivate);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk11\">CFDictionarySetValue</span><span class=\"mtk1\">(getPrivateKeyRef, kSecAttrLabel, kPrivateKeyName);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk11\">CFDictionarySetValue</span><span class=\"mtk1\">(getPrivateKeyRef, kSecReturnRef, kCFBooleanTrue);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk10\">OSStatus</span><span class=\"mtk1\"> status = </span><span class=\"mtk11\">SecItemCopyMatching</span><span class=\"mtk1\">(getPrivateKeyRef, (CFTypeRef *)&privateKeyRef);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk15\">if</span><span class=\"mtk1\"> (status == errSecItemNotFound)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> </span><span class=\"mtk4\">nil</span><span class=\"mtk1\">;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> (SecKeyRef)privateKeyRef;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">}</span></span></code></pre>\n<p>The following methods will actually deal with Secure Enclave to generate a private key and public key.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"objective-c\" data-index=\"3\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">- (</span><span class=\"mtk4\">bool</span><span class=\"mtk1\">) generatePasscodeKeyPair</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">{</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    CFErrorRef error = </span><span class=\"mtk4\">NULL</span><span class=\"mtk1\">;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    SecAccessControlRef sacObject = </span><span class=\"mtk11\">SecAccessControlCreateWithFlags</span><span class=\"mtk1\">(</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                                                                    kCFAllocatorDefault,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                                                                    kSecAttrAccessibleAfterFirstUnlockThisDeviceOnly,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                                                                    kSecAccessControlPrivateKeyUsage,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                                                                    &error</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                                                                    );</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk15\">if</span><span class=\"mtk1\"> (error != errSecSuccess) {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk11\">NSLog</span><span class=\"mtk1\">(</span><span class=\"mtk8\">@&quot;Generating key pair, error: %@</span><span class=\"mtk6\">\\n</span><span class=\"mtk8\">&quot;</span><span class=\"mtk1\">, error);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    }</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> [self generateKeyPairWithAccessControlObject:sacObject];</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">}</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">- (</span><span class=\"mtk4\">bool</span><span class=\"mtk1\">) generateKeyPairWithAccessControlObject:(SecAccessControlRef)accessControlRef</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">{</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk3\">// create dictionary of private key </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    CFMutableDictionaryRef accessControlDict = newCFDict;;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk15\">#if</span><span class=\"mtk4\"> </span><span class=\"mtk1\">!</span><span class=\"mtk11\">TARGET_IPHONE_SIMULATOR</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk11\">CFDictionaryAddValue</span><span class=\"mtk1\">(accessControlDict, kSecAttrAccessControl, accessControlRef);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk15\">#endif</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk11\">CFDictionaryAddValue</span><span class=\"mtk1\">(accessControlDict, kSecAttrIsPermanent, kCFBooleanTrue);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk11\">CFDictionaryAddValue</span><span class=\"mtk1\">(accessControlDict, kSecAttrLabel, kPrivateKeyName);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk3\">// create dictionary for saving key into keychain</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    CFMutableDictionaryRef generatePairRef = newCFDict;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk15\">#if</span><span class=\"mtk4\"> </span><span class=\"mtk1\">!</span><span class=\"mtk11\">TARGET_IPHONE_SIMULATOR</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk11\">CFDictionaryAddValue</span><span class=\"mtk1\">(generatePairRef, kSecAttrTokenID, kSecAttrTokenIDSecureEnclave);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk15\">#endif</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk11\">CFDictionaryAddValue</span><span class=\"mtk1\">(generatePairRef, kSecAttrKeyType, kSecAttrKeyTypeEC);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk11\">CFDictionaryAddValue</span><span class=\"mtk1\">(generatePairRef, kSecAttrKeySizeInBits, (__bridge </span><span class=\"mtk4\">const</span><span class=\"mtk1\"> </span><span class=\"mtk4\">void</span><span class=\"mtk1\"> *)([</span><span class=\"mtk10\">NSNumber</span><span class=\"mtk1\"> numberWithInt:</span><span class=\"mtk7\">256</span><span class=\"mtk1\">]));</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk11\">CFDictionaryAddValue</span><span class=\"mtk1\">(generatePairRef, kSecPrivateKeyAttrs, accessControlDict);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk10\">OSStatus</span><span class=\"mtk1\"> status = </span><span class=\"mtk11\">SecKeyGeneratePair</span><span class=\"mtk1\">(generatePairRef, &publicKeyRef, &privateKeyRef);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk15\">if</span><span class=\"mtk1\"> (status != errSecSuccess){</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk11\">NSLog</span><span class=\"mtk1\">(</span><span class=\"mtk8\">@&quot;Error trying to retrieve key from server.  sanityCheck: %d&quot;</span><span class=\"mtk1\">, (</span><span class=\"mtk4\">int</span><span class=\"mtk1\">)status);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> </span><span class=\"mtk4\">NO</span><span class=\"mtk1\">;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    }</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    [self savePublicKeyFromRef:publicKeyRef];</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> </span><span class=\"mtk4\">YES</span><span class=\"mtk1\">;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">}</span></span></code></pre>\n<p>The private key is generated and stored in Secure Enclave which cannot be directly used. Whereas public key have to be stored manually in keychain by following method.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"objective-c\" data-index=\"4\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">- (</span><span class=\"mtk4\">bool</span><span class=\"mtk1\">) savePublicKeyFromRef:(SecKeyRef)publicKeyRef</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">{   </span><span class=\"mtk10\">OSStatus</span><span class=\"mtk1\"> sanityCheck = noErr;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk10\">NSData</span><span class=\"mtk1\"> *tag;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk4\">id</span><span class=\"mtk1\"> keyClass;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    tag = [kPublicKeyName dataUsingEncoding:NSUTF8StringEncoding];</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    keyClass = (__bridge </span><span class=\"mtk4\">id</span><span class=\"mtk1\">) kSecAttrKeyClassPublic;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk10\">NSDictionary</span><span class=\"mtk1\"> *saveDict = @{</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        (__bridge </span><span class=\"mtk4\">id</span><span class=\"mtk1\">) kSecClass : (__bridge </span><span class=\"mtk4\">id</span><span class=\"mtk1\">) kSecClassKey,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        (__bridge </span><span class=\"mtk4\">id</span><span class=\"mtk1\">) kSecAttrKeyType : (__bridge </span><span class=\"mtk4\">id</span><span class=\"mtk1\">) kSecAttrKeyTypeEC,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        (__bridge </span><span class=\"mtk4\">id</span><span class=\"mtk1\">) kSecAttrApplicationTag : tag,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        (__bridge </span><span class=\"mtk4\">id</span><span class=\"mtk1\">) kSecAttrKeyClass : keyClass,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        (__bridge </span><span class=\"mtk4\">id</span><span class=\"mtk1\">) kSecValueData : (__bridge </span><span class=\"mtk10\">NSData</span><span class=\"mtk1\"> *)</span><span class=\"mtk11\">SecKeyCopyExternalRepresentation</span><span class=\"mtk1\">(publicKeyRef,</span><span class=\"mtk4\">nil</span><span class=\"mtk1\">),</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        (__bridge </span><span class=\"mtk4\">id</span><span class=\"mtk1\">) kSecAttrKeySizeInBits : [</span><span class=\"mtk10\">NSNumber</span><span class=\"mtk1\"> numberWithUnsignedInteger:</span><span class=\"mtk7\">256</span><span class=\"mtk1\">],</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        (__bridge </span><span class=\"mtk4\">id</span><span class=\"mtk1\">) kSecAttrEffectiveKeySize : [</span><span class=\"mtk10\">NSNumber</span><span class=\"mtk1\"> numberWithUnsignedInteger:</span><span class=\"mtk7\">256</span><span class=\"mtk1\">],</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        (__bridge </span><span class=\"mtk4\">id</span><span class=\"mtk1\">) kSecAttrCanDerive : (__bridge </span><span class=\"mtk4\">id</span><span class=\"mtk1\">) kCFBooleanFalse,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        (__bridge </span><span class=\"mtk4\">id</span><span class=\"mtk1\">) kSecAttrCanEncrypt : (__bridge </span><span class=\"mtk4\">id</span><span class=\"mtk1\">) kCFBooleanTrue,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        (__bridge </span><span class=\"mtk4\">id</span><span class=\"mtk1\">) kSecAttrCanDecrypt : (__bridge </span><span class=\"mtk4\">id</span><span class=\"mtk1\">) kCFBooleanFalse,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        (__bridge </span><span class=\"mtk4\">id</span><span class=\"mtk1\">) kSecAttrCanVerify : (__bridge </span><span class=\"mtk4\">id</span><span class=\"mtk1\">) kCFBooleanTrue,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        (__bridge </span><span class=\"mtk4\">id</span><span class=\"mtk1\">) kSecAttrCanSign : (__bridge </span><span class=\"mtk4\">id</span><span class=\"mtk1\">) kCFBooleanFalse,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        (__bridge </span><span class=\"mtk4\">id</span><span class=\"mtk1\">) kSecAttrCanWrap : (__bridge </span><span class=\"mtk4\">id</span><span class=\"mtk1\">) kCFBooleanTrue,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        (__bridge </span><span class=\"mtk4\">id</span><span class=\"mtk1\">) kSecAttrCanUnwrap : (__bridge </span><span class=\"mtk4\">id</span><span class=\"mtk1\">) kCFBooleanFalse</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    };</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    sanityCheck = </span><span class=\"mtk11\">SecItemAdd</span><span class=\"mtk1\">((__bridge CFDictionaryRef) saveDict, (CFTypeRef *)&publicKeyRef);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk15\">if</span><span class=\"mtk1\"> (sanityCheck != errSecSuccess) {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk11\">NSLog</span><span class=\"mtk1\">(</span><span class=\"mtk8\">@&quot;Error trying to retrieve key from server.  sanityCheck: %d&quot;</span><span class=\"mtk1\">, (</span><span class=\"mtk4\">int</span><span class=\"mtk1\">)sanityCheck);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    }</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> publicKeyRef;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">}</span></span></code></pre>\n<h2 id=\"demo\" style=\"position:relative;\"><a href=\"#demo\" aria-label=\"demo permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Demo</h2>\n<p>Now I am creating ViewController.h and .m files. In viewDidLoad in .m file, having a string to be stored in UserDefaults. I will encrypt this string by a private key generated above and then store persistently encrypted data for later use.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"objective-c\" data-index=\"5\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">- (</span><span class=\"mtk4\">void</span><span class=\"mtk1\">)viewDidLoad {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    [super viewDidLoad];</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk10\">NSString</span><span class=\"mtk1\"> *strDatatosave = </span><span class=\"mtk8\">@&quot;example data to save&quot;</span><span class=\"mtk1\">;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk10\">NSString</span><span class=\"mtk1\"> *bundleIdentifier = [[</span><span class=\"mtk10\">NSBundle</span><span class=\"mtk1\"> mainBundle] bundleIdentifier];</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk10\">NSString</span><span class=\"mtk1\"> *strGroupID = [</span><span class=\"mtk10\">NSString</span><span class=\"mtk1\"> stringWithFormat:</span><span class=\"mtk8\">@&quot;group.%@&quot;</span><span class=\"mtk1\">,bundleIdentifier];</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    SecEnclaveWrapper *keychainItem = [[SecEnclaveWrapper alloc] init];</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk10\">NSData</span><span class=\"mtk1\"> *encrypted = [keychainItem encryptData:[strDatatosave dataUsingEncoding:NSUTF8StringEncoding]];</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk10\">NSString</span><span class=\"mtk1\"> *strEncrypted = [[</span><span class=\"mtk10\">NSString</span><span class=\"mtk1\"> alloc] initWithData:encrypted encoding:NSUTF8StringEncoding];</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk11\">NSLog</span><span class=\"mtk1\">(</span><span class=\"mtk8\">@&quot;encrypted string %@&quot;</span><span class=\"mtk1\">,strEncrypted);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk10\">NSData</span><span class=\"mtk1\"> *decrypted =[keychainItem decryptData:encrypted];</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk10\">NSString</span><span class=\"mtk1\"> *strDecrypted = [[</span><span class=\"mtk10\">NSString</span><span class=\"mtk1\"> alloc] initWithData:decrypted encoding:NSUTF8StringEncoding];</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk11\">NSLog</span><span class=\"mtk1\">(</span><span class=\"mtk8\">@&quot;decrypted string as real string%@&quot;</span><span class=\"mtk1\">,strDecrypted);</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">}</span></span></code></pre>\n<h2 id=\"conclusion\" style=\"position:relative;\"><a href=\"#conclusion\" aria-label=\"conclusion permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Conclusion</h2>\n<p>In this blog, we learned about the basics of key generation via Secure Enclave and encryption and decryption using keys.\nBy default, key-pairs are generated in the Secure Enclave. The private key is available only at creation time and can not be obtained later as it is saved in Secure Enclave. Operations can be performed with it without exposing it to user code. Only Public Key will be stored and retrieved.</p>\n<p>You can find the complete repository link <a href=\"https://github.com/LoginRadius/engineering-blog-samples/tree/master/iOS/SecureEnclave/SecureEnclaveDemo\">here</a></p>\n<p>Thanks for reading the blog. For detailed information and execution example of this blog, please refer to the video below:</p>\n<iframe width=\"560\" height=\"315\" src=\"https://www.youtube.com/embed/c_1E_NV4NBk\" frameborder=\"0\" allow=\"accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen></iframe>\n<style class=\"grvsc-styles\">\n  .grvsc-container {\n    overflow: auto;\n    -webkit-overflow-scrolling: touch;\n    padding-top: 1rem;\n    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));\n    padding-bottom: 1rem;\n    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));\n    border-radius: 8px;\n    border-radius: var(--grvsc-border-radius, 8px);\n    font-feature-settings: normal;\n  }\n  \n  .grvsc-code {\n    display: inline-block;\n    min-width: 100%;\n  }\n  \n  .grvsc-line {\n    display: inline-block;\n    box-sizing: border-box;\n    width: 100%;\n    padding-left: 1.5rem;\n    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));\n    padding-right: 1.5rem;\n    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));\n  }\n  \n  .grvsc-line-highlighted {\n    background-color: var(--grvsc-line-highlighted-background-color, transparent);\n    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, transparent);\n  }\n  \n  .dark-default-dark {\n    background-color: #1E1E1E;\n    color: #D4D4D4;\n  }\n  .dark-default-dark .mtk3 { color: #6A9955; }\n  .dark-default-dark .mtk1 { color: #D4D4D4; }\n  .dark-default-dark .mtk10 { color: #4EC9B0; }\n  .dark-default-dark .mtk4 { color: #569CD6; }\n  .dark-default-dark .mtk15 { color: #C586C0; }\n  .dark-default-dark .mtk12 { color: #9CDCFE; }\n  .dark-default-dark .mtk11 { color: #DCDCAA; }\n  .dark-default-dark .mtk8 { color: #CE9178; }\n  .dark-default-dark .mtk6 { color: #D7BA7D; }\n  .dark-default-dark .mtk7 { color: #B5CEA8; }\n</style>","frontmatter":{"date":"October 13, 2020","updated_date":null,"description":"SecureEnclaveDemo is an xcode project containing helper named as SecEnclaveWrapper. You can use this wrapper in your project to encrypt/decrypt sensitive data using Secure Enclave. Let's understand more about in the blog.","title":"Secure Enclave in iOS App","tags":["ios","security","data","encryption","private key","xcode"],"pinned":null,"coverImage":{"childImageSharp":{"fluid":{"aspectRatio":1.5037593984962405,"src":"/static/e677a934323b29af4619ee797f0286b8/58556/CoverImage.webp","srcSet":"/static/e677a934323b29af4619ee797f0286b8/61e93/CoverImage.webp 200w,\n/static/e677a934323b29af4619ee797f0286b8/1f5c5/CoverImage.webp 400w,\n/static/e677a934323b29af4619ee797f0286b8/58556/CoverImage.webp 800w,\n/static/e677a934323b29af4619ee797f0286b8/210c1/CoverImage.webp 900w","sizes":"(max-width: 800px) 100vw, 800px"}}},"author":{"id":"Tanvi Jain","github":"tanvijn","avatar":null}}}},{"node":{"excerpt":"What is STL? STL stands for Standard Template Library. If you've used C++ even in small projects, you've likely already used STL - which is…","fields":{"slug":"/engineering/cpp-stl-containers/"},"html":"<h2 id=\"what-is-stl\" style=\"position:relative;\"><a href=\"#what-is-stl\" aria-label=\"what is stl permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>What is STL?</h2>\n<p>STL stands for Standard Template Library. If you've used C++ even in small projects, you've likely already used STL - which is a great thing! Using STL in C++ makes your code more expressive, simple, and easy to understand. This post will give you an overview of how STL works, some examples, and the basic knowledge you need to get started!</p>\n<h2 id=\"stl-components\" style=\"position:relative;\"><a href=\"#stl-components\" aria-label=\"stl components permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>STL Components</h2>\n<p>Loosely speaking, the first components you'd typically understand and use of STL are Containers &#x26; Algorithms. Then there's also Iterators &#x26; Functors, but you should try to take them on one by one, in that order perhaps. This blog will expand a bit on STL Containers.</p>\n<h3 id=\"containers\" style=\"position:relative;\"><a href=\"#containers\" aria-label=\"containers permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Containers</h3>\n<p>Suppose you are at your favorite cinema hall and it's the launch of a big movie. Since it's the launch, there are likely many people waiting in line to buy their tickets. Naturally, you join the queue at the back and wait for your turn. In the computing world, we have a queue too! This is a popular data structure. If you've had a Data Structures class before, you are most likely familiar with some other data structures as well. These are often used, so the STL provides a great implementation of all these data structures, otherwise known as containers.</p>\n<p>Take arrays, for example. Arrays are elements with the same type, stored in contiguous blocks of memory. In C++, you can use arrays as you would in C, like this:</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"cpp\" data-index=\"0\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk10\">std</span><span class=\"mtk1\">::string </span><span class=\"mtk12\">students</span><span class=\"mtk1\">[</span><span class=\"mtk7\">10</span><span class=\"mtk1\">];</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk12\">students</span><span class=\"mtk1\">[</span><span class=\"mtk7\">0</span><span class=\"mtk1\">] = </span><span class=\"mtk8\">&quot;Adam&quot;</span><span class=\"mtk1\">;</span></span></code></pre>\n<p>But wait, STL provides a container for arrays too. It's available in the header <code>&#x3C;array></code>. Example usage of it would look like this:</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"cpp\" data-index=\"1\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk15\">#include</span><span class=\"mtk4\"> </span><span class=\"mtk8\">&lt;iostream&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk15\">#include</span><span class=\"mtk4\"> </span><span class=\"mtk8\">&lt;string&gt;</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">int</span><span class=\"mtk1\"> </span><span class=\"mtk11\">main</span><span class=\"mtk1\">() {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk10\">std</span><span class=\"mtk1\">::array&lt;</span><span class=\"mtk10\">std</span><span class=\"mtk1\">::string, </span><span class=\"mtk7\">10</span><span class=\"mtk1\">&gt; students;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk12\">students</span><span class=\"mtk1\">[</span><span class=\"mtk7\">0</span><span class=\"mtk1\">] = </span><span class=\"mtk8\">&quot;Adam&#39;s Friend&quot;</span><span class=\"mtk1\">;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    cout &lt;&lt; </span><span class=\"mtk12\">students</span><span class=\"mtk1\">[</span><span class=\"mtk7\">0</span><span class=\"mtk1\">] &lt;&lt; endl;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">}</span></span></code></pre>\n<p>So, what's the difference? Why should you use the STL Container class? The performance difference is negligible, but what makes the container classes better is that it is a class. A wrapper class around normal arrays, and offers some advantages like passing by values, bounds checking, etc. As a side note, you'd normally want to use an <code>std::vector</code> instead - which is a dynamically resizable array.</p>\n<h4 id=\"other-examples\" style=\"position:relative;\"><a href=\"#other-examples\" aria-label=\"other examples permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Other examples</h4>\n<p>Other containers in C++ include:</p>\n<ul>\n<li>\n<p>Sequence containers: (accessibility in a sequential manner)</p>\n<ul>\n<li><code>std::array</code></li>\n<li>\n<p><code>std::vector</code>: Dynamically resizable arrays.\nArrays have a set size, while <code>std::vector</code> doesn't. You can keep adding elements in contigious blocks of memory. For example:</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"cpp\" data-index=\"2\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk10\">std</span><span class=\"mtk1\">::vector&lt;</span><span class=\"mtk10\">std</span><span class=\"mtk1\">::string&gt; students;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk12\">students</span><span class=\"mtk1\">.</span><span class=\"mtk11\">push_back</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;Paul&quot;</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk12\">students</span><span class=\"mtk1\">.</span><span class=\"mtk11\">push_back</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;Jack&quot;</span><span class=\"mtk1\">);</span></span></code></pre>\n<p>Paul &#x26; Jack are stored in contiguous memory blocks, even though we didn't provide a specific limit at the start - as we do with arrays.</p>\n</li>\n<li>\n<p><code>std::forward_list</code>: Singly linked-list.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"\" data-index=\"3\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">A -&gt; B -&gt; C -&gt; D</span></code></pre>\n<p>This is a simple example of linked-lists. Once you're at a point, let's say \"C\" - you can only go forwards.</p>\n</li>\n<li>\n<p><code>std::list</code>: Doubly linked-list.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"\" data-index=\"4\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">A &lt;-&gt; B &lt;-&gt; C &lt;-&gt; D</span></code></pre>\n<p>Above is a simple example of a doubly linked-list. Unlike Singly linked-lists, if you're at \"C\", you can go either way. To \"B\" or \"D\".</p>\n</li>\n<li><code>std::deque</code>: Double-ended queues - insertion and removal possible at both ends.</li>\n</ul>\n</li>\n<li>\n<p>Container Adaptors: (different interface of accessibility from sequence containers)</p>\n<ul>\n<li><code>std::queue</code>: A standard queue, where removals are done from the front, and insertions are done at the end. The queue is a FIFO structure (First in, First out).</li>\n<li><code>std::priority_queue</code>: A queue in which elements can have a varying level of importance. The ones with the highest importance are at the front, and thus processed first.\nFor example, let's say you're at a barbershop. A person arrived after you. If that person would've made a prior appointment to the shop, he would automatically be placed ahead of you with more \"importance\". Priority queues work similarly.</li>\n<li><code>std::stack</code>:\nSuppose you have a pile of 10 books. If you need a book from middle - of course, like most people, you will pull it right from the middle in one go. Let's think about how computers would take this problem. A computer needs a step-by-step instruction, so the first thing it would do is remove the book from the top. And continue to do that until it reaches the book. To keep books as they were again, it would place books one by one at the top of the pile.\nThus, insertions and removals in a stack are only done at the \"top\". </li>\n</ul>\n</li>\n<li>\n<p>Associative containers: (sorted in a specific order, these containers boast search speeds of O(log N))</p>\n<ul>\n<li><code>std::set</code>: Each element inserted into a set is it's own identifier, meaning that unique elements are entered. Each element acts as it's own \"key\" - which uniquely identifies it. For example, suppose you are a volunteer for entering student information for new students entering into the semester. They are uniquely identified by their roll numbers. Suppose you enter the same student's Roll No (the ID) twice into a set, it will be inserted just once - because a \"set\" can only have unique values.</li>\n<li><code>std::multiset</code>: Like a set, but here the same multiple elements are allowed. Entering the roll no from before twice into an <code>std::multiset</code> will result in it being added twice.</li>\n<li><code>std::map</code>: Take a literal map, for example. When you point to a location on the map, it tells you the details. The \"point\" is the key, and the details of that location are the \"values\". The keys are unique, and values can be anything. An <code>std::map</code> works the same way. Perhaps an example will help understanding more about it:</li>\n</ul>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"cpp\" data-index=\"5\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk3\">// This maps a student name to his marks. But is this correct?</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk10\">std</span><span class=\"mtk1\">::map&lt;</span><span class=\"mtk10\">std</span><span class=\"mtk1\">::string, </span><span class=\"mtk4\">int</span><span class=\"mtk1\">&gt; mapOfStudentNameToMarks;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk3\">// The answer is no. A student&#39;s name isn&#39;t necessarily unique, multiple students with the same name will have a clash this way.</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk3\">// Thus, the correct way would be:</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk10\">std</span><span class=\"mtk1\">::map&lt;</span><span class=\"mtk4\">int</span><span class=\"mtk1\">, </span><span class=\"mtk4\">int</span><span class=\"mtk1\">&gt; mapOfStudentIDToMarks;</span><span class=\"mtk3\"> // This is correct, because StudentIDs are unique!</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk12\">mapOfStudentIDToMarks</span><span class=\"mtk1\">[</span><span class=\"mtk7\">1</span><span class=\"mtk1\">] = </span><span class=\"mtk7\">100</span><span class=\"mtk1\">;</span><span class=\"mtk3\">   // StudentID 1 -&gt; 100 Marks.</span></span></code></pre>\n<ul>\n<li><code>std::multimap</code>: Can you guess what this might do, based on <code>std::multiset</code>?\nMultimap allows multiple elements to have the same key. So, for example, 10 -> 100 &#x26; 10 -> 150 are both valid for a multimap.</li>\n</ul>\n</li>\n<li>\n<p>Unordered Associative containers: (like associative containers, but implemented as hash-tables. They can be accessed at O(1), i.e., constant time.</p>\n<ul>\n<li><code>std::unordered_set</code></li>\n<li><code>std::unordered_multiset</code></li>\n<li><code>std::unordered_map</code></li>\n<li><code>std::unordered_multimap</code>\n-- </li>\n</ul>\n</li>\n</ul>\n<h3 id=\"stl---what-next\" style=\"position:relative;\"><a href=\"#stl---what-next\" aria-label=\"stl   what next permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>STL - What next?</h3>\n<p>Containers aren't the only part of STL. It is huge! You are encouraged to read up more on STL, as it makes your life easier in every manner! You don't need to reinvent the wheel. Next, you could try looking up the various algorithms contained in the STL. They're present in the header file <code>&#x3C;algorithm></code>. Good luck on your journey!</p>\n<style class=\"grvsc-styles\">\n  .grvsc-container {\n    overflow: auto;\n    -webkit-overflow-scrolling: touch;\n    padding-top: 1rem;\n    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));\n    padding-bottom: 1rem;\n    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));\n    border-radius: 8px;\n    border-radius: var(--grvsc-border-radius, 8px);\n    font-feature-settings: normal;\n  }\n  \n  .grvsc-code {\n    display: inline-block;\n    min-width: 100%;\n  }\n  \n  .grvsc-line {\n    display: inline-block;\n    box-sizing: border-box;\n    width: 100%;\n    padding-left: 1.5rem;\n    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));\n    padding-right: 1.5rem;\n    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));\n  }\n  \n  .grvsc-line-highlighted {\n    background-color: var(--grvsc-line-highlighted-background-color, transparent);\n    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, transparent);\n  }\n  \n  .dark-default-dark {\n    background-color: #1E1E1E;\n    color: #D4D4D4;\n  }\n  .dark-default-dark .mtk10 { color: #4EC9B0; }\n  .dark-default-dark .mtk1 { color: #D4D4D4; }\n  .dark-default-dark .mtk12 { color: #9CDCFE; }\n  .dark-default-dark .mtk7 { color: #B5CEA8; }\n  .dark-default-dark .mtk8 { color: #CE9178; }\n  .dark-default-dark .mtk15 { color: #C586C0; }\n  .dark-default-dark .mtk4 { color: #569CD6; }\n  .dark-default-dark .mtk11 { color: #DCDCAA; }\n  .dark-default-dark .mtk3 { color: #6A9955; }\n</style>","frontmatter":{"date":"October 13, 2020","updated_date":null,"description":"Learn how Standard Template Library works in C++ with interactive examples and what you need to get started","title":"STL Containers & Data Structures in C++","tags":["C++","STL"],"pinned":null,"coverImage":{"childImageSharp":{"fluid":{"aspectRatio":1.5037593984962405,"src":"/static/4ec0001784cd81b020aea7e2bbf26abb/58556/cover.webp","srcSet":"/static/4ec0001784cd81b020aea7e2bbf26abb/61e93/cover.webp 200w,\n/static/4ec0001784cd81b020aea7e2bbf26abb/1f5c5/cover.webp 400w,\n/static/4ec0001784cd81b020aea7e2bbf26abb/58556/cover.webp 800w,\n/static/4ec0001784cd81b020aea7e2bbf26abb/99238/cover.webp 1200w","sizes":"(max-width: 800px) 100vw, 800px"}}},"author":{"id":"Aryan Rawlani","github":"aryanrawlani28","avatar":null}}}},{"node":{"excerpt":"Before we get into details of finding out optimal clusters, let's first see what the KMeans clustering algorithm is and some basics about it…","fields":{"slug":"/engineering/optimal-clusters-kmeans/"},"html":"<p>Before we get into details of finding out optimal clusters, let's first see what the KMeans clustering algorithm is and some basics about it.</p>\n<h2 id=\"what-is-clustering\" style=\"position:relative;\"><a href=\"#what-is-clustering\" aria-label=\"what is clustering permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>What is Clustering?</h2>\n<p>Clustering is an unsupervised ML technique wherein we cluster the data to get insights from it. Clustering the data is quite essential for some business models and problems. It gives us conclusions on what is a cluster, i.e. data which is similar and in the form of cluster or groups.</p>\n<blockquote>\n<p>Clustering is the process of dividing the entire data into groups (also known as clusters) based on the patterns in the data.</p>\n</blockquote>\n<h2 id=\"what-is-the-kmeans-clustering-algorithm\" style=\"position:relative;\"><a href=\"#what-is-the-kmeans-clustering-algorithm\" aria-label=\"what is the kmeans clustering algorithm permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>What is the KMeans clustering algorithm?</h2>\n<p>It is an algorithm for clustering. We will be discussing this method with code in the further sections.</p>\n<h2 id=\"initial-imports-\" style=\"position:relative;\"><a href=\"#initial-imports-\" aria-label=\"initial imports  permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Initial Imports :</h2>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"python\" data-index=\"0\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk15\">import</span><span class=\"mtk1\"> pandas </span><span class=\"mtk15\">as</span><span class=\"mtk1\"> pd</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk15\">import</span><span class=\"mtk1\"> numpy </span><span class=\"mtk15\">as</span><span class=\"mtk1\"> np</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk15\">import</span><span class=\"mtk1\"> matplotlib.pyplot </span><span class=\"mtk15\">as</span><span class=\"mtk1\"> plt</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk15\">from</span><span class=\"mtk1\"> sklearn.cluster </span><span class=\"mtk15\">import</span><span class=\"mtk1\"> KMeans</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">%matplotlib inline</span></span></code></pre>\n<h2 id=\"method-\" style=\"position:relative;\"><a href=\"#method-\" aria-label=\"method  permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Method :</h2>\n<p>Now let's discuss the method behind finding out the right number of clusters on a K-Means clustering algorithm.\nSo we will learn how to decide what number of clusters to input into your K-Means algorithm.\nHere we've got a data science problem.\nWe've got only two variables, x and y coordinates.</p>\n<p>Now, if we run the K means clustering algorithm on this dataset with three clusters or with K pre-determine the clusters to be three, then the result will look something like this.</p>\n<p><img src=\"/f2f1dc62cdf496de947a76353a248a23/initial.webp\" alt=\"initial\"></p>\n<p>We need a specific metric, we need a way to understand or evaluate how a certain number of clusters performs compared to a different number of clusters, and preferably, that metric should be quantifiable.</p>\n<p>So what kind of metric can we impose upon our clustering algorithm that will tell us something about the final result?\nThere is such a metric called the within-cluster sum of squares. (WCSS)</p>\n<p><img src=\"/9e24eb349c5a9a1d35919c74606a5fe1/Wcss.webp\" alt=\"Wcss\"></p>\n<p>So you can see here that it jumps from 8000 down to 3000, that's a massive change of 5000. Let's just call them units, 5000 units and then from 3000 as we increase the number of the close from 2 to 3, they jump from 3000 to 1000.</p>\n<p>Again quite a large drop and then from three to four what's going to happen is going to jump from 1000 to maybe eight hundred and from 800 to 600, 600 to 500 and so on so as you can see the first two improvements or first two changes from one cluster to two from two to three created some huge jumps or considerable drops in the WTS going forward The WCR says drops not substantially. And this is our hint at selecting the optimum optimal number of clusters; and the method we're going to use is the elbow method, and it is very visual. All you have to do is look at your chart and look for that change, or that's kind of like it does look like an ELBOW.</p>\n<p>Look for that elbow in your chart where the drop goes from being quite substantial to being not as significant not as proven is not as great, and therefore, that point in your chart will be the optimal number of clusters.</p>\n<p>In this case, it is indeed three clusters.</p>\n<p>That is the optimal number. And as you can imagine, this method is entirely arbitrary.\nSometimes, the situations are not as pronounced as the elbow might not be as evident as in this case, and therefore, somebody might pick one number of clusters. Someone else might come along and select a different number.</p>\n<h2 id=\"code-\" style=\"position:relative;\"><a href=\"#code-\" aria-label=\"code  permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>CODE :</h2>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"python\" data-index=\"1\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk15\">from</span><span class=\"mtk1\"> sklearn.cluster </span><span class=\"mtk15\">import</span><span class=\"mtk1\"> KMeans</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">wcss = []</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk15\">for</span><span class=\"mtk1\"> i </span><span class=\"mtk4\">in</span><span class=\"mtk1\"> </span><span class=\"mtk11\">range</span><span class=\"mtk1\">(</span><span class=\"mtk7\">1</span><span class=\"mtk1\">, </span><span class=\"mtk7\">11</span><span class=\"mtk1\">):</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  kmeans = KMeans(</span><span class=\"mtk12\">n_clusters</span><span class=\"mtk1\"> = i, </span><span class=\"mtk12\">init</span><span class=\"mtk1\"> = </span><span class=\"mtk8\">&#39;k-means++&#39;</span><span class=\"mtk1\">, </span><span class=\"mtk12\">random_state</span><span class=\"mtk1\"> = </span><span class=\"mtk7\">42</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  kmeans.fit(X)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  wcss.append(kmeans.inertia_)</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">plt.plot(</span><span class=\"mtk11\">range</span><span class=\"mtk1\">(</span><span class=\"mtk7\">1</span><span class=\"mtk1\">, </span><span class=\"mtk7\">11</span><span class=\"mtk1\">), wcss)</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">plt.title(</span><span class=\"mtk8\">&#39;The Elbow Method&#39;</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">plt.xlabel(</span><span class=\"mtk8\">&#39;Number of clusters&#39;</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">plt.ylabel(</span><span class=\"mtk8\">&#39;WCSS&#39;</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">plt.show()</span></span></code></pre>\n<style class=\"grvsc-styles\">\n  .grvsc-container {\n    overflow: auto;\n    -webkit-overflow-scrolling: touch;\n    padding-top: 1rem;\n    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));\n    padding-bottom: 1rem;\n    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));\n    border-radius: 8px;\n    border-radius: var(--grvsc-border-radius, 8px);\n    font-feature-settings: normal;\n  }\n  \n  .grvsc-code {\n    display: inline-block;\n    min-width: 100%;\n  }\n  \n  .grvsc-line {\n    display: inline-block;\n    box-sizing: border-box;\n    width: 100%;\n    padding-left: 1.5rem;\n    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));\n    padding-right: 1.5rem;\n    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));\n  }\n  \n  .grvsc-line-highlighted {\n    background-color: var(--grvsc-line-highlighted-background-color, transparent);\n    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, transparent);\n  }\n  \n  .dark-default-dark {\n    background-color: #1E1E1E;\n    color: #D4D4D4;\n  }\n  .dark-default-dark .mtk15 { color: #C586C0; }\n  .dark-default-dark .mtk1 { color: #D4D4D4; }\n  .dark-default-dark .mtk4 { color: #569CD6; }\n  .dark-default-dark .mtk11 { color: #DCDCAA; }\n  .dark-default-dark .mtk7 { color: #B5CEA8; }\n  .dark-default-dark .mtk12 { color: #9CDCFE; }\n  .dark-default-dark .mtk8 { color: #CE9178; }\n</style>","frontmatter":{"date":"October 12, 2020","updated_date":null,"description":null,"title":"Optimal clusters for KMeans Algorithm","tags":["Machine Learning"],"pinned":null,"coverImage":{"childImageSharp":{"fluid":{"aspectRatio":1.5037593984962405,"src":"/static/225782b978d81111592f1f839c6dc1e4/58556/cover.webp","srcSet":"/static/225782b978d81111592f1f839c6dc1e4/61e93/cover.webp 200w,\n/static/225782b978d81111592f1f839c6dc1e4/1f5c5/cover.webp 400w,\n/static/225782b978d81111592f1f839c6dc1e4/58556/cover.webp 800w,\n/static/225782b978d81111592f1f839c6dc1e4/b0b9b/cover.webp 1192w","sizes":"(max-width: 800px) 100vw, 800px"}}},"author":{"id":"Neeraj Ap","github":"NEERAJAP2001","avatar":null}}}},{"node":{"excerpt":"Introduction When building APIs, the need to upload files is expected, which can be images, text documents, scripts, pdfs, among others. In…","fields":{"slug":"/engineering/upload-files-with-node-and-multer/"},"html":"<h1 id=\"introduction\" style=\"position:relative;\"><a href=\"#introduction\" aria-label=\"introduction permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Introduction</h1>\n<p>When building APIs, the need to upload files is expected, which can be images, text documents, scripts, pdfs, among others. In the development of this functionality, some problems can be found, such as the number of files, valid file types, sizes of these files, and several others. And to save us from these problems we have the <a href=\"https://github.com/expressjs/multer\">Multer</a> library. Multer is a node.js middleware for handling <code>multipart/form-data</code> that is used to send files in forms.</p>\n<h1 id=\"first-steps\" style=\"position:relative;\"><a href=\"#first-steps\" aria-label=\"first steps permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>First steps</h1>\n<p>The first step is to create a NodeJS project on your computer.</p>\n<h1 id=\"adding-express\" style=\"position:relative;\"><a href=\"#adding-express\" aria-label=\"adding express permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Adding Express</h1>\n<p>In your terminal, type the following command:</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"jsx\" data-index=\"0\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk12\">yarn</span><span class=\"mtk1\"> </span><span class=\"mtk12\">add</span><span class=\"mtk1\"> </span><span class=\"mtk12\">express</span></span></code></pre>\n<p>* <em>You can also use NPM for installation</em></p>\n<p>Create a file named <code>app.js</code> inside the <code>src/</code> folder. The next step is to start our Express server in our <code>app.js</code></p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"js\" data-index=\"1\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk4\">const</span><span class=\"mtk1\"> </span><span class=\"mtk12\">express</span><span class=\"mtk1\"> = </span><span class=\"mtk11\">require</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;express&quot;</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">const</span><span class=\"mtk1\"> </span><span class=\"mtk12\">app</span><span class=\"mtk1\"> = </span><span class=\"mtk11\">express</span><span class=\"mtk1\">()</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk12\">app</span><span class=\"mtk1\">.</span><span class=\"mtk11\">listen</span><span class=\"mtk1\">(</span><span class=\"mtk7\">3000</span><span class=\"mtk1\"> || </span><span class=\"mtk12\">process</span><span class=\"mtk1\">.</span><span class=\"mtk12\">env</span><span class=\"mtk1\">.</span><span class=\"mtk12\">PORT</span><span class=\"mtk1\">, () </span><span class=\"mtk4\">=&gt;</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk10\">console</span><span class=\"mtk1\">.</span><span class=\"mtk11\">log</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;Server on...&quot;</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">})</span></span></code></pre>\n<h1 id=\"adding-multer\" style=\"position:relative;\"><a href=\"#adding-multer\" aria-label=\"adding multer permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Adding Multer</h1>\n<p>With the project created, configured and with Express installed, we will add the multer to our project.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"js\" data-index=\"2\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk12\">yarn</span><span class=\"mtk1\"> </span><span class=\"mtk12\">add</span><span class=\"mtk1\"> </span><span class=\"mtk12\">multer</span></span></code></pre>\n<p>The next step is to import the multer into our <code>app.js</code> file.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"jsx\" data-index=\"3\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk4\">const</span><span class=\"mtk1\"> </span><span class=\"mtk12\">multer</span><span class=\"mtk1\"> = </span><span class=\"mtk11\">require</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;multer&quot;</span><span class=\"mtk1\">)</span></span></code></pre>\n<p>We are almost there. Now create a folder called <code>uploads</code> where we will store the uploaded files.</p>\n<h1 id=\"configuring-and-validating-the-upload\" style=\"position:relative;\"><a href=\"#configuring-and-validating-the-upload\" aria-label=\"configuring and validating the upload permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Configuring and validating the upload</h1>\n<p>Now we are at a very important stage which is the configuration of <code>diskStorage</code>. <code>DiskStorage</code> is a method made available by multer where we configure the destination of the file, the name of the file and we can also add validations regarding the type of the file. These settings are according to the needs of your project. Below I will leave an elementary example of the configuration.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"js\" data-index=\"4\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk4\">const</span><span class=\"mtk1\"> </span><span class=\"mtk12\">storage</span><span class=\"mtk1\"> = </span><span class=\"mtk12\">multer</span><span class=\"mtk1\">.</span><span class=\"mtk11\">diskStorage</span><span class=\"mtk1\">({</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk11\">destination</span><span class=\"mtk12\">:</span><span class=\"mtk1\"> (</span><span class=\"mtk12\">req</span><span class=\"mtk1\">, </span><span class=\"mtk12\">file</span><span class=\"mtk1\">, </span><span class=\"mtk12\">cb</span><span class=\"mtk1\">) </span><span class=\"mtk4\">=&gt;</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk11\">cb</span><span class=\"mtk1\">(</span><span class=\"mtk4\">null</span><span class=\"mtk1\">, </span><span class=\"mtk8\">&quot;uploads/&quot;</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  },</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk11\">filename</span><span class=\"mtk12\">:</span><span class=\"mtk1\"> (</span><span class=\"mtk12\">req</span><span class=\"mtk1\">, </span><span class=\"mtk12\">file</span><span class=\"mtk1\">, </span><span class=\"mtk12\">cb</span><span class=\"mtk1\">) </span><span class=\"mtk4\">=&gt;</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk11\">cb</span><span class=\"mtk1\">(</span><span class=\"mtk4\">null</span><span class=\"mtk1\">, </span><span class=\"mtk10\">Date</span><span class=\"mtk1\">.</span><span class=\"mtk11\">now</span><span class=\"mtk1\">() + </span><span class=\"mtk8\">&quot;-&quot;</span><span class=\"mtk1\"> + </span><span class=\"mtk12\">file</span><span class=\"mtk1\">.</span><span class=\"mtk12\">originalname</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  },</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">})</span></span></code></pre>\n<p>In the configuration above, we mentioned the destination for the uploaded files and also change the name of the file .</p>\n<h1 id=\"providing-an-upload-route\" style=\"position:relative;\"><a href=\"#providing-an-upload-route\" aria-label=\"providing an upload route permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Providing an upload route</h1>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"js\" data-index=\"5\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk4\">const</span><span class=\"mtk1\"> </span><span class=\"mtk12\">uploadStorage</span><span class=\"mtk1\"> = </span><span class=\"mtk11\">multer</span><span class=\"mtk1\">({ </span><span class=\"mtk12\">storage:</span><span class=\"mtk1\"> </span><span class=\"mtk12\">storage</span><span class=\"mtk1\"> })</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk3\">// Single file</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk12\">app</span><span class=\"mtk1\">.</span><span class=\"mtk11\">post</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;/upload/single&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk12\">uploadStorage</span><span class=\"mtk1\">.</span><span class=\"mtk11\">single</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;file&quot;</span><span class=\"mtk1\">), (</span><span class=\"mtk12\">req</span><span class=\"mtk1\">, </span><span class=\"mtk12\">res</span><span class=\"mtk1\">) </span><span class=\"mtk4\">=&gt;</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk10\">console</span><span class=\"mtk1\">.</span><span class=\"mtk11\">log</span><span class=\"mtk1\">(</span><span class=\"mtk12\">req</span><span class=\"mtk1\">.</span><span class=\"mtk12\">file</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> </span><span class=\"mtk12\">res</span><span class=\"mtk1\">.</span><span class=\"mtk11\">send</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;Single file&quot;</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">})</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk3\">//Multiple files</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk12\">app</span><span class=\"mtk1\">.</span><span class=\"mtk11\">post</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;/upload/multiple&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk12\">uploadStorage</span><span class=\"mtk1\">.</span><span class=\"mtk11\">array</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;file&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk7\">10</span><span class=\"mtk1\">), (</span><span class=\"mtk12\">req</span><span class=\"mtk1\">, </span><span class=\"mtk12\">res</span><span class=\"mtk1\">) </span><span class=\"mtk4\">=&gt;</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk10\">console</span><span class=\"mtk1\">.</span><span class=\"mtk11\">log</span><span class=\"mtk1\">(</span><span class=\"mtk12\">req</span><span class=\"mtk1\">.</span><span class=\"mtk12\">files</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> </span><span class=\"mtk12\">res</span><span class=\"mtk1\">.</span><span class=\"mtk11\">send</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;Multiple files&quot;</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">})</span></span></code></pre>\n<p>In the code snippet above, we created 2 POST routes for sending files. The first <code>/upload/single</code> route receives only a single file, note that the uploadStorage variable receives our diskStorage settings. As a middleware in the route, it calls the <code>single</code> method for uploading a single file. The <code>/upload/multiple</code> route receives several files, but with a maximum limit of 10 files, note that the uploadStorage variable now calls the ʻarray` method for uploading multiple files.</p>\n<h1 id=\"the-end\" style=\"position:relative;\"><a href=\"#the-end\" aria-label=\"the end permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>The end</h1>\n<p>With all the settings done, our little API is already able to store the files sent.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"js\" data-index=\"6\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk4\">const</span><span class=\"mtk1\"> </span><span class=\"mtk12\">express</span><span class=\"mtk1\"> = </span><span class=\"mtk11\">require</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;express&quot;</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">const</span><span class=\"mtk1\"> </span><span class=\"mtk12\">multer</span><span class=\"mtk1\"> = </span><span class=\"mtk11\">require</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;multer&quot;</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">const</span><span class=\"mtk1\"> </span><span class=\"mtk12\">app</span><span class=\"mtk1\"> = </span><span class=\"mtk11\">express</span><span class=\"mtk1\">()</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">const</span><span class=\"mtk1\"> </span><span class=\"mtk12\">storage</span><span class=\"mtk1\"> = </span><span class=\"mtk12\">multer</span><span class=\"mtk1\">.</span><span class=\"mtk11\">diskStorage</span><span class=\"mtk1\">({</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk11\">destination</span><span class=\"mtk12\">:</span><span class=\"mtk1\"> (</span><span class=\"mtk12\">req</span><span class=\"mtk1\">, </span><span class=\"mtk12\">file</span><span class=\"mtk1\">, </span><span class=\"mtk12\">cb</span><span class=\"mtk1\">) </span><span class=\"mtk4\">=&gt;</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk11\">cb</span><span class=\"mtk1\">(</span><span class=\"mtk4\">null</span><span class=\"mtk1\">, </span><span class=\"mtk8\">&quot;uploads/&quot;</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  },</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk11\">filename</span><span class=\"mtk12\">:</span><span class=\"mtk1\"> (</span><span class=\"mtk12\">req</span><span class=\"mtk1\">, </span><span class=\"mtk12\">file</span><span class=\"mtk1\">, </span><span class=\"mtk12\">cb</span><span class=\"mtk1\">) </span><span class=\"mtk4\">=&gt;</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk11\">cb</span><span class=\"mtk1\">(</span><span class=\"mtk4\">null</span><span class=\"mtk1\">, </span><span class=\"mtk10\">Date</span><span class=\"mtk1\">.</span><span class=\"mtk11\">now</span><span class=\"mtk1\">() + </span><span class=\"mtk8\">&quot;-&quot;</span><span class=\"mtk1\"> + </span><span class=\"mtk12\">file</span><span class=\"mtk1\">.</span><span class=\"mtk12\">originalname</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  },</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">})</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">const</span><span class=\"mtk1\"> </span><span class=\"mtk12\">uploadStorage</span><span class=\"mtk1\"> = </span><span class=\"mtk11\">multer</span><span class=\"mtk1\">({ </span><span class=\"mtk12\">storage:</span><span class=\"mtk1\"> </span><span class=\"mtk12\">storage</span><span class=\"mtk1\"> })</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk3\">// Single file</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk12\">app</span><span class=\"mtk1\">.</span><span class=\"mtk11\">post</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;/upload/single&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk12\">uploadStorage</span><span class=\"mtk1\">.</span><span class=\"mtk11\">single</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;file&quot;</span><span class=\"mtk1\">), (</span><span class=\"mtk12\">req</span><span class=\"mtk1\">, </span><span class=\"mtk12\">res</span><span class=\"mtk1\">) </span><span class=\"mtk4\">=&gt;</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk10\">console</span><span class=\"mtk1\">.</span><span class=\"mtk11\">log</span><span class=\"mtk1\">(</span><span class=\"mtk12\">req</span><span class=\"mtk1\">.</span><span class=\"mtk12\">file</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> </span><span class=\"mtk12\">res</span><span class=\"mtk1\">.</span><span class=\"mtk11\">send</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;Single file&quot;</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">})</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk3\">//Multiple files</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk12\">app</span><span class=\"mtk1\">.</span><span class=\"mtk11\">post</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;/upload/multiple&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk12\">uploadStorage</span><span class=\"mtk1\">.</span><span class=\"mtk11\">array</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;file&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk7\">10</span><span class=\"mtk1\">), (</span><span class=\"mtk12\">req</span><span class=\"mtk1\">, </span><span class=\"mtk12\">res</span><span class=\"mtk1\">) </span><span class=\"mtk4\">=&gt;</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk10\">console</span><span class=\"mtk1\">.</span><span class=\"mtk11\">log</span><span class=\"mtk1\">(</span><span class=\"mtk12\">req</span><span class=\"mtk1\">.</span><span class=\"mtk12\">files</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> </span><span class=\"mtk12\">res</span><span class=\"mtk1\">.</span><span class=\"mtk11\">send</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;Multiple files&quot;</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">})</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk12\">app</span><span class=\"mtk1\">.</span><span class=\"mtk11\">listen</span><span class=\"mtk1\">(</span><span class=\"mtk7\">3000</span><span class=\"mtk1\"> || </span><span class=\"mtk12\">process</span><span class=\"mtk1\">.</span><span class=\"mtk12\">env</span><span class=\"mtk1\">.</span><span class=\"mtk12\">PORT</span><span class=\"mtk1\">, () </span><span class=\"mtk4\">=&gt;</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk10\">console</span><span class=\"mtk1\">.</span><span class=\"mtk11\">log</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;Server on...&quot;</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">})</span></span></code></pre>\n<p>Now it's up to you!</p>\n<style class=\"grvsc-styles\">\n  .grvsc-container {\n    overflow: auto;\n    -webkit-overflow-scrolling: touch;\n    padding-top: 1rem;\n    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));\n    padding-bottom: 1rem;\n    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));\n    border-radius: 8px;\n    border-radius: var(--grvsc-border-radius, 8px);\n    font-feature-settings: normal;\n  }\n  \n  .grvsc-code {\n    display: inline-block;\n    min-width: 100%;\n  }\n  \n  .grvsc-line {\n    display: inline-block;\n    box-sizing: border-box;\n    width: 100%;\n    padding-left: 1.5rem;\n    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));\n    padding-right: 1.5rem;\n    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));\n  }\n  \n  .grvsc-line-highlighted {\n    background-color: var(--grvsc-line-highlighted-background-color, transparent);\n    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, transparent);\n  }\n  \n  .dark-default-dark {\n    background-color: #1E1E1E;\n    color: #D4D4D4;\n  }\n  .dark-default-dark .mtk12 { color: #9CDCFE; }\n  .dark-default-dark .mtk1 { color: #D4D4D4; }\n  .dark-default-dark .mtk4 { color: #569CD6; }\n  .dark-default-dark .mtk11 { color: #DCDCAA; }\n  .dark-default-dark .mtk8 { color: #CE9178; }\n  .dark-default-dark .mtk7 { color: #B5CEA8; }\n  .dark-default-dark .mtk10 { color: #4EC9B0; }\n  .dark-default-dark .mtk3 { color: #6A9955; }\n  .dark-default-dark .mtk15 { color: #C586C0; }\n</style>","frontmatter":{"date":"October 12, 2020","updated_date":null,"description":"Learn how to upload files in a NodeJS application using Multer, Multer is a middleware for handling multipart/form-data that is used to send files in forms.","title":"Upload files using NodeJS + Multer","tags":["NodeJs","Express","Multer"],"pinned":null,"coverImage":{"childImageSharp":{"fluid":{"aspectRatio":1.5037593984962405,"src":"/static/7abf157b1bfeb7c65d7e338a620ac875/58556/node-multer-upload.webp","srcSet":"/static/7abf157b1bfeb7c65d7e338a620ac875/61e93/node-multer-upload.webp 200w,\n/static/7abf157b1bfeb7c65d7e338a620ac875/1f5c5/node-multer-upload.webp 400w,\n/static/7abf157b1bfeb7c65d7e338a620ac875/58556/node-multer-upload.webp 800w,\n/static/7abf157b1bfeb7c65d7e338a620ac875/99238/node-multer-upload.webp 1200w","sizes":"(max-width: 800px) 100vw, 800px"}}},"author":{"id":"Gabriel Rabelo","github":"gabrielrab","avatar":null}}}},{"node":{"excerpt":"Introduction Learning Deep Features for Discriminative Localization: Machine learning and Deep learning are gaining traction in today’s…","fields":{"slug":"/engineering/class-activation-mapping/"},"html":"<h3 id=\"introduction\" style=\"position:relative;\"><a href=\"#introduction\" aria-label=\"introduction permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Introduction</h3>\n<h4 id=\"learning-deep-features-for-discriminative-localization\" style=\"position:relative;\"><a href=\"#learning-deep-features-for-discriminative-localization\" aria-label=\"learning deep features for discriminative localization permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Learning Deep Features for Discriminative Localization:</h4>\n<p>Machine learning and Deep learning are gaining traction in today’s world and are making significant and unimaginable progress in almost every industry. However, with the increase in complexity and accuracy of these algorithms, the interpretability of these is at stake- especially the deep learning models which take in more than a million parameters for complex, convoluted models. Class Activation Mapping (CAM) is one such technique which helps us in enhancing the interpretability of such complex models.</p>\n<h3 id=\"class-activation-mapping-cams\" style=\"position:relative;\"><a href=\"#class-activation-mapping-cams\" aria-label=\"class activation mapping cams permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Class Activation Mapping (CAMs)</h3>\n<p>For a particular class (or category), Class activation mapping basically indicates the discriminative region of the image, which influenced the deep learning model to make the decision. The architecture is very similar to a convolutional neural network. It comprises several convolution layers, with the layer just before the final output performing Global Average Pooling. The features that are obtained are fed into the fully connected neural network layer governed by the softmax activation function and thus, output us the required probabilities. The importance of the weights with respect to a category can be found out by projecting back the weights onto the last convolution layer’s feature map. </p>\n<h3 id=\"global-average-pooling-gap-vs-global-max-pooling-gmp\" style=\"position:relative;\"><a href=\"#global-average-pooling-gap-vs-global-max-pooling-gmp\" aria-label=\"global average pooling gap vs global max pooling gmp permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Global Average Pooling (GAP) vs Global Max Pooling (GMP)</h3>\n<p>The Global Average Pooling (GAP) is preferred over Global Max Pooling (GMP) because GAP helps us in identifying the full extent of the object as compared to the GMP layer, which identifies one discriminative part. In Global Average Pooling, an average is taken across all the activation maps which help us to find all the possible discriminative regions present in them. Contrary to this, the Global Max Pooling method just considers the most discriminative region. Hence, Global Average Pooling showed better results than Global Max Pooling.</p>\n<h3 id=\"mathematical-equations-governing-cams\" style=\"position:relative;\"><a href=\"#mathematical-equations-governing-cams\" aria-label=\"mathematical equations governing cams permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Mathematical equations governing CAMs</h3>\n<p>Let <img src=\"https://latex.codecogs.com/png.latex?f%28x%2Cy%29\" alt=\"Equation 1\"> be the activation map of unit <img src=\"https://latex.codecogs.com/png.latex?k\" alt=\"Equation 2\"> in the last convolutional layer at spatial location <img src=\"https://latex.codecogs.com/png.latex?%28x%2Cy%29\" alt=\"Equation 3\">.</p>\n<p><em>The result of GAP is represented as:-</em></p>\n<p><img src=\"https://latex.codecogs.com/png.latex?F_%7Bk%7D%3D%20%5Csum_%7Bx%2Cy%7Df_%7Bk%7D%28x%2Cy%29\" alt=\"Equation 4\"></p>\n<p><em>For a class c, an input to the softmax will be:-</em></p>\n<p><img src=\"https://latex.codecogs.com/png.latex?S_%7Bc%7D%3D%20%5Csum_%7Bk%7Dw%5E%7Bc%7D_%7Bk%7DF_%7Bk%7D\" alt=\"Equation 5\"></p>\n<p><em>Output of Softmax layer:-</em></p>\n<p><img src=\"https://latex.codecogs.com/png.latex?P_c%3D%20%5Cfrac%7Be%5E%7BS_c%7D%7D%7B%5Csum_ce%5E%7BS_c%7D%7D\" alt=\"Equation 6\"></p>\n<p>Thus, <strong>the final equation</strong> for an activation map of class c would be:- </p>\n<p><img src=\"https://latex.codecogs.com/png.latex?M_%7Bc%7D%28x%2Cy%29%3D%5Csum_%7Bk%7Dw%5E%7Bc%7D_%7Bk%7Df_%7Bk%7D%28x%2Cy%29\" alt=\"Equation 7\">  </p>\n<h3 id=\"weakly-supervised-object-localization\" style=\"position:relative;\"><a href=\"#weakly-supervised-object-localization\" aria-label=\"weakly supervised object localization permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Weakly-supervised Object Localization</h3>\n<p>The localization ability of the CAM method was put to the test when they were trained on the ILSVRC 2014 benchmark dataset. The CAM technique was used on popular CNN models like AlexNet, VGGNet and GoogLeNet by tweaking their models and fitting a GAP layer (similar to the CAM architecture) towards the end. This modified model was giving astounding results with the GAP layer as compared to their traditional architecture in terms of discriminative localization.</p>\n<h3 id=\"deep-features-for-generic-localization\" style=\"position:relative;\"><a href=\"#deep-features-for-generic-localization\" aria-label=\"deep features for generic localization permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Deep Features for Generic Localization</h3>\n<p>After applying a CAM architecture to fine-grained recognition and pattern discovery (like discovering informative objects in the scenes, concept localization in weakly labelled images, weakly supervised text detector and interpreting visual question answering), we can infer that feature capturing and localization was far more accurate in the CAM based GAP layer architecture, as the complete extent of the features were captured.\nVisualizing Class-specific Units:-\nWhen we use the GAP layer and the ranked softmax weight, we can directly visualize the units, which are the most discriminative for a particular class. Thus, CNN actually learns a bag of words, where each word is a discriminative class-specific unit. A combination of these class-specific units helps to guide CNNs in classifying each image.</p>\n<h3 id=\"conclusion\" style=\"position:relative;\"><a href=\"#conclusion\" aria-label=\"conclusion permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Conclusion:</h3>\n<p>CAMs are a great technique to interpret the information from the CNN models. However, the disadvantage of CAMs is that they can be noisy, and there might be some loss of spatial information. Hence, the Grad-CAM architecture and the Score-CAM architecture were built upon the CAM architecture to improve the accuracy, feature capturing and retain precise spatial information.</p>\n<style class=\"grvsc-styles\">\n  .grvsc-container {\n    overflow: auto;\n    -webkit-overflow-scrolling: touch;\n    padding-top: 1rem;\n    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));\n    padding-bottom: 1rem;\n    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));\n    border-radius: 8px;\n    border-radius: var(--grvsc-border-radius, 8px);\n    font-feature-settings: normal;\n  }\n  \n  .grvsc-code {\n    display: inline-block;\n    min-width: 100%;\n  }\n  \n  .grvsc-line {\n    display: inline-block;\n    box-sizing: border-box;\n    width: 100%;\n    padding-left: 1.5rem;\n    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));\n    padding-right: 1.5rem;\n    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));\n  }\n  \n  .grvsc-line-highlighted {\n    background-color: var(--grvsc-line-highlighted-background-color, transparent);\n    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, transparent);\n  }\n  \n</style>","frontmatter":{"date":"October 10, 2020","updated_date":null,"description":"Learn about the importance of the explainability of deep learning models and Class Activation Map Technique","title":"Class Activation Mapping in Deep Learning","tags":["Explainable AI","Deep Learning","CNN","Machine Learning"],"pinned":null,"coverImage":{"childImageSharp":{"fluid":{"aspectRatio":1.5037593984962405,"src":"/static/f00bfab91c9b545daddfe5a17abc22c8/58556/Cover.webp","srcSet":"/static/f00bfab91c9b545daddfe5a17abc22c8/61e93/Cover.webp 200w,\n/static/f00bfab91c9b545daddfe5a17abc22c8/1f5c5/Cover.webp 400w,\n/static/f00bfab91c9b545daddfe5a17abc22c8/58556/Cover.webp 800w,\n/static/f00bfab91c9b545daddfe5a17abc22c8/99238/Cover.webp 1200w","sizes":"(max-width: 800px) 100vw, 800px"}}},"author":{"id":"Ankit Choraria","github":"Ankit810","avatar":null}}}}]},"markdownRemark":{"excerpt":"Introduction Ever wondered how apps like Spotify, Netflix, or Slack manage seamless login experiences across devices? Many of them use JWT…","fields":{"slug":"/engineering/how-to-integrate-jwt/"},"html":"<h2 id=\"introduction\" style=\"position:relative;\"><a href=\"#introduction\" aria-label=\"introduction permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Introduction</h2>\n<p>Ever wondered how apps like Spotify, Netflix, or Slack manage seamless login experiences across devices? Many of them use JWT, or JSON Web Tokens, a compact, stateless method for securely transmitting user identity and session data across services.</p>\n<p>With JWT token authentication, identity information is embedded in a signed token, allowing you to maintain user sessions without server-side storage. This approach is highly scalable and ideal for modern architectures like SPAs, mobile apps, and microservices.</p>\n<p>In this blog, we’ll walk you through what is JWT, why use it, and how to implement JWT authentication using LoginRadius. </p>\n<p>You’ll learn what JWT is, why it’s effective, and how it works in real-world applications. We'll cover both integration methods (IDX and Direct API), generating your signing key, managing sessions, storing the JWT token securely, and applying best practices throughout.</p>\n<p>Whether you're a developer, product manager, or IAM architect, this guide offers a complete foundation for implementing JWT token authentication into your application stack.</p>\n<h2 id=\"what-is-jwt\" style=\"position:relative;\"><a href=\"#what-is-jwt\" aria-label=\"what is jwt permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>What is JWT?</h2>\n<p><a href=\"https://www.loginradius.com/blog/engineering/jwt/\">JSON Web Token (JWT)</a> is an open standard (RFC 7519) used to transmit information securely between parties as a JSON object. It’s compact, self-contained, and digitally signed, making it a reliable format for authentication and authorization across modern applications.</p>\n<p>A JWT consists of three parts:</p>\n<ol>\n<li><strong>Header –</strong> Contains metadata like the type of token and signing algorithm (e.g., HS256).</li>\n<li><strong>Payload –</strong> Stores the actual data or “claims,” such as user ID, roles, and token expiry.</li>\n<li><strong>Signature –</strong> A cryptographic hash that ensures the token hasn’t been tampered with.</li>\n</ol>\n<p><em>Example of a token structure:</em></p>\n<p>&#x3C;base64Header>.&#x3C;base64Payload>.&#x3C;signature></p>\n<h2 id=\"why-use-jwt\" style=\"position:relative;\"><a href=\"#why-use-jwt\" aria-label=\"why use jwt permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Why Use JWT?</h2>\n<ul>\n<li><strong>Stateless Authentication</strong>: No server-side session storage is needed — the token holds all necessary user info. </li>\n<li><strong>Portable</strong>: Works seamlessly across domains, services, and APIs. </li>\n<li><strong>Scalable</strong>: Ideal for microservices, SPAs, mobile apps, and serverless functions. </li>\n<li><strong>Interoperable</strong>: JWTs are supported across many languages and frameworks.</li>\n</ul>\n<h2 id=\"how-jwt-works\" style=\"position:relative;\"><a href=\"#how-jwt-works\" aria-label=\"how jwt works permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>How JWT Works?</h2>\n<p><img src=\"/f29edbf2978577390c7ffa02e9bc4dda/lr-JWT-authentication.webp\" alt=\"Flowchart illustrating LoginRadius JWT authentication via Identity Provider (IDP), showing user redirection from login icon to login page, authentication with IDP, JWT token validation, and subsequent redirection to the customer&#x27;s website or error page based on validation results.\"></p>\n<ol>\n<li>A user logs in with credentials. </li>\n<li>Your app (or identity provider like LoginRadius) issues a signed JWT. </li>\n<li>The client stores the token and sends it with each request (usually in the Authorization header). </li>\n<li>The server validates the token’s signature and claims. </li>\n<li>If valid, access is granted — without any session stored on the backend.</li>\n</ol>\n<p>JWT simplifies identity verification, especially when you're building apps that talk to APIs or need to scale without centralized session storage.</p>\n<h2 id=\"jwt-authentication-with-loginradius-overview\" style=\"position:relative;\"><a href=\"#jwt-authentication-with-loginradius-overview\" aria-label=\"jwt authentication with loginradius overview permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>JWT Authentication with LoginRadius: Overview</h2>\n<p>LoginRadius provides robust support for JWT (JSON Web Token) authentication, which allows for flexible and secure access control across different digital platforms. Whether you're building a fully custom identity flow or using a pre-built interface, the platform supports various integration approaches depending on your architecture.</p>\n<p>If you're looking to understand how to implement JWT token authentication effectively, LoginRadius offers two primary implementation models that cater to different levels of customization and control:</p>\n<h3 id=\"1-idx-implementation--jwt-through-a-hosted-login-page\" style=\"position:relative;\"><a href=\"#1-idx-implementation--jwt-through-a-hosted-login-page\" aria-label=\"1 idx implementation  jwt through a hosted login page permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>1. IDX Implementation – JWT through a Hosted Login Page</h3>\n<p>The IDX-hosted login approach enables secure, standards-compliant, JWT-based authentication without requiring you to build a custom login interface. This is a strategic option for fast, compliant, and user-friendly deployments.</p>\n<ul>\n<li>The Identity Experience Framework (IDX) comes with a fully custom branded hosted login page.</li>\n<li>Once the user logs in and gets enrolled, the user’s JWTs are automatically generated and issued. These tokens can be utilized for managing user sessions and accessing the APIs.</li>\n<li>This approach simplifies deployment without compromising on user experience and security standards.</li>\n</ul>\n<h3 id=\"configuration-steps\" style=\"position:relative;\"><a href=\"#configuration-steps\" aria-label=\"configuration steps permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a><strong>Configuration Steps:</strong></h3>\n<ol>\n<li>Enable JWT Login</li>\n<li>Go to <a href=\"https://console.loginradius.com/authentication/authentication-configuration\">authentication configuration settings</a> and enable JWT Login in the Admin Console.</li>\n</ol>\n<p><img src=\"/9fb19dd9c88c7916aeebd03ab6e661b7/lr-admin-console.webp\" alt=\"Screenshot of LoginRadius Admin Console showing JWT Custom IDP configuration interface with options for provider name, algorithm (HS256), key entry, clock skew, and expiration time settings.\"></p>\n<ol start=\"2\">\n<li>Specify your signing algorithm and expiry policy, and define your JWT Secret Key.</li>\n<li>Input a secure JWT signing key.</li>\n<li>Specify token expiry duration (e.g., 15–60 minutes)</li>\n<li>Select the desired algorithm —HS256 for symmetric signing (same key signs and verifies)</li>\n<li>RS256 for asymmetric signing, where LoginRadius securely stores the private key used to sign the JWT.</li>\n<li>Your app or backend service uses the public key to validate the token signature.</li>\n<li>LoginRadius provides a JWKS (JSON Web Key Set) endpoint to dynamically fetch and rotate public keys, ensuring trust without key exposure.</li>\n<li>Update IDX Template for Callback</li>\n<li>Modify your IDX login page template to retrieve the JWT post-login. You can access the token via redirect URL parameters or secure JavaScript callbacks.</li>\n</ol>\n<h3 id=\"example-response\" style=\"position:relative;\"><a href=\"#example-response\" aria-label=\"example response permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Example Response:</h3>\n<p>{</p>\n<p>  \"access_token\": \"eyJhbGciOiJIUzI1NiIsInR...\",</p>\n<p>  \"expires_in\": 1800</p>\n<p>}</p>\n<p>This integration approach works best for all teams that want effective identity workflows without the complexity of building proprietary login screens, something that is crucial for customer portals, onboarding of mobile applications, and even managing access for business partners.</p>\n<h3 id=\"2-direct-api-implementation--self-managed-login\" style=\"position:relative;\"><a href=\"#2-direct-api-implementation--self-managed-login\" aria-label=\"2 direct api implementation  self managed login permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>2. Direct API Implementation – Self Managed Login</h3>\n<p>If you’re building a custom login UI or working in a headless environment, LoginRadius lets you generate and handle JWTs directly through its <a href=\"https://www.loginradius.com/docs/api/v2/customer-identity-api/\">Authentication APIs</a>. Here’s how you can programmatically perform token authentication using the classic method:</p>\n<ul>\n<li>For custom front-end applications, LR offers an API to authenticate users and issue JWT tokens.</li>\n<li>In response to the login request, the developers are provided with signed tokens that can be validated on the client’s side or by downstream services.</li>\n<li>This method is best fit for enterprise applications that have complex custom workflows or are designed to be embedded into other applications.</li>\n</ul>\n<h3 id=\"configuration-steps-1\" style=\"position:relative;\"><a href=\"#configuration-steps-1\" aria-label=\"configuration steps 1 permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a><strong>Configuration Steps:</strong></h3>\n<h4 id=\"step-1-authenticate-via-api\" style=\"position:relative;\"><a href=\"#step-1-authenticate-via-api\" aria-label=\"step 1 authenticate via api permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Step 1: Authenticate via API:</h4>\n<ul>\n<li>\n<p>Send a POST login request to the LR Authentication URL: </p>\n<p>POST /identity/v2/auth/login</p>\n</li>\n</ul>\n<p>Include the user’s credentials (email + password) in the request body.</p>\n<h4 id=\"step-2-get-jwt-in-response\" style=\"position:relative;\"><a href=\"#step-2-get-jwt-in-response\" aria-label=\"step 2 get jwt in response permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Step 2: Get JWT in Response</h4>\n<ul>\n<li>If the user credentials are authentic, then the JWT token will be available in response.</li>\n</ul>\n<p>{</p>\n<p> \"access_token\": \"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...\",</p>\n<p> \"expires_in\": 3600</p>\n<p>}</p>\n<h4 id=\"step-3-jwt-decoding-and-validation\" style=\"position:relative;\"><a href=\"#step-3-jwt-decoding-and-validation\" aria-label=\"step 3 jwt decoding and validation permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Step 3: JWT Decoding and Validation</h4>\n<ul>\n<li>Use any JWT library (e.g., jsonwebtoken for Node.js or pyjwt for Python) to decode the token.</li>\n<li>Validate the signature using your configured secret key.</li>\n<li>Confirm claims like exp, iat, aud, and iss.</li>\n</ul>\n<h4 id=\"step-4-set-custom-claims-optional\" style=\"position:relative;\"><a href=\"#step-4-set-custom-claims-optional\" aria-label=\"step 4 set custom claims optional permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Step 4: Set Custom Claims (Optional)</h4>\n<p>With LoginRadius, it is possible to customize the payload to include user roles and/or any additional metadata. You can set custom JWT claims on the Admin Console.</p>\n<p>With this method, you have complete customization over login flows while using LoginRadius to issue signed JWTs for user session management.</p>\n<p><strong>NOTE-</strong> With either method, LoginRadius ensures that JWTs are securely signed, optionally short-lived, and compatible with standard token validation libraries, making integration seamless for everyone.</p>\n<p>To get started with JWT implementation, you can<a href=\"https://www.loginradius.com/docs/single-sign-on/federated-sso/jwt-login/jwt-implementation-guide/\"> read our complete developer documentation</a>. </p>\n<h2 id=\"hosted-login-vs-direct-api\" style=\"position:relative;\"><a href=\"#hosted-login-vs-direct-api\" aria-label=\"hosted login vs direct api permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Hosted Login vs Direct API</h2>\n<p><img src=\"/15ec02ac98d24a9f1f28e5d0f06b9174/IDX-vs-Direct-API-JWT.webp\" alt=\"Illustration showing IDX vs Direct API JWT flow diagram comparing LoginRadius JWT authentication methods via Hosted Login Page (IDX) and Custom Login UI using Direct API, illustrating user login, JWT issuance, and token return process.\"></p>\n<h2 id=\"what-is-session-management-and-how-it-works-with-jwt\" style=\"position:relative;\"><a href=\"#what-is-session-management-and-how-it-works-with-jwt\" aria-label=\"what is session management and how it works with jwt permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>What is Session Management and How It Works with JWT</h2>\n<p><a href=\"https://www.loginradius.com/blog/identity/user-session-management/\">Session management </a>is how your app keeps track of a user after they log in so they don’t have to prove who they are with every request.</p>\n<p>In traditional apps, sessions are stored on the server using session IDs. Every time a request comes in, the server checks that session ID to verify the user.</p>\n<p>In modern apps, especially SPAs and APIs, JWTs are used to manage sessions without needing server-side storage; this is called stateless session management. The token itself carries the user’s identity, roles, and expiration details. As long as the token is valid, the user stays logged in.</p>\n<p>Good session management ensures:</p>\n<ul>\n<li>Security against session hijacking</li>\n<li>Fast user validation without hitting a database</li>\n<li>Smooth experiences with token refresh strategies</li>\n</ul>\n<h2 id=\"how-loginradius-handles-session-management-with-jwt\" style=\"position:relative;\"><a href=\"#how-loginradius-handles-session-management-with-jwt\" aria-label=\"how loginradius handles session management with jwt permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>How LoginRadius Handles Session Management with JWT:</h2>\n<ol>\n<li>\n<p>User Logs In </p>\n<ul>\n<li>LoginRadius returns an access token (JWT) and, optionally, a refresh token.</li>\n</ul>\n</li>\n<li>\n<p>Client Stores the Token </p>\n<ul>\n<li>Access tokens are stored in memory, sessionStorage, or secure cookies. </li>\n<li>They’re sent on every request via the Authorization: Bearer header. </li>\n</ul>\n</li>\n<li>\n<p>Access Token Expiry </p>\n<ul>\n<li>These tokens are short-lived by design (e.g., 15–30 minutes). </li>\n<li>Once expired, the client can use the refresh token to request a new access token. </li>\n</ul>\n</li>\n<li>\n<p>Token Renewal </p>\n<ul>\n<li>LoginRadius validates the refresh token and issues a new JWT, i.e., no user re-authentication is needed. </li>\n<li>Refresh tokens can be revoked at any time.</li>\n</ul>\n</li>\n<li>Logout and Token Revocation Strategy</li>\n</ol>\n<p>When the user logs out, both the access token and refresh token should be cleared from client storage.</p>\n<ul>\n<li>The refresh token can be explicitly revoked via the LoginRadius API, terminating the ability to renew sessions. </li>\n<li>\n<p>However, access tokens are stateless and cannot be revoked mid-lifecycle unless: </p>\n<ul>\n<li>You maintain a blacklist of token IDs (jti claims) and check them on each request. </li>\n<li>You use short-lived access tokens to limit exposure naturally. </li>\n<li>Or, you rotate your JWT signing key, invalidating all previously issued tokens. </li>\n</ul>\n</li>\n</ul>\n<p>Combining these strategies gives you greater control over token misuse and enables a robust, enterprise-grade logout flow. </p>\n<p><a href=\"https://www.loginradius.com/resource/whitepaper/secure-api-using-oauth2\"><img src=\"/e55ae4bbc8ce62e13f03e46e29ebe7cc/api-economy.webp\" alt=\"illustration showing LoginRadius free downloadable resource named API economy is transforming digitization: how to secure it using oauth 2.0.\"></a></p>\n<h2 id=\"how-to-store-jwt-tokens\" style=\"position:relative;\"><a href=\"#how-to-store-jwt-tokens\" aria-label=\"how to store jwt tokens permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>How to Store JWT Tokens?</h2>\n<p>When you implement JWT-based authentication, the client (browser or mobile app) needs a way to store the access token and, optionally, the refresh token after they are issued by the authentication server. This stored token is then attached to every subsequent request to prove the user's identity.</p>\n<p>Choosing where to store the JWT is a crucial security decision. The most common storage options are:</p>\n<ul>\n<li>localStorage</li>\n<li>sessionStorage</li>\n<li>HTTP-only cookies</li>\n</ul>\n<p>Each option has trade-offs between security, accessibility, and persistence, and the right choice depends on your application's architecture and threat model.</p>\n<h4 id=\"recommended-storage-strategy\" style=\"position:relative;\"><a href=\"#recommended-storage-strategy\" aria-label=\"recommended storage strategy permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Recommended Storage Strategy</h4>\n<ul>\n<li>\n<p>Access Tokens </p>\n<ul>\n<li>For SPAs: store in memory or sessionStorage for short-term access </li>\n<li>If stored in the browser, protect against XSS </li>\n</ul>\n</li>\n<li>\n<p>Refresh Tokens</p>\n<ul>\n<li>Always store the JWT refresh token in HTTP-only secure cookies to prevent JavaScript access. This adds a critical layer of protection against XSS attacks.</li>\n<li>Combine with SameSite=Strict or SameSite=Lax attributes to mitigate CSRF risks and ensure the JWT refresh token is only sent in intended contexts.</li>\n</ul>\n</li>\n</ul>\n<h2 id=\"best-practices-for-storing-jwts\" style=\"position:relative;\"><a href=\"#best-practices-for-storing-jwts\" aria-label=\"best practices for storing jwts permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Best Practices for Storing JWTs</h2>\n<ol>\n<li>Never store sensitive tokens (like refresh tokens) in localStorage or sessionStorage.</li>\n<li>Use Secure and HttpOnly flags with cookies to prevent JavaScript access and ensure transmission only over HTTPS.</li>\n<li>Set the SameSite=Strict or Lax attribute on cookies to protect against CSRF.</li>\n<li>Use short-lived access tokens and rotate refresh tokens regularly.</li>\n<li>Implement CSP (Content Security Policy) to reduce XSS risk.</li>\n<li>Avoid storing any tokens in frontend code (e.g., hardcoded in JS files).</li>\n</ol>\n<h2 id=\"conclusion\" style=\"position:relative;\"><a href=\"#conclusion\" aria-label=\"conclusion permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Conclusion</h2>\n<p>JWT authentication with LoginRadius offers a modern, stateless approach to managing sessions across distributed systems. The IDX integration is ideal for rapid deployment, while the Direct API model is best for organizations needing deep customization and integration flexibility.</p>\n<p>With robust token signing, refresh capabilities, and centralized control, LoginRadius provides a future-ready foundation for secure, scalable identity architecture. <a href=\"https://www.loginradius.com/contact-us?utm_source=blog&#x26;utm_medium=web&#x26;utm_campaign=how-to-integrate-jwt\">Contact us</a> to know more about JWT authentication and implementation guide. </p>\n<h2 id=\"faqs\" style=\"position:relative;\"><a href=\"#faqs\" aria-label=\"faqs permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>FAQs</h2>\n<h3 id=\"1-what-is-jwt-authentication-used-for\" style=\"position:relative;\"><a href=\"#1-what-is-jwt-authentication-used-for\" aria-label=\"1 what is jwt authentication used for permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>1. What is JWT authentication used for?</h3>\n<p><strong>A:</strong> JWT authentication securely verifies user identities, enabling stateless session management across web, mobile apps, and microservices without server-side session storage.</p>\n<h3 id=\"2-how-does-loginradius-simplify-jwt-integration\" style=\"position:relative;\"><a href=\"#2-how-does-loginradius-simplify-jwt-integration\" aria-label=\"2 how does loginradius simplify jwt integration permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>2. How does LoginRadius simplify JWT integration?</h3>\n<p><strong>A:</strong> LoginRadius simplifies JWT integration by offering hosted <a href=\"https://www.loginradius.com/docs/single-sign-on/federated-sso/jwt-login/jwt-implementation-guide/\">IDX login pages </a>and direct API-based authentication methods, enabling rapid deployment and deep customization.</p>\n<h3 id=\"3-is-jwt-authentication-secure\" style=\"position:relative;\"><a href=\"#3-is-jwt-authentication-secure\" aria-label=\"3 is jwt authentication secure permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>3. Is JWT authentication secure?</h3>\n<p><strong>A:</strong> Yes, JWT authentication is secure when implemented with best practices like short-lived tokens, secure storage methods, signature validation, and refresh token rotation.</p>\n<h3 id=\"4-can-jwt-tokens-be-revoked-with-loginradius\" style=\"position:relative;\"><a href=\"#4-can-jwt-tokens-be-revoked-with-loginradius\" aria-label=\"4 can jwt tokens be revoked with loginradius permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>4. Can JWT tokens be revoked with LoginRadius?</h3>\n<p><strong>A:</strong> Yes, LoginRadius allows<a href=\"https://www.loginradius.com/docs/api/v2/customer-identity-api/refresh-token/revoke-refresh-token/?q=revoke+jwt\"> revocation of JWT</a> refresh tokens explicitly, and supports strategies like short-lived tokens and key rotation to manage token lifecycles securely.</p>\n<style class=\"grvsc-styles\">\n  .grvsc-container {\n    overflow: auto;\n    -webkit-overflow-scrolling: touch;\n    padding-top: 1rem;\n    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));\n    padding-bottom: 1rem;\n    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));\n    border-radius: 8px;\n    border-radius: var(--grvsc-border-radius, 8px);\n    font-feature-settings: normal;\n  }\n  \n  .grvsc-code {\n    display: inline-block;\n    min-width: 100%;\n  }\n  \n  .grvsc-line {\n    display: inline-block;\n    box-sizing: border-box;\n    width: 100%;\n    padding-left: 1.5rem;\n    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));\n    padding-right: 1.5rem;\n    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));\n  }\n  \n  .grvsc-line-highlighted {\n    background-color: var(--grvsc-line-highlighted-background-color, transparent);\n    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, transparent);\n  }\n  \n</style>","frontmatter":{"date":"April 15, 2025","updated_date":null,"description":"Discover JWT (JSON Web Token) authentication, its advantages, and how to integrate it seamlessly using LoginRadius' hosted IDX and Direct API methods for secure, scalable identity management.","title":"JWT Authentication with LoginRadius: Quick Integration Guide","tags":["JWT","JSON Web Token","Authentication","Authorization"],"pinned":null,"coverImage":{"childImageSharp":{"fluid":{"aspectRatio":0.7782101167315175,"src":"/static/4cedb7829f98208cbc6d5a9aea4e983d/58556/how-to-integrate-jwt.webp","srcSet":"/static/4cedb7829f98208cbc6d5a9aea4e983d/61e93/how-to-integrate-jwt.webp 200w,\n/static/4cedb7829f98208cbc6d5a9aea4e983d/1f5c5/how-to-integrate-jwt.webp 400w,\n/static/4cedb7829f98208cbc6d5a9aea4e983d/58556/how-to-integrate-jwt.webp 800w,\n/static/4cedb7829f98208cbc6d5a9aea4e983d/1cc9f/how-to-integrate-jwt.webp 896w","sizes":"(max-width: 800px) 100vw, 800px"}}},"author":{"id":"Kundan Singh","github":null,"avatar":null}}}},"pageContext":{"limit":6,"skip":144,"currentPage":25,"type":"//engineering//","numPages":53,"pinned":"5c425581-f474-5ae9-abe7-cf5342db2aaa"}},"staticQueryHashes":["1171199041","1384082988","2100481360","23180105","528864852"]}