{"componentChunkName":"component---src-templates-blog-list-template-js","path":"/engineering/44","result":{"data":{"allMarkdownRemark":{"edges":[{"node":{"excerpt":"1. Secure your server Many known attacks are possible only once physically accessing a machine. For this reason, it is best to have the…","fields":{"slug":"/engineering/is-your-database-secured-think-again/"},"html":"<p><strong>1. Secure your server</strong></p>\n<p>Many known attacks are possible only once physically accessing a machine. For this reason, it is best to have the application server and the database server on different machines. If this is not possible, greater care must be taken, Otherwise, by executing remote commands via an application server, an attacker may be able to harm your database even without permissions. For this reason, any service running on the same machine as the database should be granted the lowest possible permission that still allows the service to operate.</p>\n<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 494px; \"\n    >\n      <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 38.8663967611336%; position: relative; bottom: 0; left: 0; background-image: url('data:image/webp;base64,UklGRlgAAABXRUJQVlA4IEwAAADwAwCdASoUAAgAPtFUpEuoJKOhsAgBABoJZwC/OCHc83juPOd7OCCAAP71Oj1w24ZpUlEtIv74vuzWMg4mltCrNbwLBfABU+IBCaYA'); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"server-network-structure\"\n        title=\"server-network-structure\"\n        src=\"/static/8c877c4c84b77c6261451b2490e6c2b0/32f69/server-network-structure.webp\"\n        srcset=\"/static/8c877c4c84b77c6261451b2490e6c2b0/32f69/server-network-structure.webp 494w\"\n        sizes=\"(max-width: 494px) 100vw, 494px\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        loading=\"lazy\"\n      />\n    </span><br>\nDo not forget to install the whole security package: Antivirus and Anti-spam, Firewall, and all of the security packages recommended by your operating system's vendor. Also, do not forget to spend 10 minutes thinking of your server's physical location - in the wrong location, your server can be stolen, flooded, harmed by wild animals or vagrants.</p>\n<p><strong>2. Localhost Security or Disable or restrict remote access</strong></p>\n<p>Consider whether MySQL will be retrieved from the system or directly accessed from its own server. On the off chance that remote access is utilized, guarantee that just characterized hosts can get to the server. This is commonly done through TCP wrappers, IP tables, or some other firewall programming or hardware accessibility tools.<br>\nTo confine MySQL from opening a network socket, the accompanying parameter ought to be included in the [mysqld] area of my.cnf or my.ini:</p>\n<p>skip-networking</p>\n<p>The document is situated in the <em>\"C:\\Program Files\\MySQL\\MySQL Server 5.1\"</em> catalog on the Windows operating system or <em>\"/etc/my.cnf\"</em> or <em>\"/etc/mysql/my.cnf\"</em> on Linux.<br>\nThis line cripples the start of systems administration in the middle of MySQL startup. It would be ideal if you bear in mind that a local connection can be used set up a connection to the MySQL server.</p>\n<p>Another possible solution is to force MySQL to listen only to the localhost by adding the following line in the <em>[mysqld]</em> section of <em>my.cnf</em>bind-address=127.0.0.1<br>\nYou may not be willing to incapacitate system access to your database server if clients in your organization interface with the server from their machines or the web server introduced on an alternate machine. In that case, the following restrictive grant syntax should be considered:</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"\" data-index=\"0\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">mysql&gt; GRANT SELECT, INSERT ON mydb.\\* TO &#39;someuser&#39;@&#39;somehost&#39;;  </span></code></pre>\n<p><strong>3. Disable the use of LOCAL INFILE</strong></p>\n<p>The next change is to disable the use of the <em>\"LOAD DATA LOCAL INFILE\"</em> command, which will help to keep unapproved perusing from neighborhood records. This is particularly vital when new SQL Injection vulnerabilities in PHP applications are found.<br>\nIn addition, in certain cases, the <em>\"LOCAL INFILE\"</em> command can be used to gain access to other files on the operating system, for instance <em>\"/etc/passwd\"</em>, using the following command:  </p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"\" data-index=\"1\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">mysql&gt; LOAD DATA LOCAL INFILE &#39;/etc/passwd&#39; INTO TABLE table1</span></code></pre>\n<p>Or even significantly less difficult:</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"\" data-index=\"2\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">mysql&gt; SELECT load\\_file(&quot;/etc/passwd&quot;)</span></code></pre>\n<p>To disable the usage of the <em>\"LOCAL INFILE\"</em> command, the following parameter should be added in the <em>[mysqld]</em> section of the MySQL configuration file.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"\" data-index=\"3\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">set-variable=local-infile=0</span></code></pre>\n<p><strong>4. Change root username and password, keep them strong.</strong></p>\n<p>The default administrator username on the MySQL server is <strong>\"root\"</strong>. Hackers often attempt to gain access to its permissions. To make this task harder, rename <strong>\"root\"</strong> to something else and provide it with a long, complex alphanumeric password.</p>\n<p>To rename the administrator’s username, use the rename command in the MySQL console:</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"\" data-index=\"4\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">mysql&gt; RENAME USER root TO new\\_user;</span></code></pre>\n<p>The MySQL <em>\"RENAME USER\"</em> command first appeared in MySQL version 5.0.2. If you use an older version of MySQL, you can use other commands to rename a user:</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"\" data-index=\"5\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">mysql&gt; use mysql;</span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\">mysql&gt; update user set user=&quot;new\\_user&quot; where user=&quot;root&quot;;</span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\">mysql&gt; flush privileges;</span></code></pre>\n<p>To change a user’s password, use the following command-line command:</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"\" data-index=\"6\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">mysql&gt; SET PASSWORD FOR &#39;username&#39;@&#39;%hostname&#39; = PASSWORD(&#39;newpass&#39;);</span></code></pre>\n<p>It is also possible to change the password using the <em>\"mysqladmin\"</em> utility:</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"\" data-index=\"7\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">shell&gt; mysqladmin -u username -p password newpass</span></code></pre>\n<p><strong>5. Remove the \"Test\" database</strong></p>\n<p>MySQL comes with a \"test\" database intended as a test space. It can be accessed by the anonymous user, and is therefore used by numerous attacks.<br>\nTo remove this database, use the drop command as follows:  </p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"\" data-index=\"8\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">mysql&gt; drop database test;  </span></code></pre>\n<p>Or use the <em>\"mysqladmin\"</em> command:  </p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"\" data-index=\"9\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">shell&gt; mysqladmin -u username -p drop test  </span></code></pre>\n<p><strong>6. Remove Anonymous and outdated accounts</strong></p>\n<p>The MySQL database comes with some anonymous users with blank passwords. As a result, anyone can connect to the database to check whether this is the case, do the following:  </p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"\" data-index=\"10\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">mysql&gt; select \\* from mysql.user where user=&quot;&quot;;  </span></code></pre>\n<p>In a secure system, no lines should be echoed back. Another way to do the same:</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"\" data-index=\"11\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">mysql&gt; SHOW GRANTS FOR &#39;&#39;@&#39;localhost&#39;;</span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\">mysql&gt; SHOW GRANTS FOR &#39;&#39;@&#39;myhost&#39;;</span></code></pre>\n<p>If the grants exist, then anybody can access the database and at least use the default database<em>\"test\"</em>. Check this with:</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"\" data-index=\"12\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">shell&gt; mysql -u blablabla</span></code></pre>\n<p>To remove the account, execute the following command:</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"\" data-index=\"13\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">mysql&gt; DROP USER &quot;&quot;;</span></code></pre>\n<p>The MySQL <em>\"DROP USER\"</em> command is supported starting with MySQL version 5.0. If you use an older version of MySQL, you can remove the account as follows:</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"\" data-index=\"14\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">mysql&gt; use mysql;</span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\">mysql&gt; DELETE FROM user WHERE user=&quot;&quot;;</span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\">mysql&gt; flush privileges;  </span></code></pre>\n<p><strong>7. Increase security with Role Based Access Control</strong></p>\n<p>A very common database security recommendation is to lower the permissions given to various parties. MySQL is no different. Typically, when developers work, they use the system's maximum permission and give less consideration to permission principles than we might expect. This practice can expose the database to significant risk.<br>\n* Any new MySQL 5.x installation already installed using the correct security measures.<br>\nTo protect your database, make sure that the file directory in which the MySQL database is actually stored is owned by the user \"mysql\" and the group \"mysql\".</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"\" data-index=\"15\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">shell&gt;ls -l /var/lib/mysql</span></code></pre>\n<p>In addition, ensure that only the user \"mysql\" and \"root\" have access to the directory <code>/var/lib/mysql</code>.<br>\nThe mysql binaries, which reside under the /usr/bin/ directory, should be owned by \"root\" or the specific system \"mysql\" user. Other users should not have write access to these files.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"\" data-index=\"16\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">shell&gt;ls -l /usr/bin/my\\*  </span></code></pre>\n<p><strong>8. Keep a check on database privileges</strong></p>\n<p>Operating system permissions were fixed in the preceding section. Now let’s talk about database permissions. In most cases, there is an administrator user (the renamed \"root\") and one or more actual users who coexist in the database. Usually, the \"root\" has nothing to do with the data in the database; instead, it is used to maintain the server and its tables, to give and revoke permissions, etc.<br>\nOn the other hand, some user ids are used to access the data, such as the user id assigned to the web server to execute \"select\\update\\insert\\delete\" queries and to execute stored procedures. In most cases, no other users are necessary; however, only you, as a system administrator can really know your application’s needs.</p>\n<p>Only administrator accounts needs to be granted the SUPER / PROCESS /FILE privileges and access to the mysql database. Usually, it is a good idea to lower the administrator’s permissions for accessing the data.</p>\n<p>Review the privileges of the rest of the users and ensure that these are set appropriately. This can be done using the following steps.  </p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"\" data-index=\"17\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">mysql&gt; use mysql;  </span></code></pre>\n<p>[Identify users]  </p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"\" data-index=\"18\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">mysql&gt; select \\* from users;  </span></code></pre>\n<p>[List grants of all users]  </p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"\" data-index=\"19\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">mysql&gt; show grants for ‘root’@’localhost’;</span></code></pre>\n<p>The above statement has to be executed for each user ! Note that only users who really need root privileges should be granted them.</p>\n<p>Another interesting privilege is \"SHOW DATABASES\". By default, the command can be used by everyone having access to the MySQL prompt. They can use it to gather information (e.g., getting database names) before attacking the database by, for instance, stealing the data. To prevent this, it is recommended that you follow the procedures described below.</p>\n<ul>\n<li>Add \" --skip-show-database\" to the startup script of MySQL or add it to the MySQL configuration file</li>\n<li>Grant the SHOW DATABASES privilege only to the users you want to use this command</li>\n</ul>\n<p>To disable the usage of the \"SHOW DATABASES\" command, the following parameter should be added in the [mysqld] section of the <code>/etc/my.cnf</code>:</p>\n<p>[mysqld]</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"\" data-index=\"20\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">skip-show-database  </span></code></pre>\n<p><strong>9. Enable Logging</strong></p>\n<p>If your database server does not execute many queries, it is recommended that you enable transaction logging, by adding the following line to [mysqld] section of the <code>/etc/my.cnf</code> file:</p>\n<p>[mysqld]</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"\" data-index=\"21\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">log =/var/log/mylogfile  </span></code></pre>\n<p>This is not recommended for heavy production MySQL servers because it causes high overhead on the server.<br>\nIn addition, verify that only the \"root\" and \"mysql\" ids have access to these logfiles (at least write access).</p>\n<p><strong>Error log</strong>Ensure only \"root\" and \"mysql\" have access to the log file \"hostname.err\". The file is stored in the mysql data directory. This file contains very sensitive information such as passwords, addresses, table names, stored procedure names and code parts. It can be used for information gathering, and in some cases, can provide the attacker with the information needed to exploit the database, the machine on which the database is installed, or the data inside it.</p>\n<p><strong>MySQL log</strong>Ensure only \"root\" and \"mysql\" have access to the logfile \"logfile XY\". The file is stored in the mysql data directory.</p>\n<p><strong>10. Change the root directory</strong> </p>\n<p>A chroot on UNIX {operating system} operating systems is an operation that changes the apparent disk root directory for the present running method and its children. A program that's re-rooted to a different directory cannot access or name files outside that directory, and therefore the directory is named a \"chroot jail\" or (less commonly) a \"chroot prison\".</p>\n<p>By using the chroot environment, the write access of the mySQL processes (and child processes) can be limited, increasing the security of the server.</p>\n<p>Ensure that a dedicated directory exists for the chrooted environment. This should be something like: <code>/chroot/mysql</code> In addition, to make the use of the database administrative tools convenient, the following parameter should be changed in the [client] section of MySQL configuration file:</p>\n<p>[client]</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"\" data-index=\"22\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">socket = /chroot/mysql/tmp/mysql.sock</span></code></pre>\n<p>Thanks to that line of code, there will be no need to supply the mysql, mysqladmin, mysqldump etc. commands with the <code>--socket=/chroot/mysql/tmp/mysql.sock</code> parameter every time these tools are run.</p>\n<p><strong>11. Delete old logs regularly</strong></p>\n<p>During the installation procedures, there's plenty of sensitive data which will assist unwelcome users to assault a database. This data is kept within the server’s history and might be terribly useful if one thing goes wrong during the installation. By analyzing the history files, administrators can figure out what has gone wrong and probably fix things up. However, these files are not needed after installation is complete.<br>\nWe should remove the content of the MySQL history file (~/.mysql_history), wherever all dead SQL commands are kept (especially passwords, that are kept as plain text):</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"\" data-index=\"23\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">cat /dev/null &gt; ~/.mysql\\_history</span></code></pre>\n<p>In conclusion,we should emphasize on database security. However it should be the first thing for any individual or a company.</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</style>","frontmatter":{"date":"February 23, 2016","updated_date":null,"description":null,"title":"Is Your Database Secured? Think Again","tags":["Database","Security"],"pinned":null,"coverImage":{"childImageSharp":{"fluid":{"aspectRatio":1,"src":"/static/ceccb1d10402251d7706ea8d19050b15/403a4/database_secure-300x300.webp","srcSet":"/static/ceccb1d10402251d7706ea8d19050b15/61e93/database_secure-300x300.webp 200w,\n/static/ceccb1d10402251d7706ea8d19050b15/403a4/database_secure-300x300.webp 300w","sizes":"(max-width: 300px) 100vw, 300px"}}},"author":{"id":"Kunal","github":"SuperKunal","avatar":null}}}},{"node":{"excerpt":"Manipulating collections like arrays and objects can be a hassle with vanilla JS. Thankfully there are libraries like Underscore which offer…","fields":{"slug":"/engineering/be-more-manipulative-with-underscore-js/"},"html":"<p>Manipulating collections like arrays and objects can be a hassle with vanilla JS. Thankfully there are libraries like Underscore which offer some extremely useful low level utility functions.</p>\n<p>Underscore JS provides much of the array/collection/object manipulating functionality similar to what you may have seen in other languages such as Ruby. As for calling the methods if you're familiar with JQuery, Underscore is identical except instead of \"$\" we use the library's namesake \"_\" to access the methods.</p>\n<p>Underscore has over 100 functions that can be used on collections, arrays, objects and functions (you read that right, function functions). I'm going to be discussing a few of the functions that work on collections, but definitely check out what else <a href=\"http://underscorejs.org/\">Underscore has to offer</a>.</p>\n<p>Once you know how to re-create the same output with Underscore syntax, you'll never want to go back to plain old JS and using nested for loops. One of the most helpful tools Underscore provides for accomplishing this is...</p>\n<h2 id=\"_each\" style=\"position:relative;\"><a href=\"#_each\" aria-label=\"_each 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>_.each</h2>\n<p>The _each method does exactly what it sounds like. It works on collections (arrays or objects), and will iterate over each element in the collection invoking the function you specified with 3 arguments (value, index, list) with index being replaced by key if used on an object. It's also worth noting _.each returns the list if you want chain some more manipulation after calling _.each.</p>\n<p>Here's a quick example showing how it can be used and what's available to you when you call it.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"javascript\" data-index=\"0\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk4\">var</span><span class=\"mtk1\"> </span><span class=\"mtk12\">someArray</span><span class=\"mtk1\"> = [</span><span class=\"mtk8\">&quot;a&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk8\">&quot;b&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk8\">&quot;c&quot;</span><span class=\"mtk1\">];</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\"> </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk12\">_</span><span class=\"mtk1\">.</span><span class=\"mtk11\">each</span><span class=\"mtk1\">(</span><span class=\"mtk12\">someArray</span><span class=\"mtk1\">, </span><span class=\"mtk4\">function</span><span class=\"mtk1\"> (</span><span class=\"mtk12\">element</span><span class=\"mtk1\">, </span><span class=\"mtk12\">index</span><span class=\"mtk1\">, </span><span class=\"mtk12\">list</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;value: &quot;</span><span class=\"mtk1\"> + </span><span class=\"mtk12\">element</span><span class=\"mtk1\"> + </span><span class=\"mtk8\">&quot; index: &quot;</span><span class=\"mtk1\"> + </span><span class=\"mtk12\">index</span><span class=\"mtk1\"> + </span><span class=\"mtk8\">&quot; list: &quot;</span><span class=\"mtk1\"> + </span><span class=\"mtk12\">list</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=\"mtk3\">// outputs</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">value: </span><span class=\"mtk12\">a</span><span class=\"mtk1\"> index: </span><span class=\"mtk7\">0</span><span class=\"mtk1\"> list: </span><span class=\"mtk12\">a</span><span class=\"mtk1\">,</span><span class=\"mtk12\">b</span><span class=\"mtk1\">,</span><span class=\"mtk12\">c</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">value: </span><span class=\"mtk12\">b</span><span class=\"mtk1\"> index: </span><span class=\"mtk7\">1</span><span class=\"mtk1\"> list: </span><span class=\"mtk12\">a</span><span class=\"mtk1\">,</span><span class=\"mtk12\">b</span><span class=\"mtk1\">,</span><span class=\"mtk12\">c</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">value: </span><span class=\"mtk12\">c</span><span class=\"mtk1\"> index: </span><span class=\"mtk7\">2</span><span class=\"mtk1\"> list: </span><span class=\"mtk12\">a</span><span class=\"mtk1\">,</span><span class=\"mtk12\">b</span><span class=\"mtk1\">,</span><span class=\"mtk12\">c</span></span></code></pre>\n<p>With that out of the way, let's think about what this means in terms of cleaning up our code. To do the above normally we would write a little for loop like this.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"javascript\" data-index=\"1\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk15\">for</span><span class=\"mtk1\"> ( </span><span class=\"mtk4\">var</span><span class=\"mtk1\"> </span><span class=\"mtk12\">i</span><span class=\"mtk1\"> = </span><span class=\"mtk7\">0</span><span class=\"mtk1\">; </span><span class=\"mtk12\">i</span><span class=\"mtk1\"> &</span><span class=\"mtk12\">lt</span><span class=\"mtk1\">; </span><span class=\"mtk12\">someArray</span><span class=\"mtk1\">.</span><span class=\"mtk12\">length</span><span class=\"mtk1\">; </span><span class=\"mtk12\">i</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;value: &quot;</span><span class=\"mtk1\"> + </span><span class=\"mtk12\">someArray</span><span class=\"mtk1\">[</span><span class=\"mtk12\">i</span><span class=\"mtk1\">] + </span><span class=\"mtk8\">&quot; index: &quot;</span><span class=\"mtk1\"> + </span><span class=\"mtk12\">i</span><span class=\"mtk1\"> + </span><span class=\"mtk8\">&quot; list: &quot;</span><span class=\"mtk1\"> + </span><span class=\"mtk12\">someArray</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">}</span></span></code></pre>\n<p>Admittedly these two aren't all that different, but let's imagine we have a function defined elsewhere that will deal with handling the arguments passed in on each iteration. We can replace that same functionality with a significantly less verbose solution.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"javascript\" data-index=\"2\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk12\">_</span><span class=\"mtk1\">.</span><span class=\"mtk11\">each</span><span class=\"mtk1\">(</span><span class=\"mtk12\">someArray</span><span class=\"mtk1\">, </span><span class=\"mtk12\">doStuff</span><span class=\"mtk1\">);</span></span></code></pre>\n<p>To quote Antoine de Saint Exupéry: \"It seems that perfection is attained not when there is nothing more to add, but when there is nothing more to remove.\" While it may not be perfection, there are certainly arguments to be made about performance, I think you would be hard pressed to find anything further simplify this code.</p>\n<h2 id=\"_map\" style=\"position:relative;\"><a href=\"#_map\" aria-label=\"_map 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>_.map</h2>\n<p>While _.each will return the original list you input, _.map will allow you to manipulate or otherwise transform the input as you please and then returns the new array. Map needs a minimum of 2 arguments, first the collection and then the function to be executed on each iteratee and also accepts a third argument which dictates the context for the iterating function.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"javascript\" data-index=\"3\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk4\">var</span><span class=\"mtk1\"> </span><span class=\"mtk12\">numbersObject</span><span class=\"mtk1\"> = {</span><span class=\"mtk7\">1</span><span class=\"mtk12\">:</span><span class=\"mtk7\">1</span><span class=\"mtk1\">, </span><span class=\"mtk7\">2</span><span class=\"mtk12\">:</span><span class=\"mtk7\">4</span><span class=\"mtk1\">, </span><span class=\"mtk7\">3</span><span class=\"mtk12\">:</span><span class=\"mtk7\">9</span><span class=\"mtk1\">};</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\"> </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">var</span><span class=\"mtk1\"> </span><span class=\"mtk12\">productArray</span><span class=\"mtk1\"> = </span><span class=\"mtk12\">_</span><span class=\"mtk1\">.</span><span class=\"mtk11\">map</span><span class=\"mtk1\">(</span><span class=\"mtk12\">numbersObject</span><span class=\"mtk1\">, </span><span class=\"mtk4\">function</span><span class=\"mtk1\">(</span><span class=\"mtk12\">value</span><span class=\"mtk1\">, </span><span class=\"mtk12\">key</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\">value</span><span class=\"mtk1\"> * </span><span class=\"mtk12\">key</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=\"mtk3\">//proudctArray is now</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">[</span><span class=\"mtk7\">1</span><span class=\"mtk1\">, </span><span class=\"mtk7\">8</span><span class=\"mtk1\">, </span><span class=\"mtk7\">27</span><span class=\"mtk1\">]</span></span></code></pre>\n<p>Before you go writing some functions to pass as an argument to _.map be sure to take a peek at the other methods available in Underscore. Map is a little bit like having the Lego blocks to build whatever you want, but if you already have a pre-packaged Batcave available, it might not be the best use of your time building it from scratch.</p>\n<h2 id=\"_pluck\" style=\"position:relative;\"><a href=\"#_pluck\" aria-label=\"_pluck 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>_.pluck</h2>\n<p>To illustrate my childhood toy analogy let's talk about _.pluck. Pluck is basically just a refined version of _.map made for a specific use case. That's not to say there aren't ways of combining the two to achieve something a little more complex, but if standard _.pluck behaviour is all you're after then don't go re-inventing the wheel.</p>\n<p>Often with data objects we're interested in the values of a specific key, for example let's say we have an array of movies.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"javascript\" data-index=\"4\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk4\">var</span><span class=\"mtk1\"> </span><span class=\"mtk12\">movies</span><span class=\"mtk1\"> = [</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    {</span><span class=\"mtk12\">title:</span><span class=\"mtk1\"> </span><span class=\"mtk8\">&quot;Dracula&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk12\">genre:</span><span class=\"mtk1\"> </span><span class=\"mtk8\">&quot;Horror&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk12\">star:</span><span class=\"mtk1\"> </span><span class=\"mtk8\">&quot;Nosferatu&quot;</span><span class=\"mtk1\">},</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    {</span><span class=\"mtk12\">title:</span><span class=\"mtk1\"> </span><span class=\"mtk8\">&quot;Cast Away&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk12\">genre:</span><span class=\"mtk1\"> </span><span class=\"mtk8\">&quot;Drama&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk12\">star:</span><span class=\"mtk1\"> </span><span class=\"mtk8\">&quot;Wilson&quot;</span><span class=\"mtk1\">},</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    {</span><span class=\"mtk12\">title:</span><span class=\"mtk1\"> </span><span class=\"mtk8\">&quot;Airplane&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk12\">genre:</span><span class=\"mtk1\"> </span><span class=\"mtk8\">&quot;Comedy&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk12\">star:</span><span class=\"mtk1\"> </span><span class=\"mtk8\">&quot;Leslie Nielsen&quot;</span><span class=\"mtk1\">}</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">];</span></span></code></pre>\n<p>Now we want to just have an array of the titles of these movies.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"javascript\" data-index=\"5\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk4\">var</span><span class=\"mtk1\"> </span><span class=\"mtk12\">titlesArray</span><span class=\"mtk1\"> = </span><span class=\"mtk12\">_</span><span class=\"mtk1\">.</span><span class=\"mtk11\">pluck</span><span class=\"mtk1\">(</span><span class=\"mtk12\">movies</span><span class=\"mtk1\">, </span><span class=\"mtk8\">&#39;title&#39;</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\"> </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk3\">//titlesArray is now</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">[</span><span class=\"mtk8\">&quot;Dracula&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk8\">&quot;Cast Away&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk8\">&quot;Airplane&quot;</span><span class=\"mtk1\">]</span></span></code></pre>\n<p>Not much else to say about it, it works on collections and is extremely handy for a very common task.</p>\n<h2 id=\"_filter\" style=\"position:relative;\"><a href=\"#_filter\" aria-label=\"_filter 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>_.filter</h2>\n<p>Another example of a more refined _.map function that comes in handy often enough. Aptly named this method will return an array of only the things that make it through your test.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"javascript\" data-index=\"6\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk4\">var</span><span class=\"mtk1\"> </span><span class=\"mtk12\">numbers</span><span class=\"mtk1\"> = [</span><span class=\"mtk7\">1</span><span class=\"mtk1\">,</span><span class=\"mtk7\">33</span><span class=\"mtk1\">,</span><span class=\"mtk7\">6</span><span class=\"mtk1\">,</span><span class=\"mtk7\">24</span><span class=\"mtk1\">,</span><span class=\"mtk7\">8</span><span class=\"mtk1\">,</span><span class=\"mtk7\">21</span><span class=\"mtk1\">,</span><span class=\"mtk7\">11</span><span class=\"mtk1\">,</span><span class=\"mtk7\">22</span><span class=\"mtk1\">];</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\"> </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">var</span><span class=\"mtk1\"> </span><span class=\"mtk12\">lessThanTen</span><span class=\"mtk1\"> = </span><span class=\"mtk12\">_</span><span class=\"mtk1\">.</span><span class=\"mtk11\">filter</span><span class=\"mtk1\">(</span><span class=\"mtk12\">numbers</span><span class=\"mtk1\">, </span><span class=\"mtk4\">function</span><span class=\"mtk1\">(</span><span class=\"mtk12\">number</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\">number</span><span class=\"mtk1\"> &</span><span class=\"mtk12\">lt</span><span class=\"mtk1\">; </span><span class=\"mtk7\">10</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=\"mtk3\">//lessThanTen is now</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">[</span><span class=\"mtk7\">1</span><span class=\"mtk1\">, </span><span class=\"mtk7\">6</span><span class=\"mtk1\">, </span><span class=\"mtk7\">8</span><span class=\"mtk1\">]</span></span></code></pre>\n<p>Works on collections and kitchen sink faucets.</p>\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>Just kidding there's no _.conclusion method.</p>\n<p>I hope by now that you get the idea that if what you need to do isn't already a method, Underscore's _.map is a powerful tool for accomplishing whatever obscure collection manipulation your heart desires.</p>\n<p>So get out there, take a look through Underscore JS and start writing less obfuscated (nested) for loops with the help of _.each.</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 .mtk4 { color: #569CD6; }\n  .dark-default-dark .mtk1 { color: #D4D4D4; }\n  .dark-default-dark .mtk12 { color: #9CDCFE; }\n  .dark-default-dark .mtk8 { color: #CE9178; }\n  .dark-default-dark .mtk11 { color: #DCDCAA; }\n  .dark-default-dark .mtk10 { color: #4EC9B0; }\n  .dark-default-dark .mtk3 { color: #6A9955; }\n  .dark-default-dark .mtk7 { color: #B5CEA8; }\n  .dark-default-dark .mtk15 { color: #C586C0; }\n</style>","frontmatter":{"date":"February 16, 2016","updated_date":null,"description":null,"title":"Be More Manipulative with Underscore JS","tags":["JavaScript","UnderscoreJs"],"pinned":null,"coverImage":{"childImageSharp":{"fluid":{"aspectRatio":1.7699115044247788,"src":"/static/a0908f5af6a6436a7da16f3b91888bed/58556/underscore.webp","srcSet":"/static/a0908f5af6a6436a7da16f3b91888bed/61e93/underscore.webp 200w,\n/static/a0908f5af6a6436a7da16f3b91888bed/1f5c5/underscore.webp 400w,\n/static/a0908f5af6a6436a7da16f3b91888bed/58556/underscore.webp 800w,\n/static/a0908f5af6a6436a7da16f3b91888bed/99238/underscore.webp 1200w,\n/static/a0908f5af6a6436a7da16f3b91888bed/135cd/underscore.webp 1280w","sizes":"(max-width: 800px) 100vw, 800px"}}},"author":{"id":"Zakary Hughes","github":null,"avatar":null}}}},{"node":{"excerpt":"LinkedIn has recently revamped their API systems and added many new restrictions. We will go through some examples on how you can utilize…","fields":{"slug":"/engineering/extended-linkedin-api-usage/"},"html":"<p>LinkedIn has recently revamped their API systems and added many new restrictions. We will go through some examples on how you can utilize the LinkedIn Javascript API in order to setup some useful features that comply with LinkedIn's new terms and conditions and use cases.</p>\n<h2 id=\"getting-your-site-ready\" style=\"position:relative;\"><a href=\"#getting-your-site-ready\" aria-label=\"getting your site ready 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>Getting Your Site Ready</h2>\n<p>The first step will be setting up your login button which will prompt the user to authenticate with their LinkedIn credentials. We have provided a guide to getting a basic login button setup <a href=\"/integrate-linkedin-social-login-website/\">here</a>. The linked guide will get you as far as setting up a button that allows your users to login with LinkedIn and display a personalized welcome message. Below we will go over extending this functionality to allow you to handle more complex features for your users after logging in.</p>\n<h2 id=\"event-handling\" style=\"position:relative;\"><a href=\"#event-handling\" aria-label=\"event handling 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>Event Handling</h2>\n<p>You can control and initiate specific behavior after a user logs in. You can assign these event handlers by first setting the function that will be used to initialize the events. This will trigger the event designation after the LinkedIn scripts have been loaded on your page. Update the LinkedIn initialization script:</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"js\" data-index=\"0\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">&lt;!--</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">api_key: </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">authorize: </span><span class=\"mtk4\">true</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">onLoad: </span><span class=\"mtk12\">onLinkedInLoad</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">--&gt;</span></span></code></pre>\n<p>This will trigger the onLinkedInLoad function after the Linkedin scripts have been loaded.</p>\n<p>You can now assign some LinkedIn Event handlers in this function to control the behavior that will occur for different LinkedIn user actions. Let's begin by assigning the behavior that occurs after a user logs in.</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=\"mtk1\">&lt;!--</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">function</span><span class=\"mtk1\"> </span><span class=\"mtk11\">onLinkedInLoad</span><span class=\"mtk1\">() {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk12\">IN</span><span class=\"mtk1\">.</span><span class=\"mtk12\">Event</span><span class=\"mtk1\">.</span><span class=\"mtk11\">on</span><span class=\"mtk1\">(</span><span class=\"mtk12\">IN</span><span class=\"mtk1\">, </span><span class=\"mtk8\">&quot;auth&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk12\">getProfileData</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">}</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">--&gt;</span></span></code></pre>\n<p>The above event will trigger when a user authorizes and will call the getProfileData function. We can add another event assignment for the user logging out.</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=\"mtk1\">&lt;!--</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">function</span><span class=\"mtk1\"> </span><span class=\"mtk11\">onLinkedInLoad</span><span class=\"mtk1\">() {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk12\">IN</span><span class=\"mtk1\">.</span><span class=\"mtk12\">Event</span><span class=\"mtk1\">.</span><span class=\"mtk11\">on</span><span class=\"mtk1\">(</span><span class=\"mtk12\">IN</span><span class=\"mtk1\">, </span><span class=\"mtk8\">&quot;auth&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk12\">getProfileData</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk12\">IN</span><span class=\"mtk1\">.</span><span class=\"mtk12\">Event</span><span class=\"mtk1\">.</span><span class=\"mtk11\">on</span><span class=\"mtk1\">(</span><span class=\"mtk12\">IN</span><span class=\"mtk1\">, </span><span class=\"mtk8\">&quot;logout&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk12\">sendGoodByeMessage</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">}</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">--&gt;</span></span></code></pre>\n<p>The above logout event will trigger the sendGoodByeMessage when the user logs out. Now that we have the basic event handling in place we can handle the specific behavior for users logging in.</p>\n<h2 id=\"data-retrieval-and-api-access\" style=\"position:relative;\"><a href=\"#data-retrieval-and-api-access\" aria-label=\"data retrieval and api access 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>Data Retrieval and API access</h2>\n<p>Once a user has logged in and triggered the getProfileData event we can pull in their user profile using the LinkedIn Raw data API handlers, these allow you to access any of LinkedIn's API endpoints and get data back. We will begin with a quick check to make sure the user is still authorized and then call the Raw API to pull in the people endpoint for the current user:</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=\"mtk1\">&lt;!--</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">function</span><span class=\"mtk1\"> </span><span class=\"mtk11\">getProfileData</span><span class=\"mtk1\">() {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk15\">if</span><span class=\"mtk1\">(</span><span class=\"mtk12\">IN</span><span class=\"mtk1\">.</span><span class=\"mtk12\">User</span><span class=\"mtk1\">.</span><span class=\"mtk11\">isAuthorized</span><span class=\"mtk1\">())</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk12\">IN</span><span class=\"mtk1\">.</span><span class=\"mtk12\">API</span><span class=\"mtk1\">.</span><span class=\"mtk11\">Raw</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;/people/~&quot;</span><span class=\"mtk1\">).</span><span class=\"mtk11\">result</span><span class=\"mtk1\">(</span><span class=\"mtk12\">onSuccess</span><span class=\"mtk1\">).</span><span class=\"mtk11\">error</span><span class=\"mtk1\">(</span><span class=\"mtk12\">onError</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">}</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">--&gt;</span></span></code></pre>\n<p>If the data is successfully returned it will call the onSuccess function and if not it will call onError.</p>\n<p>These functions will both include a JSON formatted response that can be used to display their profile data or log a message:</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\">&lt;!--</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">function</span><span class=\"mtk1\"> </span><span class=\"mtk11\">onSuccess</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=\"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>\n<span class=\"grvsc-line\"><span class=\"mtk4\">function</span><span class=\"mtk1\"> </span><span class=\"mtk11\">onError</span><span class=\"mtk1\">(</span><span class=\"mtk12\">error</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\">error</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">}</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">--&gt;</span></span></code></pre>\n<p>You can test the response formats for most of the LinkedIn APIs on <a href=\"https://apigee.com/console/linkedin\">LinkedIns API console</a> You can access any of the API endpoints after successful login via the raw API handler and retrieve data per your requirements.</p>\n<h2 id=\"user-management\" style=\"position:relative;\"><a href=\"#user-management\" aria-label=\"user management 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>User Management</h2>\n<p>Before making any API requests you should verify that your user has a current active session. User sessions are valid for 30 minutes by default. These sessions can be extended using the following call:</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=\"mtk1\">&lt;!--</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk12\">IN</span><span class=\"mtk1\">.</span><span class=\"mtk12\">User</span><span class=\"mtk1\">.</span><span class=\"mtk11\">refresh</span><span class=\"mtk1\">()</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">--&gt;</span></span></code></pre>\n<p>The above call can be used to refresh the expiration time for the user but repeated calls may cause your app to be blocked so this should be used sparingly.</p>\n<p>You can provide the ability for your users to logout by setting up a button or link that will trigger the following function call:</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=\"mtk1\">&lt;!--</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk12\">IN</span><span class=\"mtk1\">.</span><span class=\"mtk12\">User</span><span class=\"mtk1\">.</span><span class=\"mtk11\">logout</span><span class=\"mtk1\">(</span><span class=\"mtk12\">sendGoodByeMessage</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">--&gt;</span></span></code></pre>\n<p>This will trigger the same function that was assigned to the logout event.</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 .mtk4 { color: #569CD6; }\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 .mtk15 { color: #C586C0; }\n  .dark-default-dark .mtk10 { color: #4EC9B0; }\n</style>","frontmatter":{"date":"February 09, 2016","updated_date":null,"description":null,"title":"Extended LinkedIn API Usage","tags":["LinkedIn","SocialLogin"],"pinned":null,"coverImage":{"childImageSharp":{"fluid":{"aspectRatio":1,"src":"/static/dacf65e1b50df78fc0c763813d3cb64f/403a4/linkedin-feat-img.webp","srcSet":"/static/dacf65e1b50df78fc0c763813d3cb64f/61e93/linkedin-feat-img.webp 200w,\n/static/dacf65e1b50df78fc0c763813d3cb64f/403a4/linkedin-feat-img.webp 300w","sizes":"(max-width: 300px) 100vw, 300px"}}},"author":{"id":"Karl Wittig","github":null,"avatar":null}}}},{"node":{"excerpt":"If you're not familiar with Angular I'd highly recommend heading over to the Angular JS resource site and checking out what all the fuss is…","fields":{"slug":"/engineering/angular-roster-tutorial/"},"html":"<p>If you're not familiar with Angular I'd highly recommend heading over to the <a href=\"https://angularjs.org/\">Angular JS</a> resource site and checking out what all the fuss is about. Once you've got a basic understanding of Angular and how to get it up and running this tutorial will show you some of the basic, but awesome features supported by Angular.</p>\n<p>Today I'm going to be building out a roster for my fantasy football team. If that's not your cup of tea then by all means feel free to substitute the content for whatever floats your boat.</p>\n<h2 id=\"players-array\" style=\"position:relative;\"><a href=\"#players-array\" aria-label=\"players array 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>Players Array</h2>\n<p>There might not be an I in team, but there are certainly players, so before we do anything in the HTML we'll have to make all the necessary components in the controller. First up let's make an array of all the players we want to include (initially at least) on our team.</p>\n<p>Every player is a special little snowflake, and our player objects should reflect that! With this in mind we will make each player an object with his or her own properties like: name, position and team. Here's an example of what our array might look like.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"js\" data-index=\"0\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk12\">$scope</span><span class=\"mtk1\">.</span><span class=\"mtk12\">players</span><span class=\"mtk1\"> = [</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    {</span><span class=\"mtk12\">name:</span><span class=\"mtk1\"> </span><span class=\"mtk8\">&quot;Tom Brady&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk12\">position:</span><span class=\"mtk1\"> </span><span class=\"mtk8\">&quot;QB&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk12\">team:</span><span class=\"mtk1\"> </span><span class=\"mtk8\">&quot;Patriots&quot;</span><span class=\"mtk1\">},</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    {</span><span class=\"mtk12\">name:</span><span class=\"mtk1\"> </span><span class=\"mtk8\">&quot;Tony Romo&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk12\">position:</span><span class=\"mtk1\"> </span><span class=\"mtk8\">&quot;QB&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk12\">team:</span><span class=\"mtk1\"> </span><span class=\"mtk8\">&quot;Cowboys&quot;</span><span class=\"mtk1\">},</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    {</span><span class=\"mtk12\">name:</span><span class=\"mtk1\"> </span><span class=\"mtk8\">&quot;Peyton Manning&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk12\">position:</span><span class=\"mtk1\"> </span><span class=\"mtk8\">&quot;QB&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk12\">team:</span><span class=\"mtk1\"> </span><span class=\"mtk8\">&quot;Broncos&quot;</span><span class=\"mtk1\">},</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    {</span><span class=\"mtk12\">name:</span><span class=\"mtk1\"> </span><span class=\"mtk8\">&quot;Rob Gronkowsi&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk12\">position:</span><span class=\"mtk1\"> </span><span class=\"mtk8\">&quot;TE&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk12\">team:</span><span class=\"mtk1\"> </span><span class=\"mtk8\">&quot;Patriots&quot;</span><span class=\"mtk1\">},</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    {</span><span class=\"mtk12\">name:</span><span class=\"mtk1\"> </span><span class=\"mtk8\">&quot;JJ Watt&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk12\">position:</span><span class=\"mtk1\"> </span><span class=\"mtk8\">&quot;DE&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk12\">team:</span><span class=\"mtk1\"> </span><span class=\"mtk8\">&quot;Texans&quot;</span><span class=\"mtk1\">},</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    {</span><span class=\"mtk12\">name:</span><span class=\"mtk1\"> </span><span class=\"mtk8\">&quot;Lavonte David&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk12\">position:</span><span class=\"mtk1\"> </span><span class=\"mtk8\">&quot;LB&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk12\">team:</span><span class=\"mtk1\"> </span><span class=\"mtk8\">&quot;Buccaneers&quot;</span><span class=\"mtk1\">}</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">];</span></span></code></pre>\n<h2 id=\"repetitive-department-of-repetition\" style=\"position:relative;\"><a href=\"#repetitive-department-of-repetition\" aria-label=\"repetitive department of repetition 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>Repetitive department of repetition</h2>\n<p>Now that we have our roster we can go back to the HTML and make use of Angular's ng-repeat directive. We put the ng-repeat on the element we want to be repeated, keeping in mind that all of its children will also get repeated.</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=\"mtk1\">&lt;!--</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    {{</span><span class=\"mtk12\">player</span><span class=\"mtk1\">.</span><span class=\"mtk12\">name</span><span class=\"mtk1\">}} - {{</span><span class=\"mtk12\">player</span><span class=\"mtk1\">.</span><span class=\"mtk12\">position</span><span class=\"mtk1\">}}</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">--&gt;</span></span></code></pre>\n<p>Okay so if you're new to Angular there's a couple of things going on here. First like I said we've got the ng-repeat placed on the li (the thing we want repeated) which will create a new li for each player in the players array we defined earlier in the controller. Next up the data binding is being implemented here with each player name as well as position being used as the values for the list item.</p>\n<p>While we're on the topic of data binding, let's throw this in just for fun. Pretty simple, it will calculate the length of your roster and keep it updated as any changes are made.</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=\"mtk1\">&lt;!--</span><span class=\"mtk12\">You</span><span class=\"mtk1\"> </span><span class=\"mtk12\">have</span><span class=\"mtk1\"> {{</span><span class=\"mtk12\">players</span><span class=\"mtk1\">.</span><span class=\"mtk12\">length</span><span class=\"mtk1\">}} </span><span class=\"mtk12\">on</span><span class=\"mtk1\"> </span><span class=\"mtk12\">your</span><span class=\"mtk1\"> </span><span class=\"mtk12\">roster</span><span class=\"mtk1\">.--&gt;</span></span></code></pre>\n<h2 id=\"easiest-search-functionality-of-your-life\" style=\"position:relative;\"><a href=\"#easiest-search-functionality-of-your-life\" aria-label=\"easiest search functionality of your life 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>Easiest Search Functionality of Your Life</h2>\n<p>Next let's add some search functionality to our list. Sounds like a lot of work, probably have to iterate over the array elements, match them to the argument being passed in and... just kidding. With Angular it's a breeze.</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=\"mtk1\">&lt;!--</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">...</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">{{</span><span class=\"mtk12\">player</span><span class=\"mtk1\">.</span><span class=\"mtk12\">name</span><span class=\"mtk1\">}} - {{</span><span class=\"mtk12\">player</span><span class=\"mtk1\">.</span><span class=\"mtk12\">position</span><span class=\"mtk1\">}}</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">--&gt;</span></span></code></pre>\n<p>Donezo.</p>\n<h2 id=\"the-shape-of-italy\" style=\"position:relative;\"><a href=\"#the-shape-of-italy\" aria-label=\"the shape of italy 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 shape of Italy</h2>\n<p>Let's imagine one of our fantasy players isn't performing too well (ahem Peyton...) and we want to give him the boot (get it now?).</p>\n<p>We'll add a little delete button beside each of our players' names, and since we're doing it for each of them guess how we're going to implement it? That's right with ng-repeat we already have on the list items!</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\">&lt;!--{{</span><span class=\"mtk12\">player</span><span class=\"mtk1\">.</span><span class=\"mtk12\">name</span><span class=\"mtk1\">}} - {{</span><span class=\"mtk12\">player</span><span class=\"mtk1\">.</span><span class=\"mtk12\">position</span><span class=\"mtk1\">}}</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    ×</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">--&gt;</span></span></code></pre>\n<p>I'll also tack on a little button with an \"x\" as the content (as a side note, when you want to do this use × instead of \"x\" it looks much nicer). Then we'll attach an ng-click with a delete function where we pass in $index.</p>\n<p>$index is a neat little feature available with certain Angular directives, and ng-repeat is one of them. It will be assigned the index value (starting at 0) of the position it holds within the array being used with the ng-repeat.</p>\n<p>That's all we need in the HTML, so now back in the controller we create a $scope function by the same name used in the HTML and give it a parameter of index. The body of the function is a single line which makes use of the array.splice method where we pass in the index of the item we want to delete, and then 1 to denote that it's only 1 item we want removed.</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=\"mtk12\">$scope</span><span class=\"mtk1\">.</span><span class=\"mtk11\">delete</span><span class=\"mtk1\"> = </span><span class=\"mtk4\">function</span><span class=\"mtk1\"> (</span><span class=\"mtk12\">index</span><span class=\"mtk1\">) {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk12\">$scope</span><span class=\"mtk1\">.</span><span class=\"mtk12\">players</span><span class=\"mtk1\">.</span><span class=\"mtk11\">splice</span><span class=\"mtk1\">(</span><span class=\"mtk12\">index</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></code></pre>\n<h2 id=\"acquisitions\" style=\"position:relative;\"><a href=\"#acquisitions\" aria-label=\"acquisitions 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>Acquisitions</h2>\n<p>Now since we just cut someone from the team, we've gotta find their replacement. Let's chuck a few text inputs in there, give them all a respective ng-model to bind with their value and finally another button with an ng-click but this time calling an addPlayer function.</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=\"mtk1\">&lt;!--</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    Name:</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    Position:</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    Team:</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk12\">Add</span><span class=\"mtk1\"> </span><span class=\"mtk12\">Player</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">--&gt;</span></span></code></pre>\n<p>This one's a lil' different from delete, but still super simple. Working from the inside out, we will create a new player object which gets the name, position and team properties from the ng-models on the HTML and then push that object to the players array. After that we clear those values just for some good housekeeping practice.</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\">$scope</span><span class=\"mtk1\">.</span><span class=\"mtk11\">add</span><span class=\"mtk1\"> = </span><span class=\"mtk4\">function</span><span class=\"mtk1\"> () {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk12\">$scope</span><span class=\"mtk1\">.</span><span class=\"mtk12\">players</span><span class=\"mtk1\">.</span><span class=\"mtk11\">push</span><span class=\"mtk1\">({</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk12\">name:</span><span class=\"mtk1\"> </span><span class=\"mtk12\">$scope</span><span class=\"mtk1\">.</span><span class=\"mtk12\">new_name</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk12\">position:</span><span class=\"mtk1\"> </span><span class=\"mtk12\">$scope</span><span class=\"mtk1\">.</span><span class=\"mtk12\">new_position</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk12\">team:</span><span class=\"mtk1\"> </span><span class=\"mtk12\">$scope</span><span class=\"mtk1\">.</span><span class=\"mtk12\">new_team</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    });</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk12\">$scope</span><span class=\"mtk1\">.</span><span class=\"mtk12\">new_name</span><span class=\"mtk1\"> = </span><span class=\"mtk8\">&quot;&quot;</span><span class=\"mtk1\">;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk12\">$scope</span><span class=\"mtk1\">.</span><span class=\"mtk12\">new_position</span><span class=\"mtk1\"> = </span><span class=\"mtk8\">&quot;&quot;</span><span class=\"mtk1\">;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk12\">$scope</span><span class=\"mtk1\">.</span><span class=\"mtk12\">new_team</span><span class=\"mtk1\"> = </span><span class=\"mtk8\">&quot;&quot;</span><span class=\"mtk1\">;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">};</span></span></code></pre>\n<h2 id=\"nothing-lasts-forever\" style=\"position:relative;\"><a href=\"#nothing-lasts-forever\" aria-label=\"nothing lasts forever 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>Nothing Lasts Forever</h2>\n<p>Now since this was all done purely on the front end, and didn't make use of cookies, localstorage, or sessionstorage none of this will persist (aka be saved). For that kind of support you'd need some sort of back end, which is beyond the scope of this article.</p>\n<p>This was a very rudimentary example of what's possible with Angular JS, so if this interested you at all please dig a little deeper and play around with Angular some more!</p>\n<p>That brings us to the end of this tutorial. Feel free to check out the finished (yet unstyled) product <a href=\"https://codepen.io/anon/pen/pgoJwq\">here on Codepen</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 .mtk12 { color: #9CDCFE; }\n  .dark-default-dark .mtk1 { color: #D4D4D4; }\n  .dark-default-dark .mtk8 { color: #CE9178; }\n  .dark-default-dark .mtk11 { color: #DCDCAA; }\n  .dark-default-dark .mtk4 { color: #569CD6; }\n  .dark-default-dark .mtk7 { color: #B5CEA8; }\n</style>","frontmatter":{"date":"January 12, 2016","updated_date":null,"description":null,"title":"Angular Roster Tutorial","tags":["Engineering","AngularJS","PlayersArray","Array","Search"],"pinned":null,"coverImage":{"childImageSharp":{"fluid":{"aspectRatio":1,"src":"/static/3fd5bbf61c136944264b54c576652f32/58556/roster-angularjs-1.webp","srcSet":"/static/3fd5bbf61c136944264b54c576652f32/61e93/roster-angularjs-1.webp 200w,\n/static/3fd5bbf61c136944264b54c576652f32/1f5c5/roster-angularjs-1.webp 400w,\n/static/3fd5bbf61c136944264b54c576652f32/58556/roster-angularjs-1.webp 800w,\n/static/3fd5bbf61c136944264b54c576652f32/1fb14/roster-angularjs-1.webp 960w","sizes":"(max-width: 800px) 100vw, 800px"}}},"author":{"id":"Zakary Hughes","github":null,"avatar":null}}}},{"node":{"excerpt":"As a front-end developer, if you haven't heard about Promise in Javascript, well ... At least you have heard about it now! And it is truly…","fields":{"slug":"/engineering/how-to-promise/"},"html":"<p>As a front-end developer, if you haven't heard about Promise in Javascript, well ...<br>\nAt least you have heard about it now! And it is truly amazing.</p>\n<p>Promise is a the standard way of handling asynchronous operations, such as calling APIs. It is comprehensive but elegant, espeically with a series of Async operations and handling the errors from them.<br>\nIt has been widely supported by mordern browsers. But of course IE is not one of the modern ones, so do not forget to find a promise-polyfill for your IE users.</p>\n<p><a href=\"http://caniuse.com/#feat=promises\">Can I use Promise</a><br>\n<a href=\"https://github.com/taylorhakes/promise-polyfill\">Polyfill for IE</a></p>\n<p>In this blog I will cover the basic usages for Promise, let's get started.<br>\nA promise function would look like this</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"javascript\" data-index=\"0\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk4\">new</span><span class=\"mtk1\"> </span><span class=\"mtk10\">Promise</span><span class=\"mtk1\">(</span><span class=\"mtk4\">function</span><span class=\"mtk1\"> (</span><span class=\"mtk12\">resolve</span><span class=\"mtk1\">, </span><span class=\"mtk12\">reject</span><span class=\"mtk1\">) {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk4\">var</span><span class=\"mtk1\"> </span><span class=\"mtk12\">data</span><span class=\"mtk1\"> = </span><span class=\"mtk11\">asyncCall</span><span class=\"mtk1\">(); </span><span class=\"mtk3\">// could be API calls</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk15\">if</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\">resolve</span><span class=\"mtk1\">(</span><span class=\"mtk12\">data</span><span class=\"mtk1\">); </span><span class=\"mtk3\">// success</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=\"mtk11\">reject</span><span class=\"mtk1\">(</span><span class=\"mtk12\">data</span><span class=\"mtk1\">); </span><span class=\"mtk3\">// fail</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>First we need to declare it is a `new` Promise, inside you can put your async calls and let promise know how to deal with the response with `resolve` and `reject`. You can treat `resolve` and `reject` as two callback functions, `resolve` when you are confirmed that you have got what you expect, and reject if anything bad happened.</p>\n<p>Here is a brief example, <a href=\"https://jsfiddle.net/02fj0cnv/\">Fiddle it here</a></p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"javascript\" data-index=\"1\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk4\">var</span><span class=\"mtk1\"> </span><span class=\"mtk11\">aync1</span><span class=\"mtk1\"> = </span><span class=\"mtk4\">function</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\">new</span><span class=\"mtk1\"> </span><span class=\"mtk10\">Promise</span><span class=\"mtk1\">(</span><span class=\"mtk4\">function</span><span class=\"mtk1\">(</span><span class=\"mtk12\">resolve</span><span class=\"mtk1\">, </span><span class=\"mtk12\">reject</span><span class=\"mtk1\">){</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk3\">// Wait 1s and alert</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk11\">setTimeout</span><span class=\"mtk1\">(</span><span class=\"mtk4\">function</span><span class=\"mtk1\">(){</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk11\">resolve</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;Hello Promise&quot;</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        }, </span><span class=\"mtk7\">1000</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=\"mtk11\">aync1</span><span class=\"mtk1\">().</span><span class=\"mtk11\">then</span><span class=\"mtk1\">(</span><span class=\"mtk4\">function</span><span class=\"mtk1\"> (</span><span class=\"mtk12\">resp</span><span class=\"mtk1\">) {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk11\">alert</span><span class=\"mtk1\">(</span><span class=\"mtk12\">resp</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">});</span></span></code></pre>\n<p>If something is going wrong, you want to catch and handle it, <a href=\"https://jsfiddle.net/j26ka27w/\">Fiddle it here.</a></p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"javascript\" data-index=\"2\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk4\">var</span><span class=\"mtk1\"> </span><span class=\"mtk11\">aync2</span><span class=\"mtk1\"> = </span><span class=\"mtk4\">function</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\">new</span><span class=\"mtk1\"> </span><span class=\"mtk10\">Promise</span><span class=\"mtk1\">(</span><span class=\"mtk4\">function</span><span class=\"mtk1\">(</span><span class=\"mtk12\">resolve</span><span class=\"mtk1\">, </span><span class=\"mtk12\">reject</span><span class=\"mtk1\">){</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk3\">// Wait 2s and alert</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk11\">setTimeout</span><span class=\"mtk1\">(</span><span class=\"mtk4\">function</span><span class=\"mtk1\">(){</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk3\">// pretend we got something wrong.</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk11\">reject</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;error&quot;</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        }, </span><span class=\"mtk7\">1000</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=\"mtk11\">aync2</span><span class=\"mtk1\">().</span><span class=\"mtk11\">then</span><span class=\"mtk1\">(</span><span class=\"mtk4\">function</span><span class=\"mtk1\"> (</span><span class=\"mtk12\">resp</span><span class=\"mtk1\">) {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk11\">alert</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;This will not be called&quot;</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=\"mtk4\">function</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 class=\"mtk11\">alert</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>Here I have quickly demonstrated the basic usage of Promise, you may think \"Oh callbacks can do the same thing as well\". You are not wrong, but in next blog I will show the real power of Promise, thanks for reading.</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 .mtk4 { color: #569CD6; }\n  .dark-default-dark .mtk1 { color: #D4D4D4; }\n  .dark-default-dark .mtk10 { color: #4EC9B0; }\n  .dark-default-dark .mtk12 { color: #9CDCFE; }\n  .dark-default-dark .mtk11 { color: #DCDCAA; }\n  .dark-default-dark .mtk3 { color: #6A9955; }\n  .dark-default-dark .mtk15 { color: #C586C0; }\n  .dark-default-dark .mtk8 { color: #CE9178; }\n  .dark-default-dark .mtk7 { color: #B5CEA8; }\n</style>","frontmatter":{"date":"January 05, 2016","updated_date":null,"description":null,"title":"How to Promise","tags":["JavaScript","Promise"],"pinned":null,"coverImage":{"childImageSharp":{"fluid":{"aspectRatio":1,"src":"/static/0391ea10a372dcec2e9e04aa7ed59ec0/403a4/promise-300x300.webp","srcSet":"/static/0391ea10a372dcec2e9e04aa7ed59ec0/61e93/promise-300x300.webp 200w,\n/static/0391ea10a372dcec2e9e04aa7ed59ec0/403a4/promise-300x300.webp 300w","sizes":"(max-width: 300px) 100vw, 300px"}}},"author":{"id":"Solomon Yu","github":null,"avatar":null}}}},{"node":{"excerpt":"When you work for a tech company in an office capacity, it feels like everyone around you is speaking another language. Which they are, most…","fields":{"slug":"/engineering/learning-how-to-code/"},"html":"<p>When you work for a tech company in an office capacity, it feels like everyone around you is speaking another language. Which they are, most of their work exists in coding language. To feel more relevant, I signed up on <a href=\"https://www.codecademy.com/\">codecademy.com</a> and started working on their beginner courses (for free! you should try it!).</p>\n<p>Here are some things I have learned about coding:</p>\n<ol>\n<li>There are many different ways to code. Not every website or app is made using the same terms or patterns, programmers and developers have options for how they want to format their content, and how they want to communicate with their computer.</li>\n<li>Coding is more about seeing what you want in your head than about math. Deciding exactly what you want and communicating it is the big struggle. Having your website/app be capable of computing things is optional, but the layout is mandatory. (Not to mention the most noticeable aspect of your site).</li>\n<li>Code is like a language. The words and punctuation must be learned for each coding language. Though they can be linked to English words (like “p” for a new paragraph), you have to be able to pull them up quick in your mind. As with any language, repetition is key to recognition.</li>\n<li>You don’t have to start from scratch (but you can). There are frameworks available, like Bootstrap, which have some existing templates you can draw from. This helps you when you are constructing your site, so that you can set up your layout quicker, and have more time to work on your content.</li>\n<li>\n<p>There are some areas of knowledge that you don’t need to memorize, but having an understanding of what they do will be helpful in coding:</p>\n<ol>\n<li>The hexi-decimal system (and how it relates to color)</li>\n<li>Binary code</li>\n<li>ASCII</li>\n</ol>\n</li>\n<li>Once you learn some of the basics, websites you see every day will start to seem simpler. You will be able to pick out some of their elements, and if you look at their bare code, you will recognize how they come together.</li>\n<li>The world of coders is large and easy to access. If you have questions, there is someone online who is willing and eager to answer. This is not a skill that anyone was born with, and due to new languages etc, everyone is still learning. </li>\n</ol>\n<p>I hope that this list has contributed to your knowledge, and would encourage you to check online for available resources to expand (or begin) your abilities in coding.</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":"December 29, 2015","updated_date":null,"description":null,"title":"Learning How to Code","tags":["Learning","Coding","Learning resources"],"pinned":null,"coverImage":{"childImageSharp":{"fluid":{"aspectRatio":1,"src":"/static/dcadc401834dd794ad2d788dd16ff014/403a4/begin-code-300x300.webp","srcSet":"/static/dcadc401834dd794ad2d788dd16ff014/61e93/begin-code-300x300.webp 200w,\n/static/dcadc401834dd794ad2d788dd16ff014/403a4/begin-code-300x300.webp 300w","sizes":"(max-width: 300px) 100vw, 300px"}}},"author":{"id":"Carling","github":null,"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":258,"currentPage":44,"type":"//engineering//","numPages":53,"pinned":"5c425581-f474-5ae9-abe7-cf5342db2aaa"}},"staticQueryHashes":["1171199041","1384082988","2100481360","23180105","528864852"]}