{"componentChunkName":"component---src-templates-blog-list-template-js","path":"/engineering/39","result":{"data":{"allMarkdownRemark":{"edges":[{"node":{"excerpt":"This blog is part 1 of a series on gRPC. Part 1 will go over some important concepts, part 2 will be a walkthrough of a client-server…","fields":{"slug":"/engineering/getting-started-with-grpc-part-1-concepts/"},"html":"<p><em>This blog is part 1 of a series on gRPC. Part 1 will go over some important concepts, part 2 will be a walkthrough of a client-server implementation in Go, and part 3 will be about LoginRadius' experience migrating to gRPC!</em></p>\n<p><strong>gRPC</strong></p>\n<p>gRPC, simply put, is just another way to send data across networks. It can be used to communicate between services in a microservice architecture, where a single service can interact with multiple others. Similarly, in client-server models, there can be multiple clients communicating with a common backend server.</p>\n<p><img src=\"/eb7252946d79f23eab5aca02ae64256d/Screen-Shot-2019-10-30-at-1.31.52-PM.webp\"></p>\n<p>The gRPC framework was initially developed at Google and is now open-source. It is a modern implementation of the RPC (Remote Procedure Call) protocol, which has been around since the 80s. You will often see gRPC being compared to other technologies like SOAP, REST, and GraphQL.</p>\n<p>Some features:</p>\n<ul>\n<li>HTTP/2 based transport</li>\n<li>Unary calls: single request, single response</li>\n<li>Streaming calls: client, server, and bidirectional</li>\n<li>Layered design for further extension e.g. authentication, load balancing, logging</li>\n</ul>\n<p><em>How is it used to send data?</em></p>\n<p>gRPC is based on the idea of calling a remote procedure just like a local one. A procedure is like a function or a method. So, ideally developers can treat remote and local calls similarly. A great thing about gRPC is that developers do not need to know the details of the remote interaction.</p>\n<p>Here is a diagram from the official grpc <a href=\"https://grpc.io/docs/guides/\">docs</a> showing the flow:</p>\n<p><img src=\"/d21748638236fc42aba043d73c0de37f/Screen-Shot-2019-10-30-at-1.35.45-PM-768x480.webp\"></p>\n<p>Each client service will include a stub, which is like an interface containing the available remote procedures. These stubs are auto-generated files.</p>\n<p><em>But what does proto refer to? And what are stubs? How can we generate them?</em></p>\n<p>To answer these questions, we need to look at another technology called protocol buffers.</p>\n<p><strong>Protocol Buffers</strong></p>\n<p>Protocol buffers (protobufs), are a way to format data for storage and transport. gRPC uses protobufs to format data sent over the wire. It is comparable to other data serialization formats such as JSON, XML, and YAML.</p>\n<p>Some features:</p>\n<ul>\n<li>\n<p>Ability to generate interfaces (stubs) for many languages</p>\n<ul>\n<li>You can create proto definitions once (in a .proto file), and compile it into a variety of different languages including Go, Java, C#, and Python.</li>\n</ul>\n</li>\n<li>\n<p>Requires defining schemas - need to know expected data fields and types</p>\n<ul>\n<li>This is unlike JSON which is flexible.</li>\n</ul>\n</li>\n<li>\n<p>Binary format, meaning data is converted into binary when sent over the wire.</p>\n<ul>\n<li>Binary is smaller, and generally can be decoded faster compared to text-based formats such as JSON.</li>\n</ul>\n</li>\n</ul>\n<p><em>How is it used with gRPC?</em></p>\n<p>Step 1: Create proto definitions - methods, requests, responses.</p>\n<ul>\n<li>For example, in account.proto file, we define 3 rpc methods: Find, Update, and Delete.</li>\n<li>These are the remote procedures that can be called by clients.</li>\n</ul>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"protobuf\" data-index=\"0\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">service AccountService {</span>\n<span class=\"grvsc-line\">  rpc Find(FindRequest) returns (FindResponse);</span>\n<span class=\"grvsc-line\">  rpc Update(UpdateRequest) returns (UpdateResponse);</span>\n<span class=\"grvsc-line\">  rpc Delete(DeleteRequest) returns (DeleteResponse);</span>\n<span class=\"grvsc-line\">}</span></code></pre>\n<ul>\n<li>Each method can have its own request and response schemas.</li>\n</ul>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"protobuf\" data-index=\"1\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">message FindRequest {</span>\n<span class=\"grvsc-line\">  string Uid = 1;</span>\n<span class=\"grvsc-line\">}</span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\">message FindResponse {</span>\n<span class=\"grvsc-line\">  string Uid = 1;</span>\n<span class=\"grvsc-line\">  string Name = 2;</span>\n<span class=\"grvsc-line\">  int32 Age = 3;</span>\n<span class=\"grvsc-line\">  bool isVerified = 4;</span>\n<span class=\"grvsc-line\">}</span></code></pre>\n<ul>\n<li>Note that each field in a message has a unique number. These numbers are used to identify the fields when encoded into binary (recall that protobuf sends data over the wire as binary).</li>\n</ul>\n<p>Step 2: Compile proto file for auto-generated stubs in desired language.</p>\n<ul>\n<li>First, the compiler needs to be <a href=\"https://github.com/protocolbuffers/protobuf\">installed</a>. Refer to blog <em>part 2</em> for detailed instructions.</li>\n<li>The compiler is invoked by the protoc command. In this case, the file account.proto is compiled into Golang with a grpc plugin.</li>\n</ul>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"batch\" data-index=\"2\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">protoc account.proto --go_out=plugins=grpc:.</span></span></code></pre>\n<ul>\n<li>Different languages may have different ways of compiling proto files. For instance with NodeJS, there are npm libraries which allow programmatically compiling proto files.</li>\n</ul>\n<p>Step 3: Use stubs in server and clients.</p>\n<p><strong>The Big Picture</strong></p>\n<p><img src=\"/bca259a3d4e6268ad603d14ed1f03e10/Screen-Shot-2019-10-30-at-1.57.55-PM.webp\"></p>\n<p><strong>Why gRPC?</strong></p>\n<p>One compelling reason to use gRPC is that it provides high performance</p>\n<ul>\n<li>HTTP/2: e.g. requests are multiplexed, so a single long-lived TCP connection can be used by multiple requests at once. This results in less connection overhead.</li>\n<li>Protobufs: e.g. as a binary format, it allows for quick encoding and decoding of data. </li>\n</ul>\n<p><em>How does it differ from REST?</em></p>\n<table>\n<thead>\n<tr>\n<th></th>\n<th><strong>gRPC</strong></th>\n<th><strong>REST</strong></th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>API</td>\n<td>Contract-based i.e. stubs</td>\n<td>Resource-based and relies on HTTP verbs i.e. GET/PUT/POST/DELETE</td>\n</tr>\n<tr>\n<td>Network protocol</td>\n<td>HTTP/2</td>\n<td>HTTP/1.1 or HTTP/2</td>\n</tr>\n<tr>\n<td>Data serialization format</td>\n<td>Protocol buffers</td>\n<td>JSON</td>\n</tr>\n<tr>\n<td>Streaming</td>\n<td>Built-in support for client, server, and bi-directional streaming</td>\n<td>REST on HTTP/1.1 does not allow streaming</td>\n</tr>\n</tbody>\n</table>\n<p><strong>Other Considerations</strong></p>\n<p>Here, we briefly go over a few other things to consider with gRPC. These will be covered in more detail in another blog.</p>\n<p><em>Management of proto files</em><br>\nIf you plan to have multiple proto files and client services, you need some way to manage them for distribution and version control. One solution is to keep all proto files in a central git repository, and maintain versions using git tags.</p>\n<p><em>Using proto2 vs. proto3</em><br>\nProtocol buffers have two syntax versions: proto2 and proto3.</p>\n<ul>\n<li>One key feature in proto2 is that it differentiates between required and optional fields, and supports nullable fields.</li>\n<li>In proto3, all fields are optional and nullable fields are no longer supported. If a field is unset, it will be set to a default value e.g. empty string for type string. Because of this, determining whether a field was intentionally set or not requires workarounds such as using wrappers.</li>\n</ul>\n<p><em>Load-Balancing</em><br>\nSomething to note about load-balancing gRPC is that HTTP/2 requires L7 (Application Layer) load-balancers. Recall that in HTTP/2, TCP connections are long-lived and requests are multiplexed. This makes L4 (Connection Layer) load-balancers ineffective. This differs from HTTP/1.1 where TCP connections get cycled and can benefit from L4 load-balancers. </p>\n<p>That's it for now! To learn more, check out the official <a href=\"https://grpc.io\">gRPC</a> and <a href=\"https://developers.google.com/protocol-buffers\">protobuf</a> docs.</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</style>","frontmatter":{"date":"October 30, 2019","updated_date":null,"description":null,"title":"Getting Started with gRPC - Part 1 Concepts","tags":["Engineering","gRPC"],"pinned":null,"coverImage":{"childImageSharp":{"fluid":{"aspectRatio":1,"src":"/static/23fcca8d49d96b5e61cc171769c93b38/a55b6/grpc.webp","srcSet":"/static/23fcca8d49d96b5e61cc171769c93b38/61e93/grpc.webp 200w,\n/static/23fcca8d49d96b5e61cc171769c93b38/a55b6/grpc.webp 246w","sizes":"(max-width: 246px) 100vw, 246px"}}},"author":{"id":"Andy Yeung","github":null,"avatar":null}}}},{"node":{"excerpt":"Introduction Cross-Site Request Forgery (CSRF) is a common web application attack where a victims’ authenticated session becomes compromised…","fields":{"slug":"/engineering/introduction-to-cross-site-request-forgery-csrf/"},"html":"<p><strong>Introduction</strong></p>\n<p>Cross-Site Request Forgery (CSRF) is a common web application attack where a victims’ authenticated session becomes compromised. This attack essentially tricks a victim into performing unintended tasks on a website they are authenticated in. There are variations to this attack, and a popular one we will discuss is utilizing authentication token to imitate api requests.</p>\n<p><strong>Context</strong></p>\n<p>In order to understand CSRF, it is important to know how cookies and authentication tokens are used for persisting user sessions. Cookies are information stored in the browser, and often used for managing state between HTTP requests. A key feature of cookies is that they are automatically passed as a header in HTTP requests. Authentication tokens are typically stored as cookies, and are a way to keep track of a users’ authenticated session. These tokens are set as cookies after a user successfully authenticates themselves by log in.</p>\n<p><strong>How it works</strong></p>\n<p>CSRF takes advantage of the storage of auth tokens in the browser, and constructs http requests to a target server on behalf of the user. Imitating http requests from the legitimate site requires research and preparation from the attacker beforehand, such as finding vulnerable websites and api’s suitable for the attack.</p>\n<p><img src=\"/29706236a94eec5b8a444b4fd69797b1/image2.webp\"></p>\n<p>Here is a high-level example of an CSRF attack. Note that some details are excluded for simplicity, but the key aspects are included.</p>\n<ol>\n<li>\n<p>John is authenticated on banking.io</p>\n<ul>\n<li>Auth token is set as a cookie on the browser.</li>\n</ul>\n</li>\n<li>\n<p>On another tab, John clicks on an advertisement for free money, which leads to a malicious site.</p>\n<ul>\n<li>Typically, some social engineering is necessary to lure victims to a malicious website.</li>\n</ul>\n</li>\n<li>\n<p>Malicious site makes a POST request to banking.io/setpassword, which is an api for setting a users password to anything.</p>\n<ul>\n<li>The malicious site will construct the POST request for setting password exactly like the legitimate site, and uses John’s authentication cookie.</li>\n<li>The password will be set to anything the attacker wants.</li>\n</ul>\n</li>\n<li>Victim is unable to authenticate with banking.io anymore, because the password was set to something else.</li>\n</ol>\n<p><strong>Mitigation</strong></p>\n<p>A common and effective way of mitigating CSRF is called the double submit cookie. Essentially the client will have two paired and encrypted tokens: one hidden in the page HTML and the other stored as a cookie.</p>\n<p><img src=\"/7a65c1db0bdc228bfa69aeb7455e1e63/image1.webp\"></p>\n<p>When a request is made by the client, both tokens are sent to the server, and the server will then ensure the tokens are valid pairs before processing the request as normal. </p>\n<p><img src=\"/846b57c31fe869f9e584127cd5e6d1f7/image3.webp\"></p>\n<p>Now the attacker will be unable to perform CSRF since they will not have access to the token hidden in the pages HTML, and the target server requires a valid token pair before processing the request.</p>\n<p>There are also many other mitigation techniques, such as using the Same-Site cookie attribute, and requiring user interaction such as CAPTCHA for requests. Learn more on the <a href=\"https://owasp.org/www-community/attacks/csrf\">OWASP wiki</a>).</p>\n<style class=\"grvsc-styles\">\n  .grvsc-container {\n    overflow: auto;\n    -webkit-overflow-scrolling: touch;\n    padding-top: 1rem;\n    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));\n    padding-bottom: 1rem;\n    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));\n    border-radius: 8px;\n    border-radius: var(--grvsc-border-radius, 8px);\n    font-feature-settings: normal;\n  }\n  \n  .grvsc-code {\n    display: inline-block;\n    min-width: 100%;\n  }\n  \n  .grvsc-line {\n    display: inline-block;\n    box-sizing: border-box;\n    width: 100%;\n    padding-left: 1.5rem;\n    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));\n    padding-right: 1.5rem;\n    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));\n  }\n  \n  .grvsc-line-highlighted {\n    background-color: var(--grvsc-line-highlighted-background-color, transparent);\n    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, transparent);\n  }\n  \n</style>","frontmatter":{"date":"October 30, 2019","updated_date":null,"description":null,"title":"Introduction to Cross-Site Request Forgery (CSRF)","tags":["CSRF"],"pinned":null,"coverImage":{"childImageSharp":{"fluid":{"aspectRatio":1.3333333333333333,"src":"/static/45655fcaf75e8e3352165b60c7cac47b/1f5c5/crosspath.webp","srcSet":"/static/45655fcaf75e8e3352165b60c7cac47b/61e93/crosspath.webp 200w,\n/static/45655fcaf75e8e3352165b60c7cac47b/1f5c5/crosspath.webp 400w","sizes":"(max-width: 400px) 100vw, 400px"}}},"author":{"id":"Andy Yeung","github":null,"avatar":null}}}},{"node":{"excerpt":"What is Web Accessibility? Web Accessibility (often stylized “a11y”), is the practice of ensuring that your websites and web applications…","fields":{"slug":"/engineering/introduction-to-web-accessibility-with-semantic-html5/"},"html":"<p><strong>What is Web Accessibility?</strong></p>\n<p>Web Accessibility (often stylized “a11y”), is the practice of ensuring that your websites and web applications are accessible by people with disabilities of many kinds.</p>\n<p>Some examples of common disabilities which we need to consider are: Blindness and visual impairment, deafness and hearing difficulties, motor skill impairment, and many more.</p>\n<p>The common categories of disabilities include:</p>\n<ul>\n<li>Auditory</li>\n<li>Cognitive, learning, and neurological</li>\n<li>Physical</li>\n<li>Speech</li>\n<li>Visual</li>\n</ul>\n<p><em>This list was taken from the W3C Web Accessibility Initiative (WAI). A link to their resources can be found at the bottom.</em></p>\n<p><strong>What is Semantic HTML? What is its correlation with Web Accessibility?</strong></p>\n<p>HTML semantics refers to conveying meaning through the use of HTML elements. An example of <em>semantic</em> HTML would be using <strong><code>&#x3C;header></code></strong>, <strong><code>&#x3C;main></code></strong>, <strong><code>&#x3C;footer></code></strong>, and other content-specific tags when applicable. <em>Unsemantic</em> HTML would be using <strong><code>&#x3C;div></code></strong> or <strong><code>&#x3C;span></code></strong> tags for every use-case.</p>\n<p><strong>Images and “alt” attributes</strong></p>\n<p>Users who are visually impaired may encounter trouble when the content of a website relies on an image. Luckily, there are precautions that we - as developers - can take to ensure that their user experience does not suffer because they are unable to see images.</p>\n<p>The easiest way to do this is to add an <strong>alt</strong> attribute to <strong>all</strong> of your <strong><code>&#x3C;img></code></strong> tags. This way, screen readers will be able to describe the image to the user. Here are a few suggestions and best practices for writing <strong>alt</strong> text:</p>\n<ul>\n<li>\n<p><strong>Do not include words like “image”, or “picture”.</strong> It is redundant, because the screen reader will notify the user that it’s an image. An exception to this would be if the image is of a painting, or an illustration. In this case, emphasizing that is fine, because you want the user to know that it’s specifically a painting, as opposed to any image.</p>\n<ul>\n<li>Example: <strong>alt=”Painted portrait of Albert Einstein”</strong></li>\n</ul>\n</li>\n<li>\n<p><strong>Always include the alt attribute</strong>, even if you don’t want the screen reader to read it. If you have a decorative image (one that is simply cosmetic, and not necessary for the site), then you can add an <strong>alt</strong> tag and assign it to an empty string. In this case, the image will be ignored by the screen reader. If this is neglected, the screen reader may read the file name instead, which may not be particularly helpful.</p>\n<ul>\n<li>Tip: you can also assign an attribute of <strong>role=”presentation”</strong> for decorative images. This can be done in addition to the alt attribute.</li>\n</ul>\n</li>\n<li><strong>Keep it concise.</strong> While there is no limit for length of <strong>alt</strong> text, some screen readers will cut off the alt text at around 125 characters. Either way, you don’t want to waste the user’s time by having their screen reader read a needlessly long description.</li>\n</ul>\n<p><strong>Form Labels and ARIA Labelling</strong></p>\n<p>Users with screen readers will need some way to differentiate between multiple inputs on a single form. Without labels, the user will have a difficult time figuring out what each input is for.</p>\n<p>The easiest way to implement form labelling is with the HTML <strong><code>&#x3C;label></code></strong> tag. The <strong><code>&#x3C;label></code></strong> element uses an attribute called <code>for</code> in order to form a relationship with the ID of the <strong><code>&#x3C;input></code></strong> tag.</p>\n<p>Another way to give context to a screen reader is with the ARIA <strong><code>aria-labelledby</code></strong> attribute. This attribute can be placed on (but not limited to) <strong><code>&#x3C;input></code></strong> tags, and then reference the <strong>id</strong> of the label. You can use <strong><code>&#x3C;label for=””></code></strong> in conjunction with <strong><code>&#x3C;input aria-labelledby=””></code></strong> in order to provide extra support and maximize compatibility.</p>\n<p><strong>Buttons and Tabindices</strong></p>\n<p>Buttons should use <strong><code>&#x3C;button></code></strong> tags (or <strong><code>&#x3C;input type=”submit”></code></strong> if applicable), rather than <strong><code>&#x3C;a></code></strong>, <strong><code>&#x3C;span></code></strong>, <strong><code>&#x3C;div></code></strong>, or anything else that doesn’t have semantic meaning for clickable buttons. Often people choose to use these tags, because they want to clear all styling and not have default <strong><code>&#x3C;button></code></strong> styling. This is ill-advised because <strong><code>&#x3C;button></code></strong> tags come with a ton of functionality built-in, an important part being its <strong><code>tabindex</code></strong>. A user who isn’t able to use a mouse, and must navigate the site with their keyboard, will press the <strong><code>tab</code></strong> key to jump through interactive elements. Standard <strong><code>&#x3C;div></code></strong> tags are not tabbable by default, and assigning a <strong><code>tabindex</code></strong> to it manually can break the flow of the natural tabindices of the page.</p>\n<p><strong>Other Semantic HTML tags</strong></p>\n<p>Other than images and forms, there are still many ways to provide the best accessibility possible. Semantic HTML tags are useful because they describe the content and the relationship with your overall page. Using appropriate, accurate tags such as <strong><code>&#x3C;article></code></strong>, <strong><code>&#x3C;aside></code></strong>, <strong><code>&#x3C;section></code></strong> will give screen readers an idea of what the role is for those sections.</p>\n<p>Other elements such as <strong><code>&#x3C;h1></code></strong> and other heading tags should be carefully planned before sprinkled throughout your webpage. The <strong><code>&#x3C;h1></code></strong> through <strong><code>&#x3C;h6></code></strong> tags should form direct relationships with each other in order to differentiate their meaning. Headings with lower importance (relative to the previous heading) can be used to start new subsections within its current section. Your different page sections can even use <strong><code>aria-labelledby</code></strong> to point to its corresponding heading in order to label your sections accurately.</p>\n<p>The full W3C specification on HTML semantics can be found at: <a href=\"https://www.w3.org/TR/2016/REC-html51-20161101/dom.html\">W3C Recommendation</a>.</p>\n<p>More information about the varying disabilities and barriers can be found at: <a href=\"https://www.w3.org/WAI/people-use-web/abilities-barriers/\">Diverse Abilities and Barriers</a></p>\n<style class=\"grvsc-styles\">\n  .grvsc-container {\n    overflow: auto;\n    -webkit-overflow-scrolling: touch;\n    padding-top: 1rem;\n    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));\n    padding-bottom: 1rem;\n    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));\n    border-radius: 8px;\n    border-radius: var(--grvsc-border-radius, 8px);\n    font-feature-settings: normal;\n  }\n  \n  .grvsc-code {\n    display: inline-block;\n    min-width: 100%;\n  }\n  \n  .grvsc-line {\n    display: inline-block;\n    box-sizing: border-box;\n    width: 100%;\n    padding-left: 1.5rem;\n    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));\n    padding-right: 1.5rem;\n    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));\n  }\n  \n  .grvsc-line-highlighted {\n    background-color: var(--grvsc-line-highlighted-background-color, transparent);\n    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, transparent);\n  }\n  \n</style>","frontmatter":{"date":"July 24, 2019","updated_date":null,"description":null,"title":"Introduction to Web Accessibility with Semantic HTML5","tags":["HTML5","HTML","Web Accessibility","Semantic HTML5"],"pinned":null,"coverImage":{"childImageSharp":{"fluid":{"aspectRatio":1,"src":"/static/70f4300c1f86c6d8e337f40979e66dea/58556/handicapped.webp","srcSet":"/static/70f4300c1f86c6d8e337f40979e66dea/61e93/handicapped.webp 200w,\n/static/70f4300c1f86c6d8e337f40979e66dea/1f5c5/handicapped.webp 400w,\n/static/70f4300c1f86c6d8e337f40979e66dea/58556/handicapped.webp 800w,\n/static/70f4300c1f86c6d8e337f40979e66dea/cc834/handicapped.webp 1024w","sizes":"(max-width: 800px) 100vw, 800px"}}},"author":{"id":"Greg Sakai","github":null,"avatar":null}}}},{"node":{"excerpt":"A basic example of a JavaScript event Events, in JavaScript, are occurrences that can trigger certain functionality, and can result in…","fields":{"slug":"/engineering/javascript-events-bubbling-capturing-and-propagation/"},"html":"<p><strong>A basic example of a JavaScript event</strong></p>\n<p>Events, in JavaScript, are occurrences that can trigger certain functionality, and can result in certain behaviour. A common example of an event, is a “click”, or a “hover”. You can set listeners to watch for these events that will trigger your desired functionality.</p>\n<p><strong>What is “propagation”?</strong></p>\n<p>Propagation refers to how events travel through the Document Object Model (DOM) tree. The DOM tree is the structure which contains parent/child/sibling elements in relation to each other. You can think of propagation as electricity running through a wire, until it reaches its destination. The event needs to pass through every node on the DOM until it reaches the end, or if it is forcibly stopped.</p>\n<p><strong>Event Bubbling and Capturing</strong></p>\n<p>Bubbling and Capturing are the two phases of propagation. In their simplest definitions, <strong>bubbling</strong> travels from the <em>target</em> to the <em>root</em>, and <strong>capturing</strong> travels from the <em>root</em> to the <em>target</em>. However, that doesn’t make much sense without first defining what a target and a root is.</p>\n<p>The <em>target</em> is the DOM node on which you click, or trigger with any other event.</p>\n<p>For example, a button with a click event would be the event target.</p>\n<p>The <em>root</em> is the highest-level parent of the target. This is usually the <strong>document</strong>, which is a parent of the <strong><body></strong>, which is a (possibly distant) parent of your target element.</p>\n<p>Capturing is not used nearly as commonly as bubbling, so our examples will revolve around the bubbling phase. As an option though, <strong>EventTarget.addEventListener()</strong> has an optional third parameter - which takes its argument as a boolean - which controls the phase of the propagation. The parameter is called <strong>useCapture</strong>, and passing <strong>true</strong> will cause the listener to be on the capturing phase. The default is <strong>false</strong>, which will apply it to the bubbling phase.</p>\n<p>Once you trigger the event, it will <em>propagate</em> up to the root, and it will trigger every single event handler which is associated with the same type. For example, if your button has a click event, during the bubbling phase, it will bubble up to the root, and trigger every click event along the way.</p>\n<p>This kind of behaviour might not sound desirable - and it often isn’t - but there’s an easy workaround...</p>\n<p><strong>Event.stopPropagation()</strong></p>\n<p>These two methods are used for solving the previously mentioned problem regarding event propagation. Calling <strong>Event.stopPropagation()</strong> will prevent further propagation through the DOM tree, and only run the event handler from which it was called.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"js\" data-index=\"0\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">&lt;!--</span><span class=\"mtk12\">Try</span><span class=\"mtk1\"> </span><span class=\"mtk12\">it</span><span class=\"mtk1\">--&gt;</span></span></code></pre>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"js\" data-index=\"1\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk4\">function</span><span class=\"mtk1\"> </span><span class=\"mtk11\">first</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=\"mtk7\">1</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">}</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">function</span><span class=\"mtk1\"> </span><span class=\"mtk11\">second</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=\"mtk7\">2</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">}</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">var</span><span class=\"mtk1\"> </span><span class=\"mtk12\">button</span><span class=\"mtk1\"> = </span><span class=\"mtk12\">document</span><span class=\"mtk1\">.</span><span class=\"mtk11\">getElementById</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;button&quot;</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">var</span><span class=\"mtk1\"> </span><span class=\"mtk12\">container</span><span class=\"mtk1\"> = </span><span class=\"mtk12\">document</span><span class=\"mtk1\">.</span><span class=\"mtk11\">getElementById</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;container&quot;</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk12\">button</span><span class=\"mtk1\">.</span><span class=\"mtk11\">addEventListener</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;click&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk12\">first</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk12\">container</span><span class=\"mtk1\">.</span><span class=\"mtk11\">addEventListener</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;click&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk12\">second</span><span class=\"mtk1\">);</span></span></code></pre>\n<p>In this example, clicking the button will cause the console to print <strong>1, 2</strong>. If we wanted to modify this so that <em>only</em> the button’s click event is triggered, we could use <strong>Event.stopPropagation()</strong> to immediately stop the event from bubbling to its parent.</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\">function</span><span class=\"mtk1\"> </span><span class=\"mtk11\">first</span><span class=\"mtk1\">(</span><span class=\"mtk12\">event</span><span class=\"mtk1\">) {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">event</span><span class=\"mtk1\">.</span><span class=\"mtk11\">stopPropagation</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=\"mtk7\">1</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">}</span></span></code></pre>\n<p>This modification will allow the console to print <strong>1</strong>, but it will end the event chain right away, preventing it from reaching <strong>2</strong>.</p>\n<p><strong>How does this differ from <code>Event.stopImmediatePropagation()</code>? When would you use either?</strong></p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"js\" data-index=\"3\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">&lt;!--</span><span class=\"mtk12\">Try</span><span class=\"mtk1\"> </span><span class=\"mtk12\">it</span><span class=\"mtk1\">--&gt;</span></span></code></pre>\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\">first</span><span class=\"mtk1\">(</span><span class=\"mtk12\">event</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=\"mtk7\">1</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">}</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">function</span><span class=\"mtk1\"> </span><span class=\"mtk11\">second</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=\"mtk7\">2</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">}</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">function</span><span class=\"mtk1\"> </span><span class=\"mtk11\">third</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=\"mtk7\">3</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">}</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">var</span><span class=\"mtk1\"> </span><span class=\"mtk12\">button</span><span class=\"mtk1\"> = </span><span class=\"mtk12\">document</span><span class=\"mtk1\">.</span><span class=\"mtk11\">getElementById</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;button&quot;</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">var</span><span class=\"mtk1\"> </span><span class=\"mtk12\">container</span><span class=\"mtk1\"> = </span><span class=\"mtk12\">document</span><span class=\"mtk1\">.</span><span class=\"mtk11\">getElementById</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;container&quot;</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk12\">button</span><span class=\"mtk1\">.</span><span class=\"mtk11\">addEventListener</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;click&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk12\">first</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk12\">button</span><span class=\"mtk1\">.</span><span class=\"mtk11\">addEventListener</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;click&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk12\">second</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk12\">container</span><span class=\"mtk1\">.</span><span class=\"mtk11\">addEventListener</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;click&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk12\">third</span><span class=\"mtk1\">);</span></span></code></pre>\n<p>Let’s suppose we wanted to add a third function, which prints <strong>3</strong> to the console. In this scenario, we will also move the <strong>second</strong> function to also be on the button. We will apply <strong>third</strong> to the container now.</p>\n<p><strong>Long story short</strong>: we have two event handlers on the button, and clicking <strong>&#x3C;div#container></strong> will now print <strong>3</strong>.</p>\n<p>What will happen now? This will behave the same as before, and it will propagate through the DOM tree, and print <strong>1, 2, 3</strong>, in that order.</p>\n<p><strong>How does this tie in to <code>Event.stopPropagation()</code> and <code>Event.stopImmediatePropagation()</code>?</strong></p>\n<p>Adding <strong>Event.stopPropagation()</strong> to the first function, like so, will print <strong>1, 2</strong> to the console.</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\">first</span><span class=\"mtk1\">(</span><span class=\"mtk12\">event</span><span class=\"mtk1\">) {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">event</span><span class=\"mtk1\">.</span><span class=\"mtk11\">stopPropagation</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=\"mtk7\">1</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">}</span></span></code></pre>\n<p>This is because <strong>Event.stopPropagation()</strong> will immediately prevent all click events on the <em>parent</em> from being triggered, but it does <strong>not</strong> stop any <strong>other</strong> event handlers from being called.</p>\n<p>As you can see in our example, our button has two click handlers, and it <em>did</em> stop the propagation to its parents. If you wanted to stop <em>all</em> event handlers after the first, <em>that’s where</em> <strong>Event.stopImmediatePropagation()</strong> <em>comes in.</em></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\">function</span><span class=\"mtk1\"> </span><span class=\"mtk11\">first</span><span class=\"mtk1\">(</span><span class=\"mtk12\">event</span><span class=\"mtk1\">) {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">event</span><span class=\"mtk1\">.</span><span class=\"mtk11\">stopImmediatePropagation</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=\"mtk7\">1</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">}</span></span></code></pre>\n<p>Now, the first function <em>really will</em> stop the parent click handlers, and all other click handlers. The console will now print just <strong>1</strong>, whereas if we simply used <strong>Event.stopPropagation()</strong>, it would print <strong>1, 2</strong>, and not including either would print <strong>1, 2, 3</strong> .</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 .mtk4 { color: #569CD6; }\n  .dark-default-dark .mtk11 { color: #DCDCAA; }\n  .dark-default-dark .mtk10 { color: #4EC9B0; }\n  .dark-default-dark .mtk7 { color: #B5CEA8; }\n  .dark-default-dark .mtk8 { color: #CE9178; }\n</style>","frontmatter":{"date":"July 22, 2019","updated_date":null,"description":null,"title":"JavaScript Events: Bubbling, Capturing, and Propagation","tags":["JavaScript","JavaScript Events"],"pinned":null,"coverImage":{"childImageSharp":{"fluid":{"aspectRatio":1.3333333333333333,"src":"/static/53a3895e9c38870937a9136813ac9e10/0ce14/bubbles.webp","srcSet":"/static/53a3895e9c38870937a9136813ac9e10/61e93/bubbles.webp 200w,\n/static/53a3895e9c38870937a9136813ac9e10/1f5c5/bubbles.webp 400w,\n/static/53a3895e9c38870937a9136813ac9e10/0ce14/bubbles.webp 772w","sizes":"(max-width: 772px) 100vw, 772px"}}},"author":{"id":"Greg Sakai","github":null,"avatar":null}}}},{"node":{"excerpt":"It is hard to write 100% holes-free code, no matter how hard you try. Sometimes it is not even your own fault (language implementation…","fields":{"slug":"/engineering/3-simple-ways-to-secure-your-websites-applications/"},"html":"<p>It is hard to write 100% holes-free code, no matter how hard you try. Sometimes it is not even your own fault (language implementation, server setups, etc.) and those factors are likely out of your control. That being said, as developers, we should strive to write our code as safe and secure as possible. Here are my suggestions to keep yourself from being woken up in the middle of the night:</p>\n<p>1. <strong>DO NOT trust any user-input, PERIOD.</strong> Not even if it is yours truly. This is the most common attack vector for your web applications, whether it is just a contact form or an API end-point. For example, if a form is implemented to store data in a database, someone can try brute-forcing with classic SQL-injection techniques. Others can certainly try calling your API and see if there are any spotty error-handling issues. Sanitize all inputs as much as you can, and handle all errors behind the scenes properly and gracefully without exposing the actual details to the public.</p>\n<p>2. <strong>UPDATE, UPGRADE and REPEAT.</strong> Chances are, a lot of your code is dependent on third-party libraries (open or closed source, does not matter). It is your job to make sure you are using the latest version for them all. When hackers find out you are using outdated or vulnerable code, you are done. I have seen this happening way too many times than I can count over the years when websites got hacked and outdated plugins or libraries was the main culprit.</p>\n<p>You might be saying, \"Hey, upgrading that library will break my code!!\". Well, what is your job again? Deal with it.</p>\n<p>3. <strong>Web Application Firewall (WAF)</strong> Consider getting one if your server admin lets you, it can potentially save yourself a lot of embarrassments. Just keep in mind though it should not be your only security strategy, as WAFs will not stop all kinds of attacks. It is still your sole responsibility to write good code and repeat step 1 and 2.</p>\n<p><strong>Happyyyyy coding!</strong></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 24, 2019","updated_date":null,"description":null,"title":"3 Simple Ways to Secure Your Websites/Applications","tags":["Engineering"],"pinned":null,"coverImage":{"childImageSharp":{"fluid":{"aspectRatio":1.5037593984962405,"src":"/static/5a3022253d6646c0ce3939c478b4481e/ad85c/hacker.webp","srcSet":"/static/5a3022253d6646c0ce3939c478b4481e/61e93/hacker.webp 200w,\n/static/5a3022253d6646c0ce3939c478b4481e/1f5c5/hacker.webp 400w,\n/static/5a3022253d6646c0ce3939c478b4481e/ad85c/hacker.webp 600w","sizes":"(max-width: 600px) 100vw, 600px"}}},"author":{"id":"Karl Wittig","github":null,"avatar":null}}}},{"node":{"excerpt":"Do you remember the Amazon outage that affected several high-profile customers back in 2011? On April 21st, widely-used sites such as Reddit…","fields":{"slug":"/engineering/failover-systems-and-loginradius-99-99-uptime/"},"html":"<p>Do you remember the Amazon outage that affected several high-profile customers back in 2011? On April 21st, widely-used sites such as Reddit and Quora were brought down, and many others experienced latency or were knocked offline, too. Early that morning, as part of normal scaling activities, Amazon staff performed a network change. However, the change was done incorrectly and, after the staff attempted to correct it through a rollback, the inner mechanisms of the service made it unavailable to serve read and write requests. The ‘inner mechanisms’ responsible for the service unavailability are out of the scope of this article, but they are described in the <a href=\"https://aws.amazon.com/message/65648/\">service disruption summary</a> that Amazon published. What interests us here is the strategies that companies can use to mitigate the negative effects on their products when a service they rely on fails. These strategies make up what is known as a <em>failover system</em>.</p>\n<p>A failover system is a set of mechanisms that perform <em>failover</em>. In computer networking, failover is the process of switching to a redundant or standby server or network upon the <strong><em>abnormal</em></strong> termination of a previously-active server or network. The benefit of a failover system is obvious: with one in place, you can ensure your product or service will be available even when adverse events take place. Uptime—time during which a service is operational—is crucial to the success of your business. If your services are unavailable, you are likely to lose customers and any revenue they would have generated. In an article entitled <a href=\"https://medium.com/netflix-techblog/lessons-netflix-learned-from-the-aws-outage-deefe5fd0c04\">‘Lessons Netflix Learned from the AWS Outage</a>,’ Netflix talks about the manual process they used to deal with the Amazon outage and acknowledges the importance of automating this process in the future so they can keep scaling their service. That is, the company acknowledges the importance of having an automated failover system in place instead of relying on a team of top engineers <strong><em>manually</em></strong> making changes every time there is an issue.</p>\n<p>How is an automated failover system set up? Let us consider the simplest scenario: setting a failover system for one server. By definition of a failover system, in addition to the main server, we need to have another redundant standby server that we can switch to whenever the main one fails. Since the redundant server must provide the same functionality as the first, it must be identical to it. Additionally, we need a tool that ensures client requests are routed to the redundant server in case of failure of the main one. We can achieve this by using a DNS failover tool. DNS is the internet protocol used to translate human-readable hostnames into IP addresses, and a DNS failover tool makes sure the “dictionary” (DNS tables) used for this translation are updated in the event of an outage. DNS failover tools know when to update the tables by periodically checking on the main server’s status. With these three tools—and some configuration—you can set up a simple, automated failover system. Of course, there are other considerations you must take when setting the failover system, such as ensuring the redundant standby server is hosted in a geographic area different from the main server’s location and using different companies to host your services. That way, your services will be less likely to go down simultaneously. </p>\n<p>At LoginRadius, we have set up automated failover systems in all layers of our architecture, which is why we can ensure 99.99% uptime on a monthly basis. With our services, you can be assured your customers will always be able to engage with your business, ensuring you will never lose these customers and any revenue they will generate. </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 24, 2019","updated_date":null,"description":null,"title":"Failover Systems and LoginRadius' 99.99% Uptime","tags":["Engineering","AWS"],"pinned":null,"coverImage":{"childImageSharp":{"fluid":{"aspectRatio":1.0050251256281406,"src":"/static/aa689bef0926b16dc0f50c38ca2e3f1c/18421/tech.webp","srcSet":"/static/aa689bef0926b16dc0f50c38ca2e3f1c/61e93/tech.webp 200w,\n/static/aa689bef0926b16dc0f50c38ca2e3f1c/1f5c5/tech.webp 400w,\n/static/aa689bef0926b16dc0f50c38ca2e3f1c/18421/tech.webp 719w","sizes":"(max-width: 719px) 100vw, 719px"}}},"author":{"id":"Ruben Gonzalez","github":"rubenprograms","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":228,"currentPage":39,"type":"//engineering//","numPages":53,"pinned":"5c425581-f474-5ae9-abe7-cf5342db2aaa"}},"staticQueryHashes":["1171199041","1384082988","2100481360","23180105","528864852"]}