{"componentChunkName":"component---src-templates-blog-list-template-js","path":"/engineering/41","result":{"data":{"allMarkdownRemark":{"edges":[{"node":{"excerpt":"A JSON Web Token (JWT) is a JSON object that is defined in RFC 7519 as a safe way of transmitting information between two parties…","fields":{"slug":"/engineering/jwt/"},"html":"<p><em>A JSON Web Token (JWT) is a JSON object that is defined in</em> <a href=\"https://tools.ietf.org/html/rfc7519\"><em>RFC 7519</em></a> <em>as a safe way</em> of <em>transmitting information between two parties. Information in the JWT is digitally-signed, so that it can be verified and trusted.</em></p>\n<p><strong>JWT Properties</strong></p>\n<ul>\n<li>Less verbose -  JWT is compact in size and can be passed in the URL, POST parameter, or HTTP header.</li>\n<li>Self-contained - JWT carries all of information needed for exchanging information and authentication.</li>\n<li>Versatile - JWT works in .NET, Python, Node.js, Java, PHP, Ruby, Go, JavaScript, and Haskell.</li>\n</ul>\n<p><strong>JWT Use Cases</strong></p>\n<ul>\n<li>Information Exchange - JWT can be used between two parties to exchange information. JWT is digitally-signed and can be used in a secure public/private key pair. Information is verified using the public key on the other end.</li>\n<li>Authentication - JWT can contain user information in the payload and can be used in the session to authenticate the user. Once authenticated, users can access protected resources in an application using the JWT included in the request. So, every request will be authenticated by verifying the JWT.</li>\n</ul>\n<p>JWT contains three parts: Header, Payload, and Signature which are separated by a dot.</p>\n<p><code>Header.Payload.Signature</code></p>\n<p><strong>Header</strong></p>\n<p>The JWT Header consists of 2 parts:</p>\n<ul>\n<li>The token type (typ): JWT </li>\n<li>Algorithm used to sign the token (alg)</li>\n</ul>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"json\" data-index=\"0\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">{  </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\"> </span><span class=\"mtk12\">&quot;typ&quot;</span><span class=\"mtk1\"> : </span><span class=\"mtk8\">&quot;JWT&quot;</span><span class=\"mtk1\">,  </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\"> </span><span class=\"mtk12\">&quot;alg&quot;</span><span class=\"mtk1\"> : </span><span class=\"mtk8\">&quot;HS256&quot;</span><span class=\"mtk1\">  </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">}</span></span></code></pre>\n<p>Header Algorithm Types:</p>\n<ul>\n<li>Symmetric Algorithms - This algorithm type uses a single secret key to both sign and verify the JWT token. For example: HMAC algorithms.</li>\n<li>Asymmetric Algorithms - This algorithm type uses a private key to sign the token and a public key to verify the signature. For example: RSA and ECDSA algorithms.</li>\n</ul>\n<p><strong>alg Value</strong></p>\n<p><strong>Digital Signature or MAC Algorithm</strong></p>\n<table>\n<thead>\n<tr>\n<th>Algo</th>\n<th align=\"center\">Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>HS256</td>\n<td align=\"center\">HMAC using SHA-256 hash algorithm</td>\n</tr>\n<tr>\n<td>HS384</td>\n<td align=\"center\">HMAC using SHA-384 hash algorithm</td>\n</tr>\n<tr>\n<td>HS512</td>\n<td align=\"center\">HMAC using SHA-512 hash algorithm</td>\n</tr>\n<tr>\n<td>RS256</td>\n<td align=\"center\">RSASSA using SHA-256 hash algorithm</td>\n</tr>\n<tr>\n<td>RS384</td>\n<td align=\"center\">RSASSA using SHA-384 hash algorithm</td>\n</tr>\n<tr>\n<td>RS512</td>\n<td align=\"center\">RSASSA using SHA-512 hash algorithm</td>\n</tr>\n<tr>\n<td>ES256</td>\n<td align=\"center\">ECDSA using P-256 curve and SHA-256 hash algorithm</td>\n</tr>\n<tr>\n<td>ES384</td>\n<td align=\"center\">ECDSA using P-384 curve and SHA-384 hash algorithm</td>\n</tr>\n<tr>\n<td>ES512</td>\n<td align=\"center\">ECDSA using P-521 curve and SHA-512 hash algorithm</td>\n</tr>\n</tbody>\n</table>\n<p>The Base64Url-encoded Header<strong>,</strong> which is first part of our JWT, looks like the following:</p>\n<p><code>eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9</code></p>\n<p><strong>Payload</strong></p>\n<p>The Payload, also known as the JWT claim, contains all of the information we want to transmit.</p>\n<p>Different types of claims can be used to build the Payload:</p>\n<ul>\n<li><strong>Registered Claim</strong> -  These claims are optional but recommended as they contain some metadata about the token:</li>\n</ul>\n<table>\n<thead>\n<tr>\n<th>Code</th>\n<th>Name</th>\n<th align=\"center\">Description</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>iss</td>\n<td>issuer</td>\n<td align=\"center\">Identifies the principal that issued the JWT.</td>\n</tr>\n<tr>\n<td>sub</td>\n<td>subject</td>\n<td align=\"center\">Identifies the principal that is the subject of the JWT.</td>\n</tr>\n<tr>\n<td>aud</td>\n<td>audience</td>\n<td align=\"center\">Identifies the recipients that the JWT is intended for.</td>\n</tr>\n<tr>\n<td>exp</td>\n<td>Expiration time</td>\n<td align=\"center\">Identifies the expiration time on or after which the JWT MUST NOT be accepted for processing.</td>\n</tr>\n<tr>\n<td>nbf</td>\n<td>Not before</td>\n<td align=\"center\">Identifies the time before which the JWT MUST NOT be accepted for processing.</td>\n</tr>\n<tr>\n<td>iat</td>\n<td>Issue at</td>\n<td align=\"center\">Identifies the time at which the JWT was issued.</td>\n</tr>\n<tr>\n<td>jti</td>\n<td>JWT id</td>\n<td align=\"center\">Unique identifier for the JWT, can be used to prevent the JWT from being replayed.</td>\n</tr>\n</tbody>\n</table>\n<ul>\n<li><strong>Public Claim</strong> - These claims are defined by you, such as user name, and other important information.</li>\n<li><strong>Private Claim</strong> - A producer and consumer may agree to use claim names that are private. These are subject to collision, so use them with caution.</li>\n</ul>\n<p>Example Payload:</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"json\" data-index=\"1\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">{  </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\"> </span><span class=\"mtk12\">&quot;sub&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;1234567890&quot;</span><span class=\"mtk1\">,  </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\"> </span><span class=\"mtk12\">&quot;name&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;Frank Emic&quot;</span><span class=\"mtk1\">,  </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\"> </span><span class=\"mtk12\">&quot;jti&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;4b5fcea6-2a5e-4a9d-97f2-3d8631ea2c5a&quot;</span><span class=\"mtk1\">,  </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\"> </span><span class=\"mtk12\">&quot;iat&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk7\">1521191902</span><span class=\"mtk1\">,  </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\"> </span><span class=\"mtk12\">&quot;exp&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk7\">1521195630</span><span class=\"mtk1\">  </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">}</span></span></code></pre>\n<p>This example contains a combination of registered and public claims. “sub”,”jti”,”iat”, and “exp” are registered claims and “name” is a public claim.</p>\n<p>The Base64Url-encoded Payload, which is the second part of our JWT, looks like the following:</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"json\" data-index=\"2\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">eyJzdWIiOiIxMjM</span><span class=\"mtk7\">0</span><span class=\"mtk1\">NTY</span><span class=\"mtk7\">3</span><span class=\"mtk1\">ODkwIiwibmFtZSI</span><span class=\"mtk7\">6</span><span class=\"mtk1\">IkZyYW</span><span class=\"mtk7\">5</span><span class=\"mtk1\">rIEVtaWMiL  </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">CJqdGkiOiI</span><span class=\"mtk7\">0</span><span class=\"mtk1\">YjVmY</span><span class=\"mtk7\">2</span><span class=\"mtk1\">VhNi</span><span class=\"mtk7\">0</span><span class=\"mtk1\">yYTVlLTRhOWQtOTdmMi</span><span class=\"mtk7\">0</span><span class=\"mtk1\">zZDg</span><span class=\"mtk7\">2</span><span class=\"mtk1\">MzFlYTJjNWEiLCJpYXQiOjE</span><span class=\"mtk7\">1</span><span class=\"mtk1\">MjExOTE</span><span class=\"mtk7\">5</span><span class=\"mtk1\">MDIsImV</span><span class=\"mtk7\">4</span><span class=\"mtk1\">cCI</span><span class=\"mtk7\">6</span><span class=\"mtk1\">MTUyMTE</span><span class=\"mtk7\">5</span><span class=\"mtk1\">NTYzMH</span><span class=\"mtk7\">0</span></span></code></pre>\n<p><strong>Signature</strong></p>\n<p>The final part of our JWT is the Signature. To create the Signature, we need 3 components:</p>\n<ul>\n<li>Header</li>\n<li>Payload</li>\n<li>Algorithm used to sign the Header and Payload</li>\n</ul>\n<p>var encodedString = base64UrlEncode(header) + \".\" + base64UrlEncode(payload);<br>\nHMACSHA256(encodedString, 'secret');</p>\n<p>The secret is the Signature held by the server in order to verify tokens and sign new ones.</p>\n<p>The above Base64Url-encoded Header and Payload are combined with a dot, and then digitally-signed using the secret. This generates the Signature as the third part of the our JWT:</p>\n<p>wGDoDSxfKj3Ns379NVxocwM9TOiwxhxWl</p>\n<p><strong>Putting It All Together</strong></p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"json\" data-index=\"3\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">eyJhbGciOiJIUzI</span><span class=\"mtk7\">1</span><span class=\"mtk1\">NiIsInR</span><span class=\"mtk7\">5</span><span class=\"mtk1\">cCI</span><span class=\"mtk7\">6</span><span class=\"mtk1\">IkpXVCJ</span><span class=\"mtk7\">9</span><span class=\"mtk1\">.eyJzdWIiOiIxMjM</span><span class=\"mtk7\">0</span><span class=\"mtk1\">NTY</span><span class=\"mtk7\">3</span><span class=\"mtk1\">ODkwIiwibmFtZSI</span><span class=\"mtk7\">6</span><span class=\"mtk1\">IkZyYW</span><span class=\"mtk7\">5</span><span class=\"mtk1\">rIEVtaWMiL  </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">CJqdGkiOiI</span><span class=\"mtk7\">0</span><span class=\"mtk1\">YjVmY</span><span class=\"mtk7\">2</span><span class=\"mtk1\">VhNi</span><span class=\"mtk7\">0</span><span class=\"mtk1\">yYTVlLTRhOWQtOTdmMi</span><span class=\"mtk7\">0</span><span class=\"mtk1\">zZDg</span><span class=\"mtk7\">2</span><span class=\"mtk1\">MzFlYTJjNWEiLCJpYXQiOjE</span><span class=\"mtk7\">1</span><span class=\"mtk1\">MjExOTE</span><span class=\"mtk7\">5</span><span class=\"mtk1\">MDIsImV</span><span class=\"mtk7\">4</span><span class=\"mtk1\">cCI</span><span class=\"mtk7\">6</span><span class=\"mtk1\">MTUyMTE</span><span class=\"mtk7\">5</span><span class=\"mtk1\">NTYzMH</span><span class=\"mtk7\">0</span><span class=\"mtk1\">.wGDoDSxfKj</span><span class=\"mtk7\">3</span><span class=\"mtk1\">Ns</span><span class=\"mtk7\">379</span><span class=\"mtk1\">NVxocwM</span><span class=\"mtk7\">9</span><span class=\"mtk1\">TOiwxhxWl</span></span></code></pre>\n<p>This is our final JWT, containing the Header, Payload, and Signature joined together with dots. It can be passed as a URL parameter, a POST parameter, or in the  HTTP header to authenticate or exchange information.</p>\n<p>Note: JWT does not hide information; it just encodes information using the digitally-signed signature and verifies that the information has not been altered over the network. So, do not add any sensitive information in the JWT claim.</p>\n<p><strong>Conclusion</strong></p>\n<p>JWT comprises three encoded parts: Header, Payload, and Signature. It can be passed as a URL or POST parameter, or in an HTTP header. Due to JWT's lightweight, self-containing, and versatile strucutre, it remains a popular tool for information exchange and authentication.</p>\n<style class=\"grvsc-styles\">\n  .grvsc-container {\n    overflow: auto;\n    -webkit-overflow-scrolling: touch;\n    padding-top: 1rem;\n    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));\n    padding-bottom: 1rem;\n    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));\n    border-radius: 8px;\n    border-radius: var(--grvsc-border-radius, 8px);\n    font-feature-settings: normal;\n  }\n  \n  .grvsc-code {\n    display: inline-block;\n    min-width: 100%;\n  }\n  \n  .grvsc-line {\n    display: inline-block;\n    box-sizing: border-box;\n    width: 100%;\n    padding-left: 1.5rem;\n    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));\n    padding-right: 1.5rem;\n    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));\n  }\n  \n  .grvsc-line-highlighted {\n    background-color: var(--grvsc-line-highlighted-background-color, transparent);\n    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, transparent);\n  }\n  \n  .dark-default-dark {\n    background-color: #1E1E1E;\n    color: #D4D4D4;\n  }\n  .dark-default-dark .mtk1 { color: #D4D4D4; }\n  .dark-default-dark .mtk12 { color: #9CDCFE; }\n  .dark-default-dark .mtk8 { color: #CE9178; }\n  .dark-default-dark .mtk7 { color: #B5CEA8; }\n</style>","frontmatter":{"date":"July 11, 2018","updated_date":null,"description":null,"title":"What is JSON Web Token","tags":["JWT","JSON Web Token"],"pinned":null,"coverImage":{"childImageSharp":{"fluid":{"aspectRatio":1.7699115044247788,"src":"/static/fca016963236696b6d07a52d211c1354/58556/jwt.webp","srcSet":"/static/fca016963236696b6d07a52d211c1354/61e93/jwt.webp 200w,\n/static/fca016963236696b6d07a52d211c1354/1f5c5/jwt.webp 400w,\n/static/fca016963236696b6d07a52d211c1354/58556/jwt.webp 800w,\n/static/fca016963236696b6d07a52d211c1354/99238/jwt.webp 1200w,\n/static/fca016963236696b6d07a52d211c1354/135cd/jwt.webp 1280w","sizes":"(max-width: 800px) 100vw, 800px"}}},"author":{"id":"Mayank Agarwal","github":"mayankagrwal","avatar":null}}}},{"node":{"excerpt":"Nowadays, many API providers support JSONP requests. One reason for this is that most web browsers disable cross-domain requests when using…","fields":{"slug":"/engineering/understanding-jsonp/"},"html":"<p>Nowadays, many API providers support JSONP requests. One reason for this is that most web browsers disable cross-domain requests when using basic Ajax.</p>\n<p>For example, if your website has the domain \"a.com\", it will use JavaScript hosted on a.com. When the a.com JavaScript makes an Ajax call to make a request on b.com, most web browsers would automatically deem the Ajax call as insecure and disable it. This is called the Same-Origin Policy and web browsers have this to prevent malicious scripts from sending off information to a different domain. Because you need the a.com JavaScript to access b.com to provide your service, this seems to pose a pretty big issue … JSONP to the rescue!</p>\n<p>Before understanding JSONP, we already know JSON is an object notation of JavaScript. The \"P\" stands for padding. So it’s a padded JSON, and, to be more specific, the JSON object is padded with a JavaScript function! It looks 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=\"mtk11\">jsFunction</span><span class=\"mtk1\">({</span><span class=\"mtk8\">&quot;name&quot;</span><span class=\"mtk12\"> :</span><span class=\"mtk1\"> </span><span class=\"mtk8\">&quot;Ash Ketchum&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk8\">&quot;role&quot;</span><span class=\"mtk12\"> :</span><span class=\"mtk1\"> </span><span class=\"mtk8\">&quot;Pokemon trainer&quot;</span><span class=\"mtk1\">});</span></span></code></pre>\n<p>Thus, technically, any call that retrieves JSONP, sends off an executable JavaScript line, if and only if your page has a JavaScript function that has the same function name that’s returned in the JSONP!</p>\n<p>Let’s look at an example: say the user is on a.com and the browser is using JavaScript hosted on a.com. Then I shouldn't have any issues making Ajax calls to a.com. Ajax GET requests to b.com however, would fail. To avoid this, I first create a method in the JavaScript code that's located on a.com with the following signature</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\">function</span><span class=\"mtk1\"> </span><span class=\"mtk11\">getData</span><span class=\"mtk1\">(</span><span class=\"mtk12\">data</span><span class=\"mtk1\">){</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk3\">// use this data</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">}</span></span></code></pre>\n<p>With this, an Ajax call using JSONP will pass through fine and return this data:</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=\"mtk11\">getData</span><span class=\"mtk1\">({</span><span class=\"mtk8\">&quot;name&quot;</span><span class=\"mtk12\"> :</span><span class=\"mtk1\"> </span><span class=\"mtk8\">&quot;test&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk8\">&quot;value&quot;</span><span class=\"mtk12\"> :</span><span class=\"mtk1\"> </span><span class=\"mtk8\">&quot;test Value&quot;</span><span class=\"mtk1\">});</span></span></code></pre>\n<p>After processing the request, the web browser will call the \"getData\" function because whenever a JavaScript tag is loaded, it gets executed.</p>\n<p>Now, the JSON object will get passed as an argument to the getData function as the data parameter. So, you can think of the getData as a callback method of the request.</p>\n<p>You can see the below code clearly</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\">function</span><span class=\"mtk1\"> </span><span class=\"mtk11\">addJavascriptFile</span><span class=\"mtk1\"> = </span><span class=\"mtk11\">function</span><span class=\"mtk1\"> (</span><span class=\"mtk12\">url</span><span class=\"mtk1\">, </span><span class=\"mtk12\">context</span><span class=\"mtk1\">) {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk12\">context</span><span class=\"mtk1\"> = </span><span class=\"mtk12\">context</span><span class=\"mtk1\"> || </span><span class=\"mtk12\">document</span><span class=\"mtk1\">;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">var</span><span class=\"mtk1\"> </span><span class=\"mtk12\">head</span><span class=\"mtk1\"> = </span><span class=\"mtk12\">context</span><span class=\"mtk1\">.</span><span class=\"mtk11\">getElementsByTagName</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&#39;head&#39;</span><span class=\"mtk1\">)\\[</span><span class=\"mtk7\">0</span><span class=\"mtk1\">\\];</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">var</span><span class=\"mtk1\"> </span><span class=\"mtk12\">js</span><span class=\"mtk1\"> = </span><span class=\"mtk12\">context</span><span class=\"mtk1\">.</span><span class=\"mtk11\">createElement</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&#39;script&#39;</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk12\">js</span><span class=\"mtk1\">.</span><span class=\"mtk12\">src</span><span class=\"mtk1\"> = </span><span class=\"mtk12\">url</span><span class=\"mtk1\">;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk12\">js</span><span class=\"mtk1\">.</span><span class=\"mtk12\">type</span><span class=\"mtk1\"> = </span><span class=\"mtk8\">&quot;text/JavaScript&quot;</span><span class=\"mtk1\">;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk12\">head</span><span class=\"mtk1\">.</span><span class=\"mtk11\">appendChild</span><span class=\"mtk1\">(</span><span class=\"mtk12\">js</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk15\">return</span><span class=\"mtk1\"> </span><span class=\"mtk12\">js</span><span class=\"mtk1\">;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">}</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">function</span><span class=\"mtk1\"> </span><span class=\"mtk11\">getJsonp</span><span class=\"mtk1\"> = </span><span class=\"mtk11\">function</span><span class=\"mtk1\"> (</span><span class=\"mtk12\">url</span><span class=\"mtk1\">, </span><span class=\"mtk12\">handle</span><span class=\"mtk1\">) {</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk3\">//creating random name of function as to not conflict with others</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">var</span><span class=\"mtk1\"> </span><span class=\"mtk12\">func</span><span class=\"mtk1\"> = </span><span class=\"mtk8\">&#39;jsonpCallback&#39;</span><span class=\"mtk1\"> + </span><span class=\"mtk10\">Math</span><span class=\"mtk1\">.</span><span class=\"mtk11\">floor</span><span class=\"mtk1\">((</span><span class=\"mtk10\">Math</span><span class=\"mtk1\">.</span><span class=\"mtk11\">random</span><span class=\"mtk1\">() \\* </span><span class=\"mtk7\">1000000000000000000</span><span class=\"mtk1\">) + </span><span class=\"mtk7\">1</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk3\">//adding randomly created function to global window object</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk12\">window</span><span class=\"mtk1\">\\[</span><span class=\"mtk12\">func</span><span class=\"mtk1\">\\] = </span><span class=\"mtk4\">function</span><span class=\"mtk1\"> (</span><span class=\"mtk12\">data</span><span class=\"mtk1\">) {</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk3\">//calling handle</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk11\">handle</span><span class=\"mtk1\">(</span><span class=\"mtk12\">data</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk3\">//removing random named declared function</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk12\">window</span><span class=\"mtk1\">\\[</span><span class=\"mtk12\">func</span><span class=\"mtk1\">\\] = </span><span class=\"mtk4\">function</span><span class=\"mtk1\"> () {};</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk3\">//removing added js</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk12\">document</span><span class=\"mtk1\">.</span><span class=\"mtk12\">head</span><span class=\"mtk1\">.</span><span class=\"mtk11\">removeChild</span><span class=\"mtk1\">(</span><span class=\"mtk12\">js</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">}</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk3\">//manipulating and adding js file to head</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">var</span><span class=\"mtk1\"> </span><span class=\"mtk12\">endurl</span><span class=\"mtk1\"> = </span><span class=\"mtk12\">url</span><span class=\"mtk1\">.</span><span class=\"mtk11\">indexOf</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&#39;?&#39;</span><span class=\"mtk1\">) != -</span><span class=\"mtk7\">1</span><span class=\"mtk1\"> ? </span><span class=\"mtk12\">url</span><span class=\"mtk1\"> + </span><span class=\"mtk8\">&#39;&amp;amp;callback=&#39;</span><span class=\"mtk1\"> + </span><span class=\"mtk12\">func</span><span class=\"mtk1\"> : </span><span class=\"mtk12\">url</span><span class=\"mtk1\"> + </span><span class=\"mtk8\">&#39;?callback=&#39;</span><span class=\"mtk1\"> + </span><span class=\"mtk12\">func</span><span class=\"mtk1\">;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">var</span><span class=\"mtk1\"> </span><span class=\"mtk12\">js</span><span class=\"mtk1\"> = </span><span class=\"mtk11\">addJavascriptFile</span><span class=\"mtk1\">(</span><span class=\"mtk12\">endurl</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">}</span></span></code></pre>\n<p>The above code is not doing any magic, it will accept the URL of the API and add a parameter callback with a random name, and also create a global method with this same random name. It will then create a script tag and add the complete URL to src of this tag.</p>\n<p>The API will read the callback parameter from the query string and, if the callback parameter has the value \"jsonCallback\", the response will be as follows:</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=\"mtk11\">jsonpCallback</span><span class=\"mtk1\">({</span><span class=\"mtk8\">&quot;name&quot;</span><span class=\"mtk12\"> :</span><span class=\"mtk1\"> </span><span class=\"mtk8\">&quot;test&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk8\">&quot;value&quot;</span><span class=\"mtk12\"> :</span><span class=\"mtk1\"> </span><span class=\"mtk8\">&quot;test Value&quot;</span><span class=\"mtk1\">});</span></span></code></pre>\n<style class=\"grvsc-styles\">\n  .grvsc-container {\n    overflow: auto;\n    -webkit-overflow-scrolling: touch;\n    padding-top: 1rem;\n    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));\n    padding-bottom: 1rem;\n    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));\n    border-radius: 8px;\n    border-radius: var(--grvsc-border-radius, 8px);\n    font-feature-settings: normal;\n  }\n  \n  .grvsc-code {\n    display: inline-block;\n    min-width: 100%;\n  }\n  \n  .grvsc-line {\n    display: inline-block;\n    box-sizing: border-box;\n    width: 100%;\n    padding-left: 1.5rem;\n    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));\n    padding-right: 1.5rem;\n    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));\n  }\n  \n  .grvsc-line-highlighted {\n    background-color: var(--grvsc-line-highlighted-background-color, transparent);\n    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, transparent);\n  }\n  \n  .dark-default-dark {\n    background-color: #1E1E1E;\n    color: #D4D4D4;\n  }\n  .dark-default-dark .mtk11 { color: #DCDCAA; }\n  .dark-default-dark .mtk1 { color: #D4D4D4; }\n  .dark-default-dark .mtk8 { color: #CE9178; }\n  .dark-default-dark .mtk12 { color: #9CDCFE; }\n  .dark-default-dark .mtk4 { color: #569CD6; }\n  .dark-default-dark .mtk3 { color: #6A9955; }\n  .dark-default-dark .mtk7 { color: #B5CEA8; }\n  .dark-default-dark .mtk15 { color: #C586C0; }\n  .dark-default-dark .mtk10 { color: #4EC9B0; }\n</style>","frontmatter":{"date":"June 29, 2018","updated_date":null,"description":null,"title":"Understanding JSONP","tags":["JavaScript","JSONP","API"],"pinned":null,"coverImage":{"childImageSharp":{"fluid":{"aspectRatio":1.834862385321101,"src":"/static/85e9390b35cfcd06b4e455bd05cc8ea7/50fff/Screenshot-2018-06-29-12.21.27.webp","srcSet":"/static/85e9390b35cfcd06b4e455bd05cc8ea7/61e93/Screenshot-2018-06-29-12.21.27.webp 200w,\n/static/85e9390b35cfcd06b4e455bd05cc8ea7/1f5c5/Screenshot-2018-06-29-12.21.27.webp 400w,\n/static/85e9390b35cfcd06b4e455bd05cc8ea7/50fff/Screenshot-2018-06-29-12.21.27.webp 730w","sizes":"(max-width: 730px) 100vw, 730px"}}},"author":{"id":"Rakesh Soni","github":"oyesoni","avatar":"rakesh-soni.webp"}}}},{"node":{"excerpt":"NuGet is a free and open-source package manager for the .NET ecosystem. We can create and install packages using NuGet client tools. All of…","fields":{"slug":"/engineering/using-nuget-to-publish-net-packages/"},"html":"<p>NuGet is a free and open-source package manager for the .NET ecosystem. We can create and install packages using NuGet client tools. All of the .NET packages are hosted for publishing and consumption on a central package repository known as NuGet Gallery.</p>\n<p>Prerequisites</p>\n<ul>\n<li>Visual Studio 2017 (with .NET-related workload)</li>\n<li>nuget.exe (add it’s location to PATH environment variable)</li>\n<li>Valid account on nuget.org</li>\n</ul>\n<p><strong>Create a class library project</strong></p>\n<p>For a .NET package to be published in the NuGet Gallery, it should be a valid class library project. The following instructions can be used to create a simple class library project:</p>\n<ul>\n<li>Open Visual Studio, go to File > New > Project, expand the Visual C# > .NET Standard node. Select the \"Class Library (.NET Standard)\" template and provide a valid name.</li>\n<li>To build the project, right-click on the project file and select Build. A DLL file will be generated in the Debug folder or Release folder (if you build the configuration)</li>\n</ul>\n<p>For a real useful NuGet package, you should write necessary code which can be used by others to develop applications. However, a class library from the template is sufficient to create a package.</p>\n<p><strong>Configure Package Properties</strong></p>\n<ol>\n<li>Go to Project > Properties, select Package tab.</li>\n<li>Provide a unique identifier for your package and fill out other required properties. For a description of various properties, please visit <a href=\"https://docs.microsoft.com/en-us/nuget/reference/nuspec\">here</a>. The properties provided at this stage will be defined in .nuspec manifest that is created by Visual Studio for the project.</li>\n<li>To view the properties directly in the project file, right-click the project in Solution Explorer and select Edit AppLogger.csproj.</li>\n</ol>\n<p><strong>Run the pack command</strong></p>\n<ol>\n<li>Set the configuration to Release.</li>\n<li>Right click the project in Solution Explorer and select the Pack command.</li>\n<li>Visual Studio builds the project and creates the .nupkg file. Please note that the built package is in bin\\Release\\netstandard2.0 as befits the .NET Standard 2.0 target.</li>\n</ol>\n<p><strong>Acquire API Key</strong></p>\n<ol>\n<li><a href=\"https://www.nuget.org/users/account/LogOn?returnUrl=%2F\">Sign in to your nuget.org account</a> or create an account if it doesn’t already exist.</li>\n<li>Select your user name on the top right, then select API Keys.</li>\n<li>Select Create, provide a name for your key, select Select Scopes > Push.</li>\n<li>Under API Key, enter * for Glob pattern, then select Create.</li>\n<li>After the key is created, select Copy to retrieve the access key needed for publishing the package.</li>\n</ol>\n<p><strong>Important:</strong> Save your key in a secure location because you cannot copy the key again later on. If you return to the API key page, you need to regenerate the key to copy it.</p>\n<p><strong>Publish with nuget push</strong></p>\n<ol>\n<li>Open Command Prompt.</li>\n<li>Change to the folder containing the .nupkg file.</li>\n<li>\n<p>Run the following command, specifying your package name and replacing the key value with your API key:</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"powershell\" data-index=\"0\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">nuget push &amp;lt;PACKAGE-NAME&amp;gt;.nupkg &amp;lt;API-KEY&amp;gt; -Source https://api.nuget.org/v3/index.json</span></span></code></pre>\n</li>\n<li>nuget.exe displays the results of the publishing process.</li>\n</ol>\n<p><strong>Manage the published package</strong></p>\n<p>You can view your published package in your profile on nuget.org. Select Manage Packages to see the one that was just published. It might take a while for your package to be visible in search results.</p>\n<p>If you want to unlist the package and hide it from search results, follow the steps listed below:</p>\n<ol>\n<li>On nuget.org, select your user name on top right, then select Manage Packages.</li>\n<li>Find the package to be unlisted under Published and select the trash can icon on the right.</li>\n<li>On the next page, clear the box labeled List (package-name) in search results and select Save.</li>\n</ol>\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</style>","frontmatter":{"date":"June 28, 2018","updated_date":null,"description":null,"title":"Using NuGet to publish .NET packages","tags":["NuGet",".NET"],"pinned":null,"coverImage":{"childImageSharp":{"fluid":{"aspectRatio":1,"src":"/static/b965f64c315a9fddcd7037c0d1e1441f/ad85c/desdev.webp","srcSet":"/static/b965f64c315a9fddcd7037c0d1e1441f/61e93/desdev.webp 200w,\n/static/b965f64c315a9fddcd7037c0d1e1441f/1f5c5/desdev.webp 400w,\n/static/b965f64c315a9fddcd7037c0d1e1441f/ad85c/desdev.webp 600w","sizes":"(max-width: 600px) 100vw, 600px"}}},"author":{"id":"Hitesh Pamnani","github":null,"avatar":null}}}},{"node":{"excerpt":"Time Required : less than 10 minutes. Technologies : None. Prerequisites : None. This tutorial will go over how to configure the ‘Actions on…","fields":{"slug":"/engineering/how-to-configure-the-actions-on-google-console-for-google-assistant/"},"html":"<p><strong>Time Required :</strong> less than 10 minutes.</p>\n<p><strong>Technologies :</strong> None.</p>\n<p><strong>Prerequisites :</strong> None.</p>\n<p>This tutorial will go over how to configure the ‘Actions on Google’ console so that it can be used for your Google Assistant actions/events that can be accessed anywhere the Google Assistant is available from phones to Google Home products.</p>\n<h3 id=\"steps\" style=\"position:relative;\"><a href=\"#steps\" aria-label=\"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>Steps</strong></h3>\n<ol>\n<li>\n<p>Create an Actions project and a Dialogflow agent <a href=\"https://console.actions.google.com/u/0/\">here</a>.</p>\n<ol>\n<li>Add/import project.\n<img src=\"/ba196995f1e6e11edbc97407d537ac5e/Screen-Shot-2018-05-30-at-9.47.33-AM-300x280.webp\"></li>\n<li>Click on Skip(in the upper right corner) choosing a category and click Build -> Actions in the left nav to add your first actions.<br>\n<span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 300px; \"\n    >\n      <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 59.00000000000001%; position: relative; bottom: 0; left: 0; background-image: url('data:image/webp;base64,UklGRm4AAABXRUJQVlA4IGIAAAAwBACdASoUAAwAPtFWo0uoJKMhsAgBABoJZACdIDf6AAeF4OYpdmQOgjAA/urzyRWMZSIXJgNyVPN+sSr6m8+jw2kOLf2pL6x2AXOEj5KNzRqpUqgTfWEQjvOOljv6wBgAAA=='); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"Screen Shot 2018 05 30 at 10 02 46 AM 300x177\"\n        title=\"Screen Shot 2018 05 30 at 10 02 46 AM 300x177\"\n        src=\"/static/8ac47fc4a5ae215cff57c935e69a3557/c85cb/Screen-Shot-2018-05-30-at-10.02.46-AM-300x177.webp\"\n        srcset=\"/static/8ac47fc4a5ae215cff57c935e69a3557/c85cb/Screen-Shot-2018-05-30-at-10.02.46-AM-300x177.webp 300w\"\n        sizes=\"(max-width: 300px) 100vw, 300px\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        loading=\"lazy\"\n      />\n    </span></li>\n</ol>\n</li>\n<li>\n<p>Configuration for your action intent in the dialogflow console.</p>\n<ol>\n<li>In the Intent section, enter your training phrases. Start with “talk to”, “speak to”, “ask” and etc, learn more <a href=\"https://developers.google.com/actions/localization/languages-locales\">here.</a>\n<img src=\"/330ce1c9b2fb89629d0215bb5f38d88f/Screen-Shot-2018-05-30-at-10.41.30-AM-300x288.webp\"></li>\n<li>Enter the default text response. This will be the default response for your action until you link your account with LoginRadius and build your customized response. (This will return errors if you leave this empty, even if you handle the response in your code.)<img src=\"/81328793b1a3955ed805c71a9c6664e7/Screen-Shot-2018-05-30-at-10.42.03-AM-300x193.webp\"></li>\n</ol>\n</li>\n</ol>\n<p>By then, you should have finished the setup for google assistant.</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":"June 18, 2018","updated_date":null,"description":null,"title":"How to configure the 'Actions on Google' console for Google Assistant","tags":["Engineering","GoogleAssistant"],"pinned":null,"coverImage":{"childImageSharp":{"fluid":{"aspectRatio":1.3333333333333333,"src":"/static/8744b7a7d1a64b8263651675a3ff555f/58556/google-home-max-13.webp","srcSet":"/static/8744b7a7d1a64b8263651675a3ff555f/61e93/google-home-max-13.webp 200w,\n/static/8744b7a7d1a64b8263651675a3ff555f/1f5c5/google-home-max-13.webp 400w,\n/static/8744b7a7d1a64b8263651675a3ff555f/58556/google-home-max-13.webp 800w,\n/static/8744b7a7d1a64b8263651675a3ff555f/99238/google-home-max-13.webp 1200w,\n/static/8744b7a7d1a64b8263651675a3ff555f/7c22d/google-home-max-13.webp 1600w","sizes":"(max-width: 800px) 100vw, 800px"}}},"author":{"id":"Vincent Lin","github":null,"avatar":null}}}},{"node":{"excerpt":"Time Required: 20 minutes. Technologies: Express, Node.js, JavaScript. Prerequisites: Basic knowledge of Express, Node.js, and JavaScript…","fields":{"slug":"/engineering/creating-a-google-hangout-bot-with-express-and-node-js/"},"html":"<p>Time Required: 20 minutes.<br>\nTechnologies: Express, Node.js, JavaScript.<br>\nPrerequisites:</p>\n<ul>\n<li>Basic knowledge of Express, Node.js, and JavaScript.</li>\n<li>Node.js and npm are installed.</li>\n</ul>\n<p>This tutorial will go over how to build a bot that will respond to pings (i.e. @<bot-name>), and send messages to a chat room. On a high level, the bot will run on an express server, and receive pings via an HTTP endpoint. Responses to pings will be sent synchronously through a payload in the HTTP response, while bot-initiated messages will be sent asynchronously using the Google Hangout Chat API.</p>\n<h5 id=\"outline\" style=\"position:relative;\"><a href=\"#outline\" aria-label=\"outline 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>Outline</strong></h5>\n<ol>\n<li>Environment setup.</li>\n<li>Get bot to respond to pings.</li>\n<li>Send bot-initiated messages.</li>\n<li>Deploy.</li>\n</ol>\n<h5 id=\"environment-setup\" style=\"position:relative;\"><a href=\"#environment-setup\" aria-label=\"environment setup 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>Environment Setup</strong></h5>\n<p>Create a new project with the file ‘app.js’.<br>\nOpen command line/terminal, and navigate to your project directory. Run ‘npm init’, and press enter until package.json is created. Next, install the following dependencies:</p>\n<ul>\n<li>express: <code>npm install express --save</code></li>\n<li>body-parser:  <code>npm install body-parser --save</code></li>\n<li>googleapis: <code>npm install googleapis --save</code></li>\n<li>unirest:  <code>npm install unirest --save</code></li>\n</ul>\n<p>In ‘app.js’, let’s setup our server:</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=\"mtk4\">const</span><span class=\"mtk1\"> </span><span class=\"mtk12\">express</span><span class=\"mtk1\"> = </span><span class=\"mtk11\">require</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&#39;express&#39;</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">const</span><span class=\"mtk1\"> </span><span class=\"mtk12\">bodyParser</span><span class=\"mtk1\"> = </span><span class=\"mtk11\">require</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&#39;body-parser&#39;</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">const</span><span class=\"mtk1\"> { </span><span class=\"mtk12\">google</span><span class=\"mtk1\"> } = </span><span class=\"mtk11\">require</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&#39;googleapis&#39;</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">const</span><span class=\"mtk1\"> </span><span class=\"mtk12\">app</span><span class=\"mtk1\"> = </span><span class=\"mtk11\">express</span><span class=\"mtk1\">();</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk12\">app</span><span class=\"mtk1\">.</span><span class=\"mtk11\">use</span><span class=\"mtk1\">(</span><span class=\"mtk12\">bodyParser</span><span class=\"mtk1\">.</span><span class=\"mtk11\">urlencoded</span><span class=\"mtk1\">({</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">extended:</span><span class=\"mtk1\"> </span><span class=\"mtk4\">false</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">}));</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk12\">app</span><span class=\"mtk1\">.</span><span class=\"mtk11\">use</span><span class=\"mtk1\">(</span><span class=\"mtk12\">bodyParser</span><span class=\"mtk1\">.</span><span class=\"mtk11\">json</span><span class=\"mtk1\">());</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk12\">app</span><span class=\"mtk1\">.</span><span class=\"mtk11\">listen</span><span class=\"mtk1\">(</span><span class=\"mtk7\">8100</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=\"mtk10\">console</span><span class=\"mtk1\">.</span><span class=\"mtk11\">log</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&#39;App listening on port 8100.&#39;</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">});</span></span></code></pre>\n<p>Running ‘node app.js’ will now create a local server on port 8100.</p>\n<h5 id=\"responding-to-pings\" style=\"position:relative;\"><a href=\"#responding-to-pings\" aria-label=\"responding to pings 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>Responding to Pings</strong></h5>\n<p>The bot will respond to pings through a HTTP POST endpoint. Create one with express:</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=\"mtk12\">app</span><span class=\"mtk1\">.</span><span class=\"mtk11\">post</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&#39;/&#39;</span><span class=\"mtk1\">, </span><span class=\"mtk4\">function</span><span class=\"mtk1\">(</span><span class=\"mtk12\">req</span><span class=\"mtk1\">, </span><span class=\"mtk12\">res</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\">&#39;someone pinged @&#39;</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk15\">if</span><span class=\"mtk1\"> (</span><span class=\"mtk12\">req</span><span class=\"mtk1\">.</span><span class=\"mtk12\">body</span><span class=\"mtk1\">.</span><span class=\"mtk12\">type</span><span class=\"mtk1\"> === </span><span class=\"mtk8\">&#39;MESSAGE&#39;</span><span class=\"mtk1\">) {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> </span><span class=\"mtk12\">res</span><span class=\"mtk1\">.</span><span class=\"mtk11\">json</span><span class=\"mtk1\">({</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">      </span><span class=\"mtk12\">text:</span><span class=\"mtk1\"> </span><span class=\"mtk8\">&#39;sleeping...&#39;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    });</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  }</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">});</span></span></code></pre>\n<p>The bot will respond with the text: ‘sleeping…’.</p>\n<p>Synchronously responding to messages simply requires us to return a response to Google. The downside to this is the 30 second time limit before Google no longer accepts responses to the request. For instance, this would be a problem if you were building some kind of reminder app; the bot wouldn't be able to synchronously respond after 30 seconds. This is where async responses come in.</p>\n<h5 id=\"bot-initiated-messages\" style=\"position:relative;\"><a href=\"#bot-initiated-messages\" aria-label=\"bot initiated messages 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>Bot-initiated Messages</strong></h5>\n<p>To show this, we will have our bot post to a chat room every 1 minute.</p>\n<p>Sending async messages to Google API requires a Service Account for authentication. Once authenticated, we can make a POST request to a Google API URL that will create a message.</p>\n<p>So first, create a Google Service Account following these <a href=\"https://developers.google.com/hangouts/chat/how-tos/service-accounts\">steps</a>. Take the downloaded JSON file and put it in the root directory of your project. Here, we renamed it to googlekeys.json:</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=\"mtk4\">const</span><span class=\"mtk1\"> </span><span class=\"mtk12\">gkeys</span><span class=\"mtk1\"> = </span><span class=\"mtk11\">require</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&#39;./googlekeys.json&#39;</span><span class=\"mtk1\">);</span></span></code></pre>\n<p>We will be making POST requests using Unirest:</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=\"mtk4\">const</span><span class=\"mtk1\"> </span><span class=\"mtk12\">unirest</span><span class=\"mtk1\"> = </span><span class=\"mtk11\">require</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&#39;unirest&#39;</span><span class=\"mtk1\">);</span></span></code></pre>\n<p>Now generate a JWT that will be used in our POST request:</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"js\" data-index=\"4\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk4\">function</span><span class=\"mtk1\"> </span><span class=\"mtk11\">getJWT</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=\"mtk4\">let</span><span class=\"mtk1\"> </span><span class=\"mtk12\">jwtClient</span><span class=\"mtk1\"> = </span><span class=\"mtk4\">new</span><span class=\"mtk1\"> </span><span class=\"mtk10\">google</span><span class=\"mtk1\">.</span><span class=\"mtk10\">auth</span><span class=\"mtk1\">.</span><span class=\"mtk10\">JWT</span><span class=\"mtk1\">(</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">      </span><span class=\"mtk12\">gkeys</span><span class=\"mtk1\">.</span><span class=\"mtk12\">client_email</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">      </span><span class=\"mtk4\">null</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">      </span><span class=\"mtk12\">gkeys</span><span class=\"mtk1\">.</span><span class=\"mtk12\">private_key</span><span class=\"mtk1\">, [</span><span class=\"mtk8\">&#39;https://www.googleapis.com/auth/chat.bot&#39;</span><span class=\"mtk1\">]</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    );</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk12\">jwtClient</span><span class=\"mtk1\">.</span><span class=\"mtk11\">authorize</span><span class=\"mtk1\">(</span><span class=\"mtk4\">function</span><span class=\"mtk1\">(</span><span class=\"mtk12\">err</span><span class=\"mtk1\">, </span><span class=\"mtk12\">tokens</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\">err</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\">&#39;Error create JWT hangoutchat&#39;</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\">err</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">      } </span><span class=\"mtk15\">else</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk11\">resolve</span><span class=\"mtk1\">(</span><span class=\"mtk12\">tokens</span><span class=\"mtk1\">.</span><span class=\"mtk12\">access_token</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">      }</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    });</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  });</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">}</span></span></code></pre>\n<p>Here is our function for posting messages. ROOM-ID can be found in the URL of the hangout chat room page i.e.: <code>https://chat.google.com/u/0/room/{ROOM-ID}</code></p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"js\" data-index=\"5\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk4\">function</span><span class=\"mtk1\"> </span><span class=\"mtk11\">postMessage</span><span class=\"mtk1\">(</span><span class=\"mtk12\">count</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=\"mtk11\">getJWT</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\">token</span><span class=\"mtk1\">) {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">          </span><span class=\"mtk12\">unirest</span><span class=\"mtk1\">.</span><span class=\"mtk11\">post</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&#39;https://chat.googleapis.com/v1/spaces/&#39;</span><span class=\"mtk1\"> + {ROOM-</span><span class=\"mtk12\">ID</span><span class=\"mtk1\">} + </span><span class=\"mtk8\">&#39;/messages&#39;</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">              .</span><span class=\"mtk11\">headers</span><span class=\"mtk1\">({</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                  </span><span class=\"mtk8\">&quot;Content-Type&quot;</span><span class=\"mtk12\">:</span><span class=\"mtk1\"> </span><span class=\"mtk8\">&quot;application/json&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                  </span><span class=\"mtk8\">&quot;Authorization&quot;</span><span class=\"mtk12\">:</span><span class=\"mtk1\"> </span><span class=\"mtk8\">&quot;Bearer &quot;</span><span class=\"mtk1\"> + </span><span class=\"mtk12\">token</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">              })</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">              .</span><span class=\"mtk11\">send</span><span class=\"mtk1\">(</span><span class=\"mtk10\">JSON</span><span class=\"mtk1\">.</span><span class=\"mtk11\">stringify</span><span class=\"mtk1\">({</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                  </span><span class=\"mtk8\">&#39;text&#39;</span><span class=\"mtk12\">:</span><span class=\"mtk1\"> </span><span class=\"mtk8\">&#39;Hello! This is message number &#39;</span><span class=\"mtk1\"> + </span><span class=\"mtk12\">count</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">              }))</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">              .</span><span class=\"mtk11\">end</span><span class=\"mtk1\">(</span><span class=\"mtk4\">function</span><span class=\"mtk1\">(</span><span class=\"mtk12\">res</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>\n<span class=\"grvsc-line\"><span class=\"mtk1\">              });</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">      }).</span><span class=\"mtk11\">catch</span><span class=\"mtk1\">(</span><span class=\"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\">reject</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>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  });</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">}</span></span></code></pre>\n<p>Finally, add the code that will repeat our post every minute.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"js\" data-index=\"6\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk4\">const</span><span class=\"mtk1\"> </span><span class=\"mtk12\">timer</span><span class=\"mtk1\"> = </span><span class=\"mtk11\">require</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&#39;timers&#39;</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk12\">app</span><span class=\"mtk1\">.</span><span class=\"mtk11\">listen</span><span class=\"mtk1\">(</span><span class=\"mtk7\">8100</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=\"mtk10\">console</span><span class=\"mtk1\">.</span><span class=\"mtk11\">log</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&#39;App listening on port 8100.&#39;</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk4\">let</span><span class=\"mtk1\"> </span><span class=\"mtk12\">count</span><span class=\"mtk1\"> = </span><span class=\"mtk7\">0</span><span class=\"mtk1\">;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">timer</span><span class=\"mtk1\">.</span><span class=\"mtk11\">setInterval</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\">postMessage</span><span class=\"mtk1\">(</span><span class=\"mtk12\">count</span><span class=\"mtk1\"> += </span><span class=\"mtk7\">1</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  }, </span><span class=\"mtk7\">60000</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">});</span></span></code></pre>\n<h5 id=\"deploy\" style=\"position:relative;\"><a href=\"#deploy\" aria-label=\"deploy 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>Deploy</strong></h5>\n<p>Expose your local server to public (we used <a href=\"https://ngrok.com/\">ngrok</a>).</p>\n<p>Login to <a href=\"https://console.developers.google.com\">developer console</a>. Create a new project, and enable Hangout Chat API. Under configuration, set:</p>\n<ul>\n<li>status: live</li>\n<li>bot name (this is how you will add and ping the bot)</li>\n<li>avatar</li>\n<li>description</li>\n<li>functionality: rooms</li>\n<li>connection settings - bot URL: <your ngrok HTTPS url></li>\n<li>permission: everyone in your domain</li>\n</ul>\n<p>Restart your local server, and that’s it! Make sure you have your bot added to the chat room, and you can ping it by sending @<bot-name>. The bot will also post to the chat room every minute.</p>\n<p>There are a lot of different ways to further extend this bot, such as setting reminders/notifications, making to-do lists, displaying server logs, and interacting with API’s.</p>\n<p><img src=\"/8a9a029d9f5b2717f8798fde837c34e0/image2.webp\"></p>\n<p><img src=\"/b8ded5c577b86826fa436a130babfd07/image1.webp\"></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 .mtk11 { color: #DCDCAA; }\n  .dark-default-dark .mtk8 { color: #CE9178; }\n  .dark-default-dark .mtk7 { color: #B5CEA8; }\n  .dark-default-dark .mtk10 { color: #4EC9B0; }\n  .dark-default-dark .mtk15 { color: #C586C0; }\n</style>","frontmatter":{"date":"June 06, 2018","updated_date":null,"description":null,"title":"Creating a Google Hangout Bot with Express and Node.js","tags":["Express","NodeJs","Hangout"],"pinned":null,"coverImage":{"childImageSharp":{"fluid":{"aspectRatio":1,"src":"/static/ce69f8b38834ee73f9b8821830d73c87/0c543/hangoutchatimgage2.webp","srcSet":"/static/ce69f8b38834ee73f9b8821830d73c87/61e93/hangoutchatimgage2.webp 200w,\n/static/ce69f8b38834ee73f9b8821830d73c87/1f5c5/hangoutchatimgage2.webp 400w,\n/static/ce69f8b38834ee73f9b8821830d73c87/0c543/hangoutchatimgage2.webp 630w","sizes":"(max-width: 630px) 100vw, 630px"}}},"author":{"id":"Andy Yeung","github":null,"avatar":null}}}},{"node":{"excerpt":"Which character do you consider as the end of line or newline? Most developers will answer \\n (except for front-end developers, they would…","fields":{"slug":"/engineering/eol-end-of-line-or-newline-characters/"},"html":"<p>Which character do you consider as the end of line or newline? Most developers will answer \\n (except for front-end developers, they would say: \"&#x3C;/br>tag\" 😊 ). But this is not true, let's understand why.</p>\n<p><strong>What is an End of Line character:</strong></p>\n<p>It is a character in a string which represents a line break, which means that after this character, a new line will start. There are two basic new line characters:</p>\n<p><strong>LF</strong> (character : \\n, Unicode : U+000A, ASCII : 10, hex : 0x0a): This is simply the '\\n' character which we all know from our early programming days. This character is commonly known as the ‘Line Feed’ or ‘Newline Character’.</p>\n<p><strong>CR</strong> (character : \\r, Unicode : U+000D, ASCII : 13, hex : 0x0d) : This is simply the 'r' character. This character is commonly known as ‘Carriage Return’.</p>\n<p>As matter of fact, \\r has also has a different meaning. In older printers, \\r meant moving the print head back to the start of line and \\n meant starting a new line.</p>\n<p><strong>OS support</strong></p>\n<p>Unix: Unix systems consider '\\n' as a line terminator. Unix considers \\r as going back to the start of the same line.</p>\n<p>Mac (up to 9): Older Mac OSs consider '\\r' as a newline terminator but newer OS versions have been made to be more compliant with Unix systems to use '\\n' as the newline.</p>\n<p>Windows: Windows has a different style of newline, Windows supports the combination of both CR and LF as the newline character - '\\r\\n'.</p>\n<p><strong>How to check</strong><br>\nThere are lots ways to check this. I use Notepad++ as my text editor for this because it is easy to use and is widely used by developers.<br>\nNPP show all characters</p>\n<p>Open any text file and click on the pilcrow (¶) button. Notepad++ will show all of the characters with newline characters in either the CR and LF format. If it is a Windows EOL encoded file, the newline characters of CR LF will appear (\\r\\n). If the file is UNIX or Mac EOL encoded, then it will only show LF (\\n).</p>\n<p><strong>NPP Extended search</strong></p>\n<p>Press the key combination of Ctrl + Shift + F and select 'Extended' under the search mode. Now search '\\r\\n' - if you find this at end of every line, it means this is a Windows EOL encoded file. However, if it is '\\n' at the end of every line, then it is a Unix or Mac EOL encoded file.</p>\n<p><strong>How to convert</strong></p>\n<p>Let's stick with notepad++ for this, too. Open any file that you would like to convert, click on the Edit menu, scroll down to the EOL conversion option, and select the format that you would like to convert the file to.</p>\n<p><strong>Reference</strong></p>\n<ul>\n<li><a href=\"https://www.compart.com/en/unicode/U+000A\">Unicode Character (U+000A)</a></li>\n<li><a href=\"https://www.compart.com/en/unicode/U+000D\">Unicode Character (U+000D)</a></li>\n</ul>\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":"September 06, 2017","updated_date":null,"description":"Learn what are EOL (End of Line) or LF (Line Feed) or NL (New Line) ascii characters (\\n\\r) and why there are two (\\n\\r) newline characters.","title":"EOL or End of Line or newline ascii character","tags":["Engineering","EOL","LF","Linux","Mac","Windows"],"pinned":null,"coverImage":{"childImageSharp":{"fluid":{"aspectRatio":1.7699115044247788,"src":"/static/c54e66c499f461eea5df725fac0348d7/58556/eol.webp","srcSet":"/static/c54e66c499f461eea5df725fac0348d7/61e93/eol.webp 200w,\n/static/c54e66c499f461eea5df725fac0348d7/1f5c5/eol.webp 400w,\n/static/c54e66c499f461eea5df725fac0348d7/58556/eol.webp 800w,\n/static/c54e66c499f461eea5df725fac0348d7/99238/eol.webp 1200w,\n/static/c54e66c499f461eea5df725fac0348d7/135cd/eol.webp 1280w","sizes":"(max-width: 800px) 100vw, 800px"}}},"author":{"id":"Kundan Singh","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":240,"currentPage":41,"type":"//engineering//","numPages":53,"pinned":"5c425581-f474-5ae9-abe7-cf5342db2aaa"}},"staticQueryHashes":["1171199041","1384082988","2100481360","23180105","528864852"]}