{"componentChunkName":"component---src-templates-blog-list-template-js","path":"/128","result":{"data":{"allMarkdownRemark":{"edges":[{"node":{"excerpt":"There is a constant need for compliance and security in every industry that uses customer identities for tracking records, transactions, or…","fields":{"slug":"/identity/loginradius-consumer-audit-trail-data-analysis/"},"html":"<p>There is a constant need for compliance and security in every industry that uses customer identities for tracking records, transactions, or any other activity. As such the advantages of audit trails are multidimensional - from generating historical reports, crime investigation, future budget planning, audit compliance, risk management, and many more.</p>\n<p>The LoginRadius’ recently announced Consumer Audit Trail detects threats in real-time, manages incident response, and if need be, even performs a forensic investigation on past security incidents. It also turns log entries, and events from security systems, into actionable information.</p>\n<p>Additionally, it prepares audits for compliance purposes, provides the functionality to track user engagement, and gain an in-depth understanding of customer behavioral metrics.</p>\n<h2 id=\"intent-behind-the-launch\" style=\"position:relative;\"><a href=\"#intent-behind-the-launch\" aria-label=\"intent behind the launch 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>Intent Behind the Launch</h2>\n<p>The ability to track back records to their source comes with a lot of benefits. Transparency, compliance, accountability, and security of sensitive information are a few of them.</p>\n<p>Through real-time monitoring, businesses can automate audit logs and use them to identify unusual activities or operational issues. </p>\n<p>In addition, audit logs can be used to gain deeper insights into an identity cloud environment. This information improves the application's performance and maintainability and automates actions that otherwise require manual intervention.</p>\n<h2 id=\"core-capabilities-of-loginradius-consumer-audit-trail\" style=\"position:relative;\"><a href=\"#core-capabilities-of-loginradius-consumer-audit-trail\" aria-label=\"core capabilities of loginradius consumer audit trail 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>Core Capabilities of LoginRadius Consumer Audit Trail</h2>\n<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 768px; \"\n    >\n      <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 60.61538461538461%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAMABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAEDBf/EABYBAQEBAAAAAAAAAAAAAAAAAAIAAf/aAAwDAQACEAMQAAABctCaLKmX/8QAGhAAAgIDAAAAAAAAAAAAAAAAAQIAIgMRE//aAAgBAQABBQJkrjYseAjWZEAm5//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EAB0QAAICAQUAAAAAAAAAAAAAAAABERICECExMkH/2gAIAQEABj8CcIWL3OxV8QW90//EAB0QAAIBBAMAAAAAAAAAAAAAAAABESExQWFRgZH/2gAIAQEAAT8hWuEMtKNi7WhKgwVQVtyrC8P/2gAMAwEAAgADAAAAENP/AP/EABYRAQEBAAAAAAAAAAAAAAAAAAARAf/aAAgBAwEBPxCJj//EABYRAQEBAAAAAAAAAAAAAAAAAAARAf/aAAgBAgEBPxCrr//EAB4QAQEAAgEFAQAAAAAAAAAAAAERACFBMVFhcYHh/9oACAEBAAE/EFWmm2rTg/McTeFWDvfGbLZViFybQVDjNii3XvF9T/Gf/9k='); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"Core Capabilities of LoginRadius Consumer Audit Trail\"\n        title=\"Core Capabilities of LoginRadius Consumer Audit Trail\"\n        src=\"/static/64fe103f2211d175424ff037f1385bd0/212bf/Core-Capabilities-of-LoginRadius-Consumer-Audit-Trail.jpg\"\n        srcset=\"/static/64fe103f2211d175424ff037f1385bd0/6aca1/Core-Capabilities-of-LoginRadius-Consumer-Audit-Trail.jpg 650w,\n/static/64fe103f2211d175424ff037f1385bd0/212bf/Core-Capabilities-of-LoginRadius-Consumer-Audit-Trail.jpg 768w,\n/static/64fe103f2211d175424ff037f1385bd0/72e01/Core-Capabilities-of-LoginRadius-Consumer-Audit-Trail.jpg 1024w\"\n        sizes=\"(max-width: 768px) 100vw, 768px\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        loading=\"lazy\"\n      />\n    </span></p>\n<ul>\n<li><strong>Data Collection</strong>: The LoginRadius Data Management Platform gathers data from various sources, APIs, and even from migrated data to enrich the user profile data. </li>\n<li><strong>Secure Data Management</strong>: It offers end-to-end encryption at rest and in transit and ensures <a href=\"https://www.loginradius.com/data-governance/\">data collection within the compliance</a> boundaries of social networks and website privacy policy terms.</li>\n<li><strong>Data Categorization</strong>: It categorizes APIs as create, read, update, delete (CRUD) to manage all rules, properties, and events.</li>\n<li><strong>Data Versioning</strong>: It produces gigabytes of log data every day, and every change made to the user profile is stored/versioned and used for auditing purposes.</li>\n<li><strong>Data Filtration for Identified Data Point</strong>: The consumer audit trail filter the activities of a user based on identified data points like ID, UID, apple ID, CRUD operations on user profile, date, time, region, IP, database, user agent, host and many more.</li>\n<li><strong>Log Retention</strong>: The parsed data is stored for further analysis for a default retention policy, which is the last 30 days. </li>\n<li><strong>Real-Time Alerting</strong>: It offers alert notification supported via email, dashboard, webhook, and other inbuilt integrations.</li>\n<li><strong>Incident Response</strong>: It provides case management, collaboration, and knowledge sharing around security incidents. </li>\n<li><strong>SIEM Complete Solution Analytics</strong>: LoginRadius offers its SIEM solution via integration to showcase the analytical details for business decisions. It supports integrations with most-used tools like Splunk, logstash, sumo logic, etc.</li>\n</ul>\n<p><a href=\"https://www.loginradius.com/resource/loginradius-consumer-audit-trail/\"><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 768px; \"\n    >\n      <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 30.307692307692307%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAGABQDASIAAhEBAxEB/8QAFwABAAMAAAAAAAAAAAAAAAAAAAIDBP/EABUBAQEAAAAAAAAAAAAAAAAAAAEC/9oADAMBAAIQAxAAAAGGIqKgn//EABoQAAICAwAAAAAAAAAAAAAAAAECAAMEERP/2gAIAQEAAQUCoxOtSIDGGm//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAaEAACAgMAAAAAAAAAAAAAAAAAAQIREoGh/9oACAEBAAY/AlLKtDt8KR//xAAaEAEBAAIDAAAAAAAAAAAAAAABEQAhMUHB/9oACAEBAAE/IQ5GusE0kZqvcJkodyZ//9oADAMBAAIAAwAAABAMP//EABcRAAMBAAAAAAAAAAAAAAAAAAABESH/2gAIAQMBAT8QiwZ//8QAFxEAAwEAAAAAAAAAAAAAAAAAARARIf/aAAgBAgEBPxCnV//EABwQAQEAAQUBAAAAAAAAAAAAAAERACExUYGRsf/aAAgBAQABPxBX3Y3JGc4kpwAUeMfyzRUeq/c//9k='); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"Consumer audit trail datasheet\"\n        title=\"Consumer audit trail datasheet\"\n        src=\"/static/2d22772fa230a7fc3d196f16f605e8be/212bf/DS-Cosumer-Audit-Trail-1024x310.jpg\"\n        srcset=\"/static/2d22772fa230a7fc3d196f16f605e8be/6aca1/DS-Cosumer-Audit-Trail-1024x310.jpg 650w,\n/static/2d22772fa230a7fc3d196f16f605e8be/212bf/DS-Cosumer-Audit-Trail-1024x310.jpg 768w,\n/static/2d22772fa230a7fc3d196f16f605e8be/72e01/DS-Cosumer-Audit-Trail-1024x310.jpg 1024w\"\n        sizes=\"(max-width: 768px) 100vw, 768px\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        loading=\"lazy\"\n      />\n    </span></a></p>\n<h2 id=\"a-final-word\" style=\"position:relative;\"><a href=\"#a-final-word\" aria-label=\"a final word 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>A Final Word</h2>\n<p>The world that we live in today falls under several regulatory laws - be it <a href=\"https://www.loginradius.com/blog/2019/09/ccpa-vs-gdpr-the-compliance-war/\">the EU's GDPR, California's CCPA</a>, or any other international statutes. It is a good practice to maintain a reliable and accurate audit log and trail system.</p>\n<p>The LoginRadius' Consumer AuditTrail feature plays a vital role in the maintenance, security, availability, and integrity of the records so businesses can understand the <a href=\"https://www.loginradius.com/blog/identity/cyber-threats-business-risk-covid-19/\">bigger picture in the cybersecurity threat</a> landscape.</p>\n<p><a href=\"https://www.loginradius.com/book-a-demo/\"><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 768px; \"\n    >\n      <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 30.307692307692307%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAGCAYAAADDl76dAAAACXBIWXMAAAsTAAALEwEAmpwYAAABbElEQVQY0zVQO0/CUBQmaihthUbRhPhCAlhKEXlE3s+CCEaBwQF10riQODkwaFyMMcTFwR9gjBvRSeKko4NxcfD/fJ57C8PJbc53+r0soj8Lm5qHbS0HW6AIwZ+DXSvAESxBpJ3MMLph3+xWDlUwm2jCGa5A0isQtRIkhrH/CbdwwkDBHAJlGodexsy6wUkduknMBCfdmxCCBhZKHailfUxGm5jQKphaTUDwmaIWdigyF1oZsm7AFavBRspKuMpdTJMQO5yLbCHVPkG0cYRY4xAR9tbp3T5AsnUMT7YFqzdtOuQOSFmiyMupXUihKuzk0hWvc0xgUYlYod18tAZPrg13eg8rNIuJHSihMtVUHEUe51cLPJ5zo8oJJRJQRnHlQB6WpTjOru7w/fuH59d3PL0M8Th4w+fXDwbDD16R1ZsxCcelsyUbidQEEuC9ECap1J8nCaPTRe/2Ad3LvjkXfZxf3+O0d8P7FnwZ/AMzEsMp2f6LdQAAAABJRU5ErkJggg=='); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"book-a-free-demo-loginradius\"\n        title=\"book-a-free-demo-loginradius\"\n        src=\"/static/779ad148d33fb1ecfd80cc41f1a94ef3/e5715/Book-a-free-demo-request-1024x310.png\"\n        srcset=\"/static/779ad148d33fb1ecfd80cc41f1a94ef3/a6d36/Book-a-free-demo-request-1024x310.png 650w,\n/static/779ad148d33fb1ecfd80cc41f1a94ef3/e5715/Book-a-free-demo-request-1024x310.png 768w,\n/static/779ad148d33fb1ecfd80cc41f1a94ef3/2bef9/Book-a-free-demo-request-1024x310.png 1024w\"\n        sizes=\"(max-width: 768px) 100vw, 768px\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        loading=\"lazy\"\n      />\n    </span></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 02, 2020","updated_date":null,"description":"The recently released Consumer Audit Trail by LoginRadius tracks threats in real time, handles incident response, and even conducts a forensic analysis on past security incidents, if necessary.","title":"LoginRadius Approves Consumer Audit Trail for In-Depth Data Analysis and Risk Assessment","tags":["industry-news"],"pinned":null,"coverImage":{"childImageSharp":{"fluid":{"aspectRatio":1.408450704225352,"src":"/static/630b48719d163e895ae90a3ef26eeec4/14b42/Consumer-Audit-Trail.jpg","srcSet":"/static/630b48719d163e895ae90a3ef26eeec4/f836f/Consumer-Audit-Trail.jpg 200w,\n/static/630b48719d163e895ae90a3ef26eeec4/2244e/Consumer-Audit-Trail.jpg 400w,\n/static/630b48719d163e895ae90a3ef26eeec4/14b42/Consumer-Audit-Trail.jpg 800w,\n/static/630b48719d163e895ae90a3ef26eeec4/c4bcc/Consumer-Audit-Trail.jpg 1026w","sizes":"(max-width: 800px) 100vw, 800px"}}},"author":{"id":"Rakesh Soni","github":"oyesoni","avatar":"rakesh-soni.jpg"}}}},{"node":{"excerpt":"Kafka Streams is a Java library developed to help applications that do stream processing built on Kafka. To learn about Kafka Streams, you…","fields":{"slug":"/engineering/stream-processing-using-kafka/"},"html":"<p>Kafka Streams is a Java library developed to help applications that do stream processing built on Kafka. To learn about Kafka Streams, you need to have a basic idea about Kafka to understand better.  If you’ve worked with Kafka before, Kafka Streams is going to be easy to understand.</p>\n<h2 id=\"what-are-kafka-streams\" style=\"position:relative;\"><a href=\"#what-are-kafka-streams\" aria-label=\"what are kafka streams 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 are Kafka Streams?</h2>\n<p>Kafka Streams is a streaming application building library, specifically applications that turn Kafka input topics into Kafka output topics. Kafka Streams enables you to do this in a way that is distributed and fault-tolerant, with succinct code.</p>\n<h2 id=\"what-is-stream-processing\" style=\"position:relative;\"><a href=\"#what-is-stream-processing\" aria-label=\"what is stream processing 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 Stream processing?</h2>\n<p>Stream processing is the ongoing, concurrent, and record-by-record real-time processing of data.</p>\n<p><strong>Let us get started with some highlights of Kafka Streams:</strong></p>\n<ul>\n<li>Low Barrier to Entry:  Quickly write and run a small-scale POC on a single instance. You only need to run multiple instances of the application on various machines to scale up to high-volume production workloads.</li>\n<li>Lightweight and straightforward client library:  Can be easily embedded in any Java application and integrated with any existing packaging, deployment, and operational tools.</li>\n<li>No external dependencies on systems other than <a href=\"https://en.wikipedia.org/wiki/Apache_Kafka\">Apache Kafka</a> itself</li>\n<li>Fault-tolerant local state: Enables fast and efficient stateful operations like windowed joins and aggregations</li>\n<li>Supports exactly-once processing: Each record will be processed once and only once, even when there is a failure.</li>\n<li>One-record-at-a-time processing to achieve millisecond processing latency supports event-time-based windowing operations with out-of-order arrival of records.</li>\n</ul>\n<h2 id=\"kafka-streams-concepts\" style=\"position:relative;\"><a href=\"#kafka-streams-concepts\" aria-label=\"kafka streams concepts 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>Kafka Streams Concepts:</h2>\n<ul>\n<li><strong>Stream</strong>:  An ordered, replayable, and fault-tolerant sequence of immutable data records, where each data record is defined as a key-value pair.</li>\n<li><strong>Stream Processor</strong>:  A node in the processor topology represents a processing step to transform data in streams by receiving one input record at a time from its source in the topology, applying any operation to it, and may subsequently produce one or more output records to its sinks.</li>\n</ul>\n<p>There are two individual processors in the topology:</p>\n<ul>\n<li><strong>Source Processor</strong>: A source processor is a special type of stream processor that does not have any upstream processors. It produces an input stream to its topology from one or multiple Kafka topics by consuming records from these topics and forwarding them to its down-stream processors.</li>\n<li><strong>Sink Processor</strong>: A sink processor is a special type of stream processor that does not have down-stream processors. It sends any received records from its up-stream processors to a specified Kafka topic.</li>\n</ul>\n<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 768px; \"\n    >\n      <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 119.53846153846155%; position: relative; bottom: 0; left: 0; background-image: url('data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAYABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAIF/8QAFQEBAQAAAAAAAAAAAAAAAAAAAAH/2gAMAwEAAhADEAAAAd1UlASS0LP/xAAYEAACAwAAAAAAAAAAAAAAAAAAECAhMf/aAAgBAQABBQIt7H//xAAVEQEBAAAAAAAAAAAAAAAAAAAQEf/aAAgBAwEBPwEh/8QAFBEBAAAAAAAAAAAAAAAAAAAAIP/aAAgBAgEBPwEf/8QAFBABAAAAAAAAAAAAAAAAAAAAMP/aAAgBAQAGPwIf/8QAGhAAAgMBAQAAAAAAAAAAAAAAAAEQEVFxof/aAAgBAQABPyGtZ1DVmGobovfBH//aAAwDAQACAAMAAAAQ08BB/8QAGBEAAgMAAAAAAAAAAAAAAAAAAAEQETH/2gAIAQMBAT8QuEHp/8QAFhEBAQEAAAAAAAAAAAAAAAAAAQAQ/9oACAECAQE/EMWL/8QAHBABAQEBAAIDAAAAAAAAAAAAAREhABAxQVGB/9oACAEBAAE/EHTfXIzoLSFyngIp6adpYAZvzx60nAijv0XhbqLkPRMv73//2Q=='); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"Toplogy Example\"\n        title=\"Toplogy Example\"\n        src=\"/static/b27b1b16e63c3b3ac479a43ba7c12482/212bf/streams-architecture-topology.jpg\"\n        srcset=\"/static/b27b1b16e63c3b3ac479a43ba7c12482/6aca1/streams-architecture-topology.jpg 650w,\n/static/b27b1b16e63c3b3ac479a43ba7c12482/212bf/streams-architecture-topology.jpg 768w,\n/static/b27b1b16e63c3b3ac479a43ba7c12482/47311/streams-architecture-topology.jpg 1080w\"\n        sizes=\"(max-width: 768px) 100vw, 768px\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        loading=\"lazy\"\n      />\n    </span></p>\n<ul>\n<li><strong>Kstream</strong>: KStream is nothing but that, a Kafka Stream. It’s a never-ending flow of data in a stream. Each piece of data — a record or a fact — is a collection of key-value pairs. Data records in a record stream are always interpreted as an \"INSERT\".</li>\n<li><strong>KTable</strong>: A KTable is just an abstraction of the stream, where only the latest value is kept. Data records in a record stream are always interpreted as an \"UPDATE\".</li>\n</ul>\n<p>There is actually a close relationship between streams and tables, the so-called stream-table duality</p>\n<h2 id=\"implementing-kafka-streams\" style=\"position:relative;\"><a href=\"#implementing-kafka-streams\" aria-label=\"implementing kafka streams 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>Implementing Kafka Streams</h2>\n<p>Let's Start with the Setup using Scala instead of Java. The Kafka Streams DSL for Scala library is a wrapper over the existing Java APIs for Kafka Streams DSL.</p>\n<p>To Setup things, we need to create a <code>KafkaStreams</code> Instance. It needs a topology and configuration (<code>java.util.Properties</code>). We also need a input topic and output topic. Let's look through a simple example of sending data from an input topic to an output topic using the Streams API</p>\n<p>You can create a topic using the below commands (need to have Kafka pre installed)</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"shell\" data-index=\"0\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">kafka-topics --create --zookeeper localhost:2181 --replication-factor 1 --partitions 1 --topic inputTopic</span>\n<span class=\"grvsc-line\">kafka-topics --create --zookeeper localhost:2181 --replication-factor 1 --partitions 1 --topic outputTopic</span></code></pre>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"scala\" data-index=\"1\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">val config: Properties = {</span>\n<span class=\"grvsc-line\">    val properties = new Properties()</span>\n<span class=\"grvsc-line\">    properties.put(StreamsConfig.APPLICATION_ID_CONFIG, &quot;your-application&quot;)</span>\n<span class=\"grvsc-line\">    properties.put(StreamsConfig.BOOTSTRAP_SERVERS_CONFIG, &quot;localhost:9092&quot;)</span>\n<span class=\"grvsc-line\">    properties.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, &quot;latest&quot;)</span>\n<span class=\"grvsc-line\">    properties.put(StreamsConfig.PROCESSING_GUARANTEE_CONFIG, StreamsConfig.EXACTLY_ONCE)</span>\n<span class=\"grvsc-line\">    properties.put(StreamsConfig.DEFAULT_KEY_SERDE_CLASS_CONFIG, Serdes.String())</span>\n<span class=\"grvsc-line\">    properties.put(StreamsConfig.DEFAULT_VALUE_SERDE_CLASS_CONFIG, Serdes.String())</span>\n<span class=\"grvsc-line\">    properties</span>\n<span class=\"grvsc-line\">    }</span></code></pre>\n<p>StreamsBuilder provide the high-level Kafka Streams DSL to specify a Kafka Streams topology.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"scala\" data-index=\"2\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">val builder: StreamsBuilder = new StreamsBuilder</span></code></pre>\n<p>Creates a KStream from the specified topics.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"scala\" data-index=\"3\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">val inputStream: KStream[String,String] = builder.stream(inputTopic, Consumed.`with`(Serdes.String(), Serdes.String()))</span></code></pre>\n<p>Store the input stream to the output topic.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"scala\" data-index=\"4\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">inputStream.to(outputTopic)(producedFromSerde(Serdes.String(),Serdes.String())</span></code></pre>\n<p>Starts the Streams Application</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"scala\" data-index=\"5\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">val kEventStream = new KafkaStreams(builder.build(), config)</span>\n<span class=\"grvsc-line\">kEventStream.start()</span>\n<span class=\"grvsc-line\">sys.ShutdownHookThread {</span>\n<span class=\"grvsc-line\">      kEventStream.close(10, TimeUnit.SECONDS)</span>\n<span class=\"grvsc-line\">    }</span></code></pre>\n<p>You can send data to the input topic using </p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"shell\" data-index=\"6\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">kafka-console-producer --broker-list localhost:9092 --topic inputTopic</span></code></pre>\n<p>And can fetch the data from the output topic using</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"shell\" data-index=\"7\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">kafka-console-consumer --bootstrap-server localhost:9092 --topic outputTopic --from-beginning</span></code></pre>\n<p>You can add the necessary dependencies in your build file for sbt or pom file for maven. Below is an example for build.sbt.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"sbt\" data-index=\"8\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">// Kafka</span>\n<span class=\"grvsc-line\">libraryDependencies += &quot;org.apache.kafka&quot; %% &quot;kafka-streams-scala&quot; % &quot;2.0.0&quot;</span>\n<span class=\"grvsc-line\">libraryDependencies += &quot;javax.ws.rs&quot; % &quot;javax.ws.rs-api&quot; % &quot;2.1&quot; artifacts( Artifact(&quot;javax.ws.rs-api&quot;, &quot;jar&quot;, &quot;jar&quot;)) // this is a workaround. There is an upstream dependency that causes trouble in SBT builds.</span></code></pre>\n<p>Let us modify the code a little bit to try out a WordCount example:\nThe code splits the sentences into words and groups by word as a key and the number of occurences or count as value and is being sent to the output topic by converting the KTable to KStream.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"scala\" data-index=\"9\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">val textLines: KStream[String, String] = builder.stream[String, String](inputTopic)</span>\n<span class=\"grvsc-line\">val wordCounts: KTable[String, Long] = textLines</span>\n<span class=\"grvsc-line\">\t\t.flatMapValues(textLine =&gt; textLine.toLowerCase.split(&quot;\\\\W+&quot;))</span>\n<span class=\"grvsc-line\">\t\t.groupBy((_, word) =&gt; word)</span>\n<span class=\"grvsc-line\">\t\t.count()(materializedFromSerde(Serdes.String(),Serdes.Long()))</span>\n<span class=\"grvsc-line\">\twordCounts.toStream.to(outputTopic)(producedFromSerde(Serdes.String(),Serdes.Long())</span></code></pre>\n<p>With the above process, we can now implement a simple streaming application or a word count application using Kafka Streams in Scala. If you want to set up kafka on Windows, here is a quick guide to implement apache <a href=\"/quick-kafka-installation/\">kafka on windows OS</a>. </p>\n<style class=\"grvsc-styles\">\n  .grvsc-container {\n    overflow: auto;\n    -webkit-overflow-scrolling: touch;\n    padding-top: 1rem;\n    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));\n    padding-bottom: 1rem;\n    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));\n    border-radius: 8px;\n    border-radius: var(--grvsc-border-radius, 8px);\n    font-feature-settings: normal;\n  }\n  \n  .grvsc-code {\n    display: inline-block;\n    min-width: 100%;\n  }\n  \n  .grvsc-line {\n    display: inline-block;\n    box-sizing: border-box;\n    width: 100%;\n    padding-left: 1.5rem;\n    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));\n    padding-right: 1.5rem;\n    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));\n  }\n  \n  .grvsc-line-highlighted {\n    background-color: var(--grvsc-line-highlighted-background-color, transparent);\n    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, transparent);\n  }\n  \n  .dark-default-dark {\n    background-color: #1E1E1E;\n    color: #D4D4D4;\n  }\n</style>","frontmatter":{"date":"July 01, 2020","updated_date":null,"description":"Learn about Kafka Streams, key concepts and highlights with simple streaming or a word count application using Kafka Streams in Scala","title":"Kafka Streams: A stream processing guide","tags":["Scala","Kafka","Kafka Streams"],"pinned":null,"coverImage":{"childImageSharp":{"fluid":{"aspectRatio":1.5037593984962405,"src":"/static/b42ed1fb037f4d27ff3e60a004298488/ee604/header.png","srcSet":"/static/b42ed1fb037f4d27ff3e60a004298488/69585/header.png 200w,\n/static/b42ed1fb037f4d27ff3e60a004298488/497c6/header.png 400w,\n/static/b42ed1fb037f4d27ff3e60a004298488/ee604/header.png 800w,\n/static/b42ed1fb037f4d27ff3e60a004298488/f3583/header.png 1200w","sizes":"(max-width: 800px) 100vw, 800px"}}},"author":{"id":"Priyadarshan Mohanty","github":"priyadarshan1995","avatar":null}}}},{"node":{"excerpt":"You’re probably hosting your MongoDB on a reliable cloud service provider say Atlas for instance because you really want to focus on your…","fields":{"slug":"/engineering/self-hosted-mongo/"},"html":"<p>You’re probably hosting your MongoDB on a reliable cloud service provider say <a href=\"https://cloud.mongodb.com\">Atlas</a> for instance because you really want to focus on your idea and delegate all the subtle key management areas such as networking, storage, access, etc.</p>\n<p>It all looks good initially until your small idea starts turning into a business and the cost starts skyrocketing. Even if that is not the case, this post will still give you a general overview of the technical complexities involved (and bucks saved!) if you were to migrate to a self-hosted solution.</p>\n<p>BTW, how much savings are we talking about? Let’s do a quick comparison between an <strong>Atlas</strong> instance and a self-hosted MongoDB on <strong>AWS</strong>.</p>\n<p><strong>Atlas (~$166/month)</strong></p>\n<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 768px; \"\n    >\n      <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 42%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAICAIAAAB2/0i6AAAACXBIWXMAAAsTAAALEwEAmpwYAAABDUlEQVQY031Qy24DIQzM//9YL1VvVXto02y0kdhHAAMGzLPejdJDGxWNMBiPPcPhWR9f3TjQ9cWcLqQwExAuSlJJvtIMUqjVF4LoxkVINAKu78ORcVbzQRjpQlDGfAwnqSGnjNZNej0r4RxSpFrqjpJT6r23WjkZfdDeHiYmozeIYK3znp9jjF9GPIm3EEMkChQ3xICIrfdaKxcYDatR22QMQSzLMI7aGIeotebaXDpSibn2P6vtu01+l+09y5YA3AUcTtOMPqTaKNdc2n/km2zLfAAWz95SSq094DyebNmzx4sQq1IsGwDanc3hp1Hr7Td5tkpq/TkMN892W44D7P75opTm8w2c5w/rd/I3OuXMieG2KrwAAAAASUVORK5CYII='); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"&quot;Atlas Pricing&quot;\"\n        title=\"Atlas Pricing\"\n        src=\"/static/37ae695d63da0d8e11b315ac53da7162/e5715/atlas.png\"\n        srcset=\"/static/37ae695d63da0d8e11b315ac53da7162/a6d36/atlas.png 650w,\n/static/37ae695d63da0d8e11b315ac53da7162/e5715/atlas.png 768w,\n/static/37ae695d63da0d8e11b315ac53da7162/cc8d6/atlas.png 791w\"\n        sizes=\"(max-width: 768px) 100vw, 768px\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        loading=\"lazy\"\n      />\n    </span>\n$0.23/hour based on the above-selected requirements (~ <a href=\"https://cloud.mongodb.com\">cloud.mongodb.com</a>)</p>\n<p><br><br><strong>AWS (~$36/month)</strong>\n<span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 768px; \"\n    >\n      <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 27.846153846153847%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAGCAIAAABM9SnKAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAu0lEQVQY021QywqDMBDM//9Sv6HnXgo9VMGoZPMg72g6RhRpO2yGIQmzs8sez1c/cEGktNbGgKVSX4XLcZqPmmZBYuTqfmMpxlxKrdU51/U9SQldSlmW5WQhKISQck4p4bMgqZWqemZo50Pw3ltriQjt/QHYbew9HHcNwAVRlDE2RPbuOmtdaIgxhgtOl6v27Qkt4cgkyYIo/4DM9QdIvq4rBF7ZwDn2sW2rsWwLw4pwMEhuc16B9LtA/w8AoVktzOpq7wAAAABJRU5ErkJggg=='); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"&quot;AWS Pricing&quot;\"\n        title=\"AWS Pricing\"\n        src=\"/static/919463e3199f2098ff4d7388991b988f/e5715/aws.png\"\n        srcset=\"/static/919463e3199f2098ff4d7388991b988f/a6d36/aws.png 650w,\n/static/919463e3199f2098ff4d7388991b988f/e5715/aws.png 768w,\n/static/919463e3199f2098ff4d7388991b988f/2cefc/aws.png 1400w\"\n        sizes=\"(max-width: 768px) 100vw, 768px\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        loading=\"lazy\"\n      />\n    </span></p>\n<p>$0.0416/hour for the instance and additional pricing based on the EBS type and storage (~ <a href=\"https://calculator.aws/\">calculator.aws</a>)</p>\n<blockquote>\n<p>It is almost 4.5x savings just in terms of the infrastructure!</p>\n</blockquote>\n<p>Now that you know the major why(s) and are still reading this post, without further ado, let’s dive into the tech.</p>\n<hr />\n<h1 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>Outline</h1>\n<ol>\n<li>Setting up the infrastructure</li>\n<li>Setting up MongoDB</li>\n<li>Bulk migration</li>\n<li>Delta-sync to bridge the connection switch latency (not applicable to stale clusters)</li>\n</ol>\n<p>Since the entire content can be a bit exhausting in one place, I’m going to divide this into 2 related posts.</p>\n<h1 id=\"1-setting-up-the-infrastructure\" style=\"position:relative;\"><a href=\"#1-setting-up-the-infrastructure\" aria-label=\"1 setting up the infrastructure 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. Setting up the Infrastructure</h1>\n<p>I’m going to mention below the guide for setting up an instance running <strong>RedHat Enterprise Linux 8</strong> on AWS. This is because MongoDB generally performs better with the xfs file-system.</p>\n<h2 id=\"spin-up-an-ec2-instance\" style=\"position:relative;\"><a href=\"#spin-up-an-ec2-instance\" aria-label=\"spin up an ec2 instance 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>Spin up an EC2 Instance</h2>\n<p>I’ve used a <code>t3.small</code> instance that comes with <strong>2 vCPUs</strong> and <strong>2Gb of RAM</strong> albeit you can select any instance of your choice.</p>\n<blockquote>\n<p>It is recommended that your DB should have access to at least <strong>1GB of RAM</strong> and <strong>2 real cores</strong> as that directly affects the performance during caching &#x26; concurrency mechanisms as handled by the default engine <a href=\"https://docs.mongodb.com/manual/core/wiredtiger/\"><strong>WiredTiger</strong></a>. You can read more about the <a href=\"https://docs.mongodb.com/manual/administration/production-notes/#allocate-sufficient-ram-and-cpu\"><strong>production notes related to the RAM and CPU requirements here</strong></a>.</p>\n</blockquote>\n<p><em>Configuration Overview:</em></p>\n<ul>\n<li>OS: <strong>Redhat Enterprise Linux 8 (x64 intel-based)</strong></li>\n<li>Instance Type: <strong>t3.small</strong></li>\n<li>Storage: <strong>10GB</strong>(os) + <strong>30GB</strong>(data) + <strong>3GB</strong>(logs) of <strong>EBS</strong> i.e. 3 separate volumes</li>\n</ul>\n<p>I’m assuming that you’re familiar with creating a VM on AWS.</p>\n<p>Now, once the instance is in running state, assign an <strong>Elastic IP</strong> to it and then simply do a remote login into the machine.</p>\n<blockquote>\n<p>We'll need the <strong>Elastic IP</strong> to setup public hostname for the instance</p>\n</blockquote>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"bash\" data-index=\"0\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">$ ssh -i &lt;PEM_FILE&gt; ec2-user@&lt;ELASTIC_IP&gt;</span></span></code></pre>\n<h2 id=\"mount-additional-volumes\" style=\"position:relative;\"><a href=\"#mount-additional-volumes\" aria-label=\"mount additional volumes 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>Mount Additional Volumes</h2>\n<p>We have added 2 additional EBS volumes other than the Root FS for Data and Logs which are yet to be mounted (<em>Remember the 30Gb and 3Gb?</em>). You can list the volume blocks using,</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"bash\" data-index=\"1\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">$ sudo lsblk</span></span></code></pre>\n<p>The additional volumes will be listed right after the root block (refer to the arrows)</p>\n<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 353px; \"\n    >\n      <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 25.21246458923513%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAFCAIAAADKYVtkAAAACXBIWXMAAAsTAAALEwEAmpwYAAAA8klEQVQY0x2PyW6DMBCGeYKeUEmhbFJDCeBQFKAsYTFmSykW4lBVqtRz3/8J+sffYTRj+5vxSNM0DcMgy3Jd133fM8auAuQ4ybIMsaoqPMPVOI4oNU17FkhN00DWDb2l7crX4Exc1w3DsBEkSYIuaZoahmHbtmmalmXpgrvs+z6ldP34vA0zX/jri+McHUJIWZYYAnmeZ8iY9iQ4HA6Koqiqepcv8WXshmPlVT9s/LqdaeQGLgkI5xwyNHw4z/M4jqMoeheg9DwPjaSOdexKH7JH8pflv/TtO3Ojk3/y8LooCkTsiaQVLMuCptu27fuO7f4B7lI+vFGhNDMAAAAASUVORK5CYII='); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"&quot;sudo lsblk&quot;\"\n        title=\"List volume blocks\"\n        src=\"/static/e89cd4d9897ca07cc7ffb0edcda7119e/6c115/lsblk.png\"\n        srcset=\"/static/e89cd4d9897ca07cc7ffb0edcda7119e/6c115/lsblk.png 353w\"\n        sizes=\"(max-width: 353px) 100vw, 353px\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        loading=\"lazy\"\n      />\n    </span></p>\n<p>In the image above, you can see that the additional volumes are named</p>\n<ol>\n<li><strong>xvdb</strong> (30Gb space to store data)</li>\n<li><strong>xvdc</strong> (3Gb space to store logs)</li>\n</ol>\n<p>Now, let’s create the file-systems in those volumes.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"bash\" data-index=\"2\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">$ sudo mkfs.xfs -L mongodata /dev/xvdb</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">$ sudo mkfs.xfs -L mongologs /dev/xvdc</span></span></code></pre>\n<blockquote>\n<p><code>-L</code> is an alias option for setting the <strong>volume label</strong></p>\n</blockquote>\n<p>And then mount the volumes.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"bash\" data-index=\"3\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">$ sudo mount -t xfs /dev/xvdb /var/lib/mongo</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">$ sudo mount -t xfs /dev/xvdc /var/log/mongodb</span></span></code></pre>\n<p>In order for these changes to reflect, the system must be rebooted. Hence, now we also need the partition persistence so that in case of an unintentional reboot we don’t lose the Database storage.</p>\n<p>We can achieve this by specifying the mount rules in the fstab file. <a href=\"https://geek-university.com/linux/etc-fstab-file/\">You can read more about it here</a>.</p>\n<p>Before that let's copy the UUID of the above partitions(<em>because they are unique and won't change over a system restart</em>)</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"bash\" data-index=\"4\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">$ sudo blkid</span></span></code></pre>\n<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 768px; \"\n    >\n      <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 9.846153846153847%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAACCAIAAADXZGvcAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAaUlEQVQI1x2KvQrFIAyF+xiCk5ODg1i7FBJsoWkrGlO47/8uN/gNh/O3EFEp5ZkMHnAi/A7+uLUmIsysB/W991rrO1GTc3bOLbohoma66Rty8b0LrpuueZ2klFQBQJsQQozRe2+Msdb+AZEjHOgCyMRoAAAAAElFTkSuQmCC'); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"&quot;sudo blkid&quot;\"\n        title=\"List attached block info\"\n        src=\"/static/a37188eaa209c947db818b61fd19dfbb/e5715/blkid.png\"\n        srcset=\"/static/a37188eaa209c947db818b61fd19dfbb/a6d36/blkid.png 650w,\n/static/a37188eaa209c947db818b61fd19dfbb/e5715/blkid.png 768w,\n/static/a37188eaa209c947db818b61fd19dfbb/20c85/blkid.png 999w\"\n        sizes=\"(max-width: 768px) 100vw, 768px\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        loading=\"lazy\"\n      />\n    </span></p>\n<p>Copy the UUIDs listed for <strong>/dev/xvdb</strong> and <strong>/dev/xvdc</strong>. Refer to the <strong>“LABEL”</strong> for block identification</p>\n<p>Now open the <code>/etc/fstab</code> file and paste the configuration in the following format.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"bash\" data-index=\"5\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">UUID=&lt;COPIED_UUID_FOR_DATA&gt; /var/lib/mongo xfs defaults,nofail 0 0</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">UUID=&lt;COPIED_UUID_FOR_LOGS&gt; /var/log/mongodb xfs defaults,nofail 0 0</span></span></code></pre>\n<h2 id=\"update-hostname\" style=\"position:relative;\"><a href=\"#update-hostname\" aria-label=\"update hostname 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>Update Hostname</h2>\n<p>The hostname will be used to identify your database server on the network. You can either use the above assigned <strong>Elastic IP</strong> or Domain name (if available). Open the <code>/etc/hostname</code> file and append the entry. For e.g.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"bash\" data-index=\"6\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">ip-xx.us-east-2.compute.internal **&lt;ELASTIC_IP&gt; &lt;DOMAIN_1&gt; &lt;DOMAIN_2&gt;** ...</span></span></code></pre>\n<h2 id=\"update-the-process-limits-optional\" style=\"position:relative;\"><a href=\"#update-the-process-limits-optional\" aria-label=\"update the process limits 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>Update the Process Limits (Optional)</h2>\n<p>This is optionally required in order to control the maximum number of acceptable connections while keeping the system stable.\nOpen the <code>/etc/security/limits.conf</code> file and add the following entries.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"bash\" data-index=\"7\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">* soft nofile 64000</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">* hard nofile 64000</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">* soft nproc 32000</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">* hard nproc 32000</span></span></code></pre>\n<p>Now that all of the infra related prerequisites are sorted, <strong>reboot</strong> the instance, and let’s proceed to MongoDB installation.</p>\n<hr />\n<h1 id=\"1-setting-up-mongodb\" style=\"position:relative;\"><a href=\"#1-setting-up-mongodb\" aria-label=\"1 setting up mongodb 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. Setting up MongoDB</h1>\n<h2 id=\"add-the-repo-source\" style=\"position:relative;\"><a href=\"#add-the-repo-source\" aria-label=\"add the repo source 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>Add the Repo Source</h2>\n<p>Create a file <code>/etc/yum.repos.d/mongodb-org.4.2.repo</code> and add the following package repository details.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"bash\" data-index=\"8\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">[mongodb-org-4.2]</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">name=MongoDB Repository</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">baseurl=https://repo.mongodb.org/yum/redhat/</span><span class=\"mtk12\">$releasever</span><span class=\"mtk1\">/mongodb-org/4.2/x86_64/</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">gpgcheck=1</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">enabled=1</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">gpgkey=https://www.mongodb.org/static/pgp/server-4.2.asc</span></span></code></pre>\n<p>Now let’s install MongoDB.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"bash\" data-index=\"9\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">$ sudo yum -y install mongodb-org</span></span></code></pre>\n<h2 id=\"create-directories-and-setup-permissions\" style=\"position:relative;\"><a href=\"#create-directories-and-setup-permissions\" aria-label=\"create directories and setup permissions 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>Create directories and setup permissions</h2>\n<p>MongoDB by default uses the following paths to store the data and the internal logs:</p>\n<blockquote>\n<p><strong>/var/lib/mongo</strong> → Data<br><strong>/var/log/mongodb</strong> → Logs</p>\n</blockquote>\n<p><strong>Create the directories</strong></p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"bash\" data-index=\"10\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">$ sudo mkdir /var/lib/mongo</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">$ sudo mkdir /var/log/mongodb</span></span></code></pre>\n<p><strong>Change user &#x26; group permissions</strong></p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"bash\" data-index=\"11\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">$ sudo chown mongod:mongod /var/lib/mongo</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">$ sudo chown mongod:mongod /var/log/mongod</span></span></code></pre>\n<h2 id=\"create-an-admin-user\" style=\"position:relative;\"><a href=\"#create-an-admin-user\" aria-label=\"create an admin user 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>Create an Admin User</h2>\n<p>The <strong>mongod daemon/service</strong> must be first running before we proceed to create a user.\nLet’s use the default config(stored in <code>/etc/mongod.conf</code>) for now and start the daemon process.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"bash\" data-index=\"12\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">$ sudo -u mongod mongod -f /etc/mongod.conf</span></span></code></pre>\n<p>The above command will start the mongod daemon in fork mode (default).</p>\n<p>Now, let’s login to the server and create our first admin user.</p>\n<p><strong>Open a mongo shell</strong></p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"bash\" data-index=\"13\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">$ mongo</span></span></code></pre>\n<p><strong>Use the \"admin\" database to create the root-admin</strong></p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"bash\" data-index=\"14\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">&gt; use admin</span></span></code></pre>\n<p><strong>Create the admin user</strong></p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"bash\" data-index=\"15\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">&gt; db.createUser({user: </span><span class=\"mtk8\">&quot;admin&quot;</span><span class=\"mtk1\">, pwd: </span><span class=\"mtk8\">&quot;password&quot;</span><span class=\"mtk1\">, roles: [{role: </span><span class=\"mtk8\">&quot;root&quot;</span><span class=\"mtk1\">, db: </span><span class=\"mtk8\">&quot;admin&quot;</span><span class=\"mtk1\">}]})</span></span></code></pre>\n<p><strong>Create a regular user</strong></p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"bash\" data-index=\"16\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">&gt; db.createUser({user: </span><span class=\"mtk8\">&quot;normal_user&quot;</span><span class=\"mtk1\">, pwd: </span><span class=\"mtk8\">&quot;password&quot;</span><span class=\"mtk1\">, roles: [{role: </span><span class=\"mtk8\">&quot;readWriteAnyDatabase&quot;</span><span class=\"mtk1\">, db: </span><span class=\"mtk8\">&quot;admin&quot;</span><span class=\"mtk1\">}]})</span></span></code></pre>\n<p><strong>Shutdown the server for now. We'll restart again with the modified config</strong></p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"bash\" data-index=\"17\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">&gt; </span><span class=\"mtk11\">db.shutDownServer</span><span class=\"mtk1\">()</span></span></code></pre>\n<h2 id=\"setting-up-authentication\" style=\"position:relative;\"><a href=\"#setting-up-authentication\" aria-label=\"setting up authentication 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>Setting up Authentication</h2>\n<p>Here, we’ll enable the database authentication and modify the bind-address for our server to be accessible in the public domain.\nOpen <code>/etc/mongod.conf</code> and make the below changes.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"bash\" data-index=\"18\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk3\"># network interfaces</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">net:</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  port: 27017</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  bindIp: 0.0.0.0 </span><span class=\"mtk3\"># accessible on the network address</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">security:</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  authorization: enabled </span><span class=\"mtk3\"># creds will be required for making db operations</span></span></code></pre>\n<p>Save the config and <strong>restart</strong> the server.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"bash\" data-index=\"19\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">$ sudo -u mongod mongod -f /etc/mongod.conf</span></span></code></pre>\n<h2 id=\"test-login\" style=\"position:relative;\"><a href=\"#test-login\" aria-label=\"test 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>Test Login</h2>\n<p>You can verify if the credentials work using,</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"bash\" data-index=\"20\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">$ mongo -u admin -p password</span></span></code></pre>\n<p>That is it about the initial setup! Please stay tuned for my next related post on the detailed migration process and tips on keeping the DB production-ready.</p>\n<p>P.S. Thanks to <a href=\"https://twitter.com/MrEnvoy17\">Piyush Kumar</a> for helping curate this post!</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 .mtk11 { color: #DCDCAA; }\n  .dark-default-dark .mtk3 { color: #6A9955; }\n</style>","frontmatter":{"date":"June 30, 2020","updated_date":null,"description":"Learn how to optimize your DB cost? This article will help you with the complete migration steps from a cloud to a self-hosted environment.","title":"Self-Hosted MongoDB","tags":["MongoDB","Mongo","AWS","Atlas"],"pinned":null,"coverImage":{"childImageSharp":{"fluid":{"aspectRatio":2.0408163265306123,"src":"/static/504642ca3a1f7d78dea8509436faa4c6/14b42/cover.jpg","srcSet":"/static/504642ca3a1f7d78dea8509436faa4c6/f836f/cover.jpg 200w,\n/static/504642ca3a1f7d78dea8509436faa4c6/2244e/cover.jpg 400w,\n/static/504642ca3a1f7d78dea8509436faa4c6/14b42/cover.jpg 800w,\n/static/504642ca3a1f7d78dea8509436faa4c6/d8343/cover.jpg 925w","sizes":"(max-width: 800px) 100vw, 800px"}}},"author":{"id":"Chinmaya Pati","github":"cnp96","avatar":null}}}},{"node":{"excerpt":"Roadmap of IDX-auto-tester We're delightfully Announcing the upcoming releases of LoginRadius Identity-Experience-Framework Open-Source…","fields":{"slug":"/engineering/roadmap-idx-autotester/"},"html":"<h1 id=\"roadmap-of-idx-auto-tester\" style=\"position:relative;\"><a href=\"#roadmap-of-idx-auto-tester\" aria-label=\"roadmap of idx auto tester 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>Roadmap of IDX-auto-tester</h1>\n<p>We're delightfully Announcing the upcoming releases of LoginRadius Identity-Experience-Framework Open-Source Automation</p>\n<p>These full-version releases will include more test coverage and major changes with several improvements &#x26; code optimizations, the details have been given below.<br>\nThe below changes are planned to go live in multiple scheduled major releases starting with mid of June 2020.  </p>\n<h2 id=\"release-roadmap\" style=\"position:relative;\"><a href=\"#release-roadmap\" aria-label=\"release roadmap 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>Release Roadmap:</h2>\n<h3 id=\"july-2020\" style=\"position:relative;\"><a href=\"#july-2020\" aria-label=\"july 2020 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>July 2020:</h3>\n<h4 id=\"test-cases\" style=\"position:relative;\"><a href=\"#test-cases\" aria-label=\"test cases 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>Test Cases:</h4>\n<ul>\n<li><strong>Improving the ratio of Good Test Cases in Test repository:</strong> We will be adding more test cases in Registration and Login flow to cover as much as possible Use Cases.</li>\n<li><strong>Increasing Negative Test Case Coverage:</strong> We are also focusing on negative test cases that are the most important part of the Test Coverage in Testing Life Cycle.</li>\n<li><strong>Delivering Manual Test Cases</strong>: We know that understanding of the test steps or mining the test cases by reading the code is not so easy for everyone, so we will also deliver the written Test Cases with the expected outcomes.</li>\n</ul>\n<blockquote>\n<p><em>CI/CD pipelines for automation is to make everyday development tasks simple that can save time and reduce human intervention to check them every single code commit.</em></p>\n</blockquote>\n<h3 id=\"august-2020\" style=\"position:relative;\"><a href=\"#august-2020\" aria-label=\"august 2020 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>August 2020:</h3>\n<h4 id=\"usability-improvements\" style=\"position:relative;\"><a href=\"#usability-improvements\" aria-label=\"usability improvements 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>Usability Improvements:</h4>\n<ul>\n<li>Adding Command-line parameters for parallel run.</li>\n<li>Improving the naming conventions of functions for better readability.  </li>\n<li>Better Error and Exception Handling for failed assertions.</li>\n<li>Adding detailed descriptive comments to functions, custom-commands, and test cases for better understanding.</li>\n</ul>\n<h4 id=\"documentations\" style=\"position:relative;\"><a href=\"#documentations\" aria-label=\"documentations 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>Documentations:</h4>\n<ul>\n<li>Improved Installation &#x26; usage guide</li>\n<li>More about different nightwatch configurations.</li>\n<li>More about working with <code>headless</code> mode</li>\n</ul>\n<blockquote>\n<p><em>We are not just delivering automation we deliver values to our customers, some useful tips \"to working with selenium and nightwatch\" can be expected with this release</em></p>\n</blockquote>\n<h3 id=\"september-2020\" style=\"position:relative;\"><a href=\"#september-2020\" aria-label=\"september 2020 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>September 2020:</h3>\n<h4 id=\"code-level-improvements-and-optimizations\" style=\"position:relative;\"><a href=\"#code-level-improvements-and-optimizations\" aria-label=\"code level improvements and optimizations permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Code Level Improvements and Optimizations:</h4>\n<ul>\n<li>Applying Page Object Model for application pages instead of static CSS-selector class.</li>\n<li>Applying async functioning in Test Cases and Custom-Commands to overcome the callback.    </li>\n<li>Updating the Custom-Command as per the latest version of nightwatch.</li>\n<li>Browser Compatibility Testing.</li>\n</ul>\n<h4 id=\"better-reporting\" style=\"position:relative;\"><a href=\"#better-reporting\" aria-label=\"better reporting 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>Better Reporting:</h4>\n<ul>\n<li>More detailed, readable and graphical-representation of html reports will be added.</li>\n</ul>\n<blockquote>\n<p><em>Although current configuration does not support different browsers, still you can run on any browser by making few changes in nightwatch.json detailed guide is <a href=\"https://nightwatchjs.org/guide/running-tests/\">here</a></em></p>\n</blockquote>\n<h3 id=\"october-2020\" style=\"position:relative;\"><a href=\"#october-2020\" aria-label=\"october 2020 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>October 2020:</h3>\n<h4 id=\"overcoming-the-limitations\" style=\"position:relative;\"><a href=\"#overcoming-the-limitations\" aria-label=\"overcoming the limitations 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>Overcoming the Limitations:</h4>\n<ul>\n<li>The build will be coming up with testing support of IEF feature <code>optional</code> and <code>disabled</code> email verification flows.</li>\n<li>Test Cases for <code>multifactor-authentication</code></li>\n</ul>\n<p>It is agreed that we are committed to delivering you a seamless experience in automation, but still, if you face any issue or need any enhancements, please report us <a href=\"https://github.com/LoginRadius/idx-auto-tester/issues\">here </a></p>\n<!--stackedit_data:\neyJoaXN0b3J5IjpbMjY2MTYyNjE4LDE5MDkzNjIxNjIsLTIyNT\ngwODM3OSwtNDI4ODY2Mjk2LDk1NTk3ODQ4NSwtMTU4Mjc5MDcy\nOF19\n-->\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 30, 2020","updated_date":null,"description":null,"title":"Roadmap of idx-auto-tester","tags":["Automation","idx","roadmap"],"pinned":null,"coverImage":{"childImageSharp":{"fluid":{"aspectRatio":1.7699115044247788,"src":"/static/b5c43b2bffb92542e899a8b9837bd4c5/ee604/roadmap_idx_auto_tester.png","srcSet":"/static/b5c43b2bffb92542e899a8b9837bd4c5/69585/roadmap_idx_auto_tester.png 200w,\n/static/b5c43b2bffb92542e899a8b9837bd4c5/497c6/roadmap_idx_auto_tester.png 400w,\n/static/b5c43b2bffb92542e899a8b9837bd4c5/ee604/roadmap_idx_auto_tester.png 800w,\n/static/b5c43b2bffb92542e899a8b9837bd4c5/f3583/roadmap_idx_auto_tester.png 1200w,\n/static/b5c43b2bffb92542e899a8b9837bd4c5/e4d72/roadmap_idx_auto_tester.png 1280w","sizes":"(max-width: 800px) 100vw, 800px"}}},"author":{"id":"Rakesh Pareek","github":"rkpareek","avatar":null}}}},{"node":{"excerpt":"Today we will learn about the progressive web app, a very interesting and trending topic in current times,  We will start with the basic…","fields":{"slug":"/engineering/build-pwa-using-vanilla-javascript/"},"html":"<p>Today we will learn about the progressive web app, a very interesting and trending topic in current times,  We will start with the basic steps first on how Progressive Web App works with vanilla js. Also, we’ll cover the concept of PWAS without using any of the frameworks, it's just a plain <code>vanillaJS</code>.</p>\n<h2 id=\"what-are-progressive-web-apps\" style=\"position:relative;\"><a href=\"#what-are-progressive-web-apps\" aria-label=\"what are progressive web apps 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 are Progressive Web Apps?</h2>\n<p>A Progressive Web app is an application which is built on top of <em>HTML</em>, <em>JS</em> and <em>CSS</em> with some extra features like <code>service worker</code> and <code>manifest.json</code> file. These extra features will give the ability to run the web application offline.</p>\n<p>Various big companies are moving towards the progressive web app instead of native apps, as it gives some much flexibility to end-users. In some websites you can find the + icon at the right side of the address bar, those are progressive web apps. </p>\n<h2 id=\"setup-your-base-app-for-pwa\" style=\"position:relative;\"><a href=\"#setup-your-base-app-for-pwa\" aria-label=\"setup your base app for pwa 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>Setup your base app for PWA</h2>\n<p>We will be using <code>npm</code> to start our project, so firstly create a root folder using this command <code>mkdir first-pwa-app</code> or another name of your choice then go to that directory by using this command <code>cd first-pwa-app</code>. Run <code>npm init</code></p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"sh\" data-index=\"0\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">npm init</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">package name: (first-pwa-app)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">version: (1.0.0)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">description: This is the first PWA example</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">entry point: (index.js): index.html</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk11\">test</span><span class=\"mtk1\"> command:</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">git repository:</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">keywords:</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">author: Mohammed Modi</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">license: (ISC)</span></span></code></pre>\n<p>Once you fill up those details your final output of the <code>package.json</code> file will be below</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;name&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;first-pwa-app&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">&quot;version&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;1.0.0&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">&quot;description&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;This is the first PWA example&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">&quot;main&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;index.html&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">&quot;scripts&quot;</span><span class=\"mtk1\">: {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk12\">&quot;test&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;echo </span><span class=\"mtk6\">\\&quot;</span><span class=\"mtk8\">Error: no test specified</span><span class=\"mtk6\">\\&quot;</span><span class=\"mtk8\"> && exit 1&quot;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  },</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">&quot;author&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;Mohammed Modi&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">&quot;license&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;ISC&quot;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">}</span></span></code></pre>\n<p>After that, we need to install the <code>serve</code> dependency to serve the application in localhost so install it using npm <code>npm i serve --save</code>. And then add a script in the <code>package.json</code> file.</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\">{</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk14\">...</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">&quot;scripts&quot;</span><span class=\"mtk1\">: {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk12\">&quot;test&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;echo </span><span class=\"mtk6\">\\&quot;</span><span class=\"mtk8\">Error: no test specified</span><span class=\"mtk6\">\\&quot;</span><span class=\"mtk8\"> && exit 1&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk12\">&quot;serve&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;serve .&quot;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  },</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk14\">...</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">}</span></span></code></pre>\n<p>So finally our application is ready to serve in localhost. Now let's add some <code>html</code> and <code>css</code></p>\n<h3 id=\"setting-up-the-javascript\" style=\"position:relative;\"><a href=\"#setting-up-the-javascript\" aria-label=\"setting up the javascript 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>Setting up the Javascript</h3>\n<p>Create a directory for the app and add js, css, and images subdirectories. It should look like this when you’re finished:</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"\" data-index=\"3\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">/first-pwa-app   # Project Folder</span>\n<span class=\"grvsc-line\">    /css     # Stylesheets</span>\n<span class=\"grvsc-line\">    /js      # Javascript</span>\n<span class=\"grvsc-line\">    /images  # Image files.</span>\n<span class=\"grvsc-line\">    package.json</span>\n<span class=\"grvsc-line\">    package-lock.json</span>\n<span class=\"grvsc-line\">    index.html</span>\n<span class=\"grvsc-line\">    manifest.json</span>\n<span class=\"grvsc-line\">    sw.js</span></code></pre>\n<p>You will understand the use of <code>manifest.json</code> and <code>sw.js</code> files once we move ahead in this tutorial.</p>\n<h3 id=\"add-some-code-for-app-interface\" style=\"position:relative;\"><a href=\"#add-some-code-for-app-interface\" aria-label=\"add some code for app interface 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>Add Some code for app interface</h3>\n<p>When writing the code for Progressive Web Application we need to keep in mind two requirements</p>\n<ol>\n<li>The landing page should have some content even if the javascript is not loaded</li>\n<li>The App should be responsive and can be properly interactive in any device.</li>\n</ol>\n<p>For this app, to handle the first requirement we will add the static text in the Html page and for the second requirement, we will use the viewport.</p>\n<p>So let's add this code inside the <code>index.html</code> file.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"html\" data-index=\"4\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">&lt;!</span><span class=\"mtk12\">DOCTYPE</span><span class=\"mtk1\"> </span><span class=\"mtk12\">html</span><span class=\"mtk1\">&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">html</span><span class=\"mtk1\"> </span><span class=\"mtk12\">lang</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;en&quot;</span><span class=\"mtk17\">&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">head</span><span class=\"mtk17\">&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">meta</span><span class=\"mtk1\"> </span><span class=\"mtk12\">charset</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;utf-8&quot;</span><span class=\"mtk1\"> </span><span class=\"mtk17\">/&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">title</span><span class=\"mtk17\">&gt;</span><span class=\"mtk1\">My First PWA</span><span class=\"mtk17\">&lt;/</span><span class=\"mtk4\">title</span><span class=\"mtk17\">&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">link</span><span class=\"mtk1\"> </span><span class=\"mtk12\">rel</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;stylesheet&quot;</span><span class=\"mtk1\"> </span><span class=\"mtk12\">href</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;css/style.css&quot;</span><span class=\"mtk1\"> </span><span class=\"mtk17\">/&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">meta</span><span class=\"mtk1\"> </span><span class=\"mtk12\">name</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;viewport&quot;</span><span class=\"mtk1\"> </span><span class=\"mtk12\">content</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;width=device-width, initial-scale=1.0&quot;</span><span class=\"mtk1\"> </span><span class=\"mtk17\">/&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk17\">&lt;/</span><span class=\"mtk4\">head</span><span class=\"mtk17\">&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">body</span><span class=\"mtk1\"> </span><span class=\"mtk12\">class</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;fullscreen&quot;</span><span class=\"mtk17\">&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">div</span><span class=\"mtk1\"> </span><span class=\"mtk12\">class</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;container&quot;</span><span class=\"mtk17\">&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">      </span><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">h1</span><span class=\"mtk1\"> </span><span class=\"mtk12\">class</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;title&quot;</span><span class=\"mtk17\">&gt;</span><span class=\"mtk1\">My First PWA!</span><span class=\"mtk17\">&lt;/</span><span class=\"mtk4\">h1</span><span class=\"mtk17\">&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk17\">&lt;/</span><span class=\"mtk4\">div</span><span class=\"mtk17\">&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk17\">&lt;/</span><span class=\"mtk4\">body</span><span class=\"mtk17\">&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk17\">&lt;/</span><span class=\"mtk4\">html</span><span class=\"mtk17\">&gt;</span></span></code></pre>\n<p>Next, we need to create a file <code>css/style.css</code> and paste this code inside this</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"css\" data-index=\"5\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk6\">body</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">font-family</span><span class=\"mtk1\">: </span><span class=\"mtk8\">sans-serif</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\">/* Make content area fill the entire browser window */</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk3\">/* Make content area fill the entire browser window */</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk6\">html</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk6\">.fullscreen</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">display</span><span class=\"mtk1\">: </span><span class=\"mtk8\">flex</span><span class=\"mtk1\">;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">height</span><span class=\"mtk1\">: </span><span class=\"mtk7\">100%</span><span class=\"mtk1\">;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">margin</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\">padding</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\">width</span><span class=\"mtk1\">: </span><span class=\"mtk7\">100%</span><span class=\"mtk1\">;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">}</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk3\">/* Center the content in the browser window */</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk6\">.container</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">margin</span><span class=\"mtk1\">: </span><span class=\"mtk8\">auto</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=\"mtk6\">.title</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">font-size</span><span class=\"mtk1\">: </span><span class=\"mtk7\">3rem</span><span class=\"mtk1\">;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">}</span></span></code></pre>\n<p>Once you add the code save all the files and run the script <code>npm run serve</code> which will start your application in <code>http://localhost:5000/</code></p>\n<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 768px; \"\n    >\n      <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 80.76923076923077%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAQCAYAAAAWGF8bAAAACXBIWXMAABYlAAAWJQFJUiTwAAABbElEQVQ4y8WUy2rCQBSG8yCikmiSjpPEBLPrQuiq9DWkbxB7odA2bZ/Jnasq8bITfAe3Kgpe8jdzYCRqK9FND/zMwMDHdzgzo7yHnwg/vvD6FiJM9k/PLwiaj2j+kiB4oPNG4x6sYoFbDq2McRSLKu0VXFCj0Qh+zYPnVmGaJhzHBuccnudB2W63yJrVakXAzncHls1Rv6nDtjg0TYOu6yiXy1DiOEbWbDYbAkbdLnSniuvbO3DGoKoqQUUIKEqup0oCe71eAjJRcy1qWdgZhkE5Av5ldwS0KnD9WjIQRmalUomipM1OWaZbFkABMa4YGcp2dy2nLWazGabTKebzORaLBa3L5XLPMIoi5PN5MpJ2R0AxRVHD4RCtVgvj8Rj9fh/tdhuTyYTO1uv1DlgoFGiqaejFLUtDCUznoqGcBcxybf4PmPmlHAxlD5jV7tAwl8vRkzuMIq/LOYaDwYB+F9/34boubNtOfhyH8gPOd+KYkgDmUgAAAABJRU5ErkJggg=='); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"First Build\"\n        title=\"First Build\"\n        src=\"/static/328993f8670367e5593427d2344d31d6/e5715/1.png\"\n        srcset=\"/static/328993f8670367e5593427d2344d31d6/a6d36/1.png 650w,\n/static/328993f8670367e5593427d2344d31d6/e5715/1.png 768w,\n/static/328993f8670367e5593427d2344d31d6/53e84/1.png 2074w\"\n        sizes=\"(max-width: 768px) 100vw, 768px\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        loading=\"lazy\"\n      />\n    </span></p>\n<h3 id=\"testing-the-app\" style=\"position:relative;\"><a href=\"#testing-the-app\" aria-label=\"testing the app 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>Testing the App</h3>\n<p>As we can see our application is running in the browser, let test it using the <a href=\"https://chrome.google.com/webstore/detail/lighthouse/blipmdconlkpinefehnmjammfjpmpbjk?hl=en\">LightHouse Extension</a> in Google Chrome browser. For the best result, I recommend testing in an <strong>incognito tab</strong> of google chrome.</p>\n<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 768px; \"\n    >\n      <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 58.15384615384615%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAYAAABiDJ37AAAACXBIWXMAABYlAAAWJQFJUiTwAAABuklEQVQoz5WS3Y4SQRCFeQtuRIb5H5jp+elp1sVkE5P1VTS+gOia1QtXfbfdGbiFfQ8gZIHjqVkhIeqKlVQq3Ul/dU51tb7efMfNtx+4/vwF4/FHjD9cHeV73l19usabt++QqAxpmh8yjhUc18do9BKXl69xcfEKLZwY9/MZhjrD6PwMxpTIsgz9fh++7yMIAnieyyYKrc1mg30+PPye6/W6Ad7d3qIfBggIsCwL3W4XnU6nqc+eW2i327BtG63dboenUhpJ1HWNTOcojUGhdZNRFKHX68Fx7KaWZfloWR7+LQ7AqoIKQ+h4gDJJoFWCkGcBiTJR2gD3MKmLxQLL5bKpq9XqSOFkMoEZGkScl03LDkF72B+B2+0W0+kUs9msyfl83gDlXqKq7qCoThcFdJ6jkErbotImWOZqOI7TLXOGWikUgwFiz4PrOOhRmfVLqSiUBkeWn/wUzjBPUxS0lVGdIjwkMOKH+ExRmHC2hz38F7AisOCDF7R7XuQ44x4mvoeEaiOqFaVxHJ9uuaorpFyboS5hqNLQnmID2UvHflT4X8CawISfIrbkoXyG67rcQQcuVTqux/sEPwHkdpQSGWEwNAAAAABJRU5ErkJggg=='); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"First Test\"\n        title=\"First Test\"\n        src=\"/static/7e9a07953900a7deec8b038fe9524e96/e5715/2.png\"\n        srcset=\"/static/7e9a07953900a7deec8b038fe9524e96/a6d36/2.png 650w,\n/static/7e9a07953900a7deec8b038fe9524e96/e5715/2.png 768w,\n/static/7e9a07953900a7deec8b038fe9524e96/d9ed5/2.png 2880w\"\n        sizes=\"(max-width: 768px) 100vw, 768px\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        loading=\"lazy\"\n      />\n    </span></p>\n<p>As you can see we have green signals for both of our above requirement:</p>\n<ol>\n<li>Has a <meta name=\"viewport\"> tag with width or initial-scale</li>\n<li>Contains some content when JavaScript is not available</li>\n</ol>\n<p>But still, there is lots of work to do, so let's start with the first feature of PWA's.</p>\n<h3 id=\"adding-a-web-app-manifest\" style=\"position:relative;\"><a href=\"#adding-a-web-app-manifest\" aria-label=\"adding a web app manifest permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Adding a Web App Manifest</h3>\n<p>Let's create a new file called <code>manifest.json</code> in the root of our application. To understand more about the manifest file check out [this doc]</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"json\" data-index=\"6\"><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;name&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;My First Progressive Web app&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">&quot;short_name&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;First PWA&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">&quot;lang&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;en-US&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">&quot;start_url&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;/index.html&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">&quot;display&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;standalone&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">&quot;background_color&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;white&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">&quot;theme_color&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;white&quot;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">}</span></span></code></pre>\n<p>Now update the <code>index.html</code> head tag by adding the manifest.json file as a link</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"html\" data-index=\"7\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">head</span><span class=\"mtk17\">&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  ...</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">link</span><span class=\"mtk1\"> </span><span class=\"mtk12\">rel</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;manifest&quot;</span><span class=\"mtk1\"> </span><span class=\"mtk12\">href</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;/manifest.json&quot;</span><span class=\"mtk1\"> </span><span class=\"mtk17\">/&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  ...</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk17\">&lt;/</span><span class=\"mtk4\">head</span><span class=\"mtk17\">&gt;</span></span></code></pre>\n<p>We should also declare the theme colour which should match with your manifest.json file as <code>meta tag</code>.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"html\" data-index=\"8\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">head</span><span class=\"mtk17\">&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  ...</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">meta</span><span class=\"mtk1\"> </span><span class=\"mtk12\">name</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;theme-color&quot;</span><span class=\"mtk1\"> </span><span class=\"mtk12\">content</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;white&quot;</span><span class=\"mtk1\"> </span><span class=\"mtk17\">/&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  ...</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk17\">&lt;/</span><span class=\"mtk4\">head</span><span class=\"mtk17\">&gt;</span></span></code></pre>\n<p>Once you run the lighthouse test again you can see we got green signals in some points like</p>\n<ol>\n<li>Sets a theme colour for the address bar.</li>\n</ol>\n<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 768px; \"\n    >\n      <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 58.00000000000001%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAYAAABiDJ37AAAACXBIWXMAABYlAAAWJQFJUiTwAAABuElEQVQoz5WTWW7bMBiEfYv0xdFqWdQuUopRB2jRB18m6A2cNjDykOVohuxnu72GDcPwMhnSC4o2bRMCAwEC+HFmfrL18PiMx6dnjEb3GN5+x+1vGg6/4e5uhJubr8jyEkUhjXIqSXP4foB+/xqDwQCfPn9BC29cP3/M0FMl+h97qKoKRZ4jigSCIEDQ7RLsI8sytLbbLbQ2m82rWq/XBjgejxGJEF0CHMeBbdu4bLdhWTba1MXFB7iui9Z+v8e/pA/TazKZoFQSVX0FqZSREAIu4Z7nmkO0cxNZb/zbOgObBhmjyTiCTBKoNIUIQ9gEaWeWZR2AJ5j+LhYLLJdLo9VqdXC4OwKnU9S9GoJQ17HhEaRdOYSdgIquz8DdbocpN81mM6P5fG6A+r9eDR0WaYJKSqiyRM3vVaVMr6dO3xeZHUpOsUxiRJ0OBKcqfA++e+jvD4f/HQodqiKnq8q4zNmjju0eY2uHKXs938PXYL86bOhQyQJ9Tvq6rqEyDsXzENCpc3SZ8JA3R24mDZIy4yvha2GHJV3GBHQY33TIyO8C6g4rdqSLVxoWxwh5bfRLCUO+mDA2kV8AAfuU5aBuRe0AAAAASUVORK5CYII='); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"Improving the Application\"\n        title=\"Improving the Application\"\n        src=\"/static/1a6d6e4f756d84ce7645f20d106d8b3b/e5715/3.png\"\n        srcset=\"/static/1a6d6e4f756d84ce7645f20d106d8b3b/a6d36/3.png 650w,\n/static/1a6d6e4f756d84ce7645f20d106d8b3b/e5715/3.png 768w,\n/static/1a6d6e4f756d84ce7645f20d106d8b3b/d9ed5/3.png 2880w\"\n        sizes=\"(max-width: 768px) 100vw, 768px\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        loading=\"lazy\"\n      />\n    </span></p>\n<h3 id=\"app-icons\" style=\"position:relative;\"><a href=\"#app-icons\" aria-label=\"app icons 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>App Icons</h3>\n<p>Still, we need to add more attributes to our <code>manifest.json</code> files like <strong>icons</strong> so let's add the icons inside the <code>images</code> folder, I have used to icons <code>pwa-icon-256.png</code> and <code>pwa-icon-256.png</code> for this demo you can find in this repo. You can use various sizes in it. And finally, add the <code>favicon.png</code> in the root of the project.</p>\n<p>So let's add the <code>icons</code> attribute after the <code>short-name</code></p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"json\" data-index=\"9\"><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;name&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;My First Progressive Web app&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">&quot;short_name&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;First PWA&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">&quot;icons&quot;</span><span class=\"mtk1\">: [</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">      </span><span class=\"mtk12\">&quot;src&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;.images/pwa-icon-256.png&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">      </span><span class=\"mtk12\">&quot;sizes&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;256x256&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">      </span><span class=\"mtk12\">&quot;type&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;image/png&quot;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    },</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">      </span><span class=\"mtk12\">&quot;src&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;.images/pwa-icon-512.png&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">      </span><span class=\"mtk12\">&quot;sizes&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;512x512&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">      </span><span class=\"mtk12\">&quot;type&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;image/png&quot;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    }</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  ],</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">&quot;lang&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;en-US&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">&quot;start_url&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;/index.html&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">&quot;display&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;standalone&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">&quot;background_color&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;white&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">&quot;theme_color&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;white&quot;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">}</span></span></code></pre>\n<p>And the index.html will head can will look like</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"html\" data-index=\"10\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">head</span><span class=\"mtk17\">&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  ...</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">link</span><span class=\"mtk1\"> </span><span class=\"mtk12\">rel</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;apple-touch-icon&quot;</span><span class=\"mtk1\"> </span><span class=\"mtk12\">href</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;images/pwa-icon-256.png&quot;</span><span class=\"mtk1\"> </span><span class=\"mtk17\">/&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  ...</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk17\">&lt;/</span><span class=\"mtk4\">head</span><span class=\"mtk17\">&gt;</span></span></code></pre>\n<p>You can also verify the <code>manifest.json</code> file by opening Chrome DevTools, in the <strong>Application Tab</strong>, the first tab in the sidebar <strong>manifest</strong></p>\n<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 768px; \"\n    >\n      <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 121.23076923076923%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAYCAYAAAD6S912AAAACXBIWXMAABYlAAAWJQFJUiTwAAADbUlEQVQ4y41VyU7jUBD0dwBCJCGb7diOncSOsxL2JSAkhu9h/gDOLDckOCCExIHhyAUuiE+q6erkRYbJYQ6t5+fY5arq6hdrd3cXSZKg2Wyi2+2i1WohTVMkcaz3G42GViz7lZUVFAoFLC0twfd89JsR0qSOlvwWRaE+Zx0fH2Nvbw+bm5sK0G63tTqdDmq1GuJ2iuFoHWm3h2KxqICrq6u65ln5wuQ6n0elUoE1Ho9xcvILp6enODjYx2AwUECy9TxPylf2tm3rS3zZFIFNFaSq1SqsjY0NlcgiSBiGqNfruvKBIBBp/b7eI8NyuYySFFcC5XM5/VBOVt6zxoeHyore0QMCRVGk17ZdRdK00R8O0ekPVH6SdtDpDdSCehjBdly4Yo3j1uD7ASw2hSxHo5H6SPMJSkDHseHYRXi+D78eoibyWX4QSNUz15M9P2Dt7OyIdwc4OjrC+vq6+mUA6ZsnXw1Fbk46nM/nZg2Y7CdStWRfKpVgbW9vK0OyIwi9MpIdx1GfjHeOyKuHDUSNJuIkRaMVoxknqIjX/JA2hZExOSQzUwQlILNHULJlhQJGwGyHTYw0Nnv7+xjSdMldr9dDc9oYw5AgZM1rExdKnQeoDCl1JN5xpXSCZj1UVrIPxHh6xD0Db0D+YchgE6QnGeTa+MHQjJvjugLkossPih3Kdp5kslpbW8O+SN/a2lL5WUAjhcV9W3JYKldQmMrOjqICGqlsDrPIgFOekUyZrrAjIPdxpqtzm0JWBOLKCJEtZ5ldJyM2gLGhb9UfQNmZ/sZwOFxTMLKkZBMjAjK0PFXIjkyZvVbSnttlDTZBKJPRyBZzqF0W0IqEOjc9BDgt+dn1dD89hQhssRmUrN0VkGhaxkOyCmVGJ132ZH49HUfON2fZkxl25X6pVFZQi2C+/BhlwLI5JECSdlVmS8YtEPaBHBQ8EAgay/1EPC+LfwrIDhuJ2dHT2AggZ9jTU8ZTBZeXl3h5ecHj4yNeX//g99mZesfGqWSeMIzJXEDxjw+6sjrTifn6+sL19TXu7+/x9PSkwAsLC7PmfAPMgmZPG7Kk8YzO+/s7rq6ucHt7i4eHB9zd3emf1lyG8wDNQcARZIM+Pz9xfn6Om5sbBSXDxcXF/wek0ebfjvvn52d8fHzg7e1NwS8uLrC8vDwD/As3uxARKwst4AAAAABJRU5ErkJggg=='); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"Application Manifest\"\n        title=\"Application Manifest\"\n        src=\"/static/1fa7bbfafde2b8b0c2a364cca9c89f36/e5715/5.png\"\n        srcset=\"/static/1fa7bbfafde2b8b0c2a364cca9c89f36/a6d36/5.png 650w,\n/static/1fa7bbfafde2b8b0c2a364cca9c89f36/e5715/5.png 768w,\n/static/1fa7bbfafde2b8b0c2a364cca9c89f36/fbf76/5.png 1252w\"\n        sizes=\"(max-width: 768px) 100vw, 768px\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        loading=\"lazy\"\n      />\n    </span></p>\n<p>After running the test again, we can see all the <code>manifest.json</code> related issues are solved, The remaining issues can be resolved by adding the service worker.</p>\n<h3 id=\"adding-service-worker\" style=\"position:relative;\"><a href=\"#adding-service-worker\" aria-label=\"adding service worker permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Adding Service Worker</h3>\n<p>The next requirement of our app will be the service worker. The service worker is a script that runs in the background without any user interaction.</p>\n<p>The task of service worker will be to download and cache our content and then serve it when the user is offline. To understand more on service workers you can check this doc <a href=\"https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API\">from mozilla</a>.</p>\n<p>To integrate service workers we need to create a file called <code>sw.js</code> in the root of our project.</p>\n<blockquote>\n<p><strong>Note</strong>: Service worker will only have the access to the files of the <strong>current and sub-directories</strong> hence we need to place it in the root of our project</p>\n</blockquote>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"javascript\" data-index=\"11\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk4\">let</span><span class=\"mtk1\"> </span><span class=\"mtk12\">cacheName</span><span class=\"mtk1\"> = </span><span class=\"mtk8\">&quot;my-first-pwa&quot;</span><span class=\"mtk1\">;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">let</span><span class=\"mtk1\"> </span><span class=\"mtk12\">filesToCache</span><span class=\"mtk1\"> = [</span><span class=\"mtk8\">&quot;/&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk8\">&quot;/index.html&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk8\">&quot;/css/style.css&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk8\">&quot;/js/main.js&quot;</span><span class=\"mtk1\">];</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk3\">/* Start the service worker and cache all of the app&#39;s content */</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk12\">self</span><span class=\"mtk1\">.</span><span class=\"mtk11\">addEventListener</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;install&quot;</span><span class=\"mtk1\">, (</span><span class=\"mtk12\">e</span><span class=\"mtk1\">) </span><span class=\"mtk4\">=&gt;</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">e</span><span class=\"mtk1\">.</span><span class=\"mtk11\">waitUntil</span><span class=\"mtk1\">(</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk12\">caches</span><span class=\"mtk1\">.</span><span class=\"mtk11\">open</span><span class=\"mtk1\">(</span><span class=\"mtk12\">cacheName</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\">cache</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\">cache</span><span class=\"mtk1\">.</span><span class=\"mtk11\">addAll</span><span class=\"mtk1\">(</span><span class=\"mtk12\">filesToCache</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>\n<span class=\"grvsc-line\"><span class=\"mtk3\">/* Serve cached content when offline */</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk12\">self</span><span class=\"mtk1\">.</span><span class=\"mtk11\">addEventListener</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;fetch&quot;</span><span class=\"mtk1\">, (</span><span class=\"mtk12\">e</span><span class=\"mtk1\">) </span><span class=\"mtk4\">=&gt;</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk12\">e</span><span class=\"mtk1\">.</span><span class=\"mtk11\">respondWith</span><span class=\"mtk1\">(</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk12\">caches</span><span class=\"mtk1\">.</span><span class=\"mtk11\">match</span><span class=\"mtk1\">(</span><span class=\"mtk12\">e</span><span class=\"mtk1\">.</span><span class=\"mtk12\">request</span><span class=\"mtk1\">).</span><span class=\"mtk11\">then</span><span class=\"mtk1\">((</span><span class=\"mtk12\">response</span><span class=\"mtk1\">) </span><span class=\"mtk4\">=&gt;</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">      </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> </span><span class=\"mtk12\">response</span><span class=\"mtk1\"> || </span><span class=\"mtk11\">fetch</span><span class=\"mtk1\">(</span><span class=\"mtk12\">e</span><span class=\"mtk1\">.</span><span class=\"mtk12\">request</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>The first 2 variables <code>cacheName</code> and <code>filesToCache</code> are used to create an offline cache in the browser. <code>cacheName</code> is used to create a cache of specific name and <code>filesToCache</code> will be the list of files that we need to cache, <code>/</code> will store the root files that is <code>index.html</code> even if the user does not specify the file name in the URL and then all other files specified in the array.</p>\n<blockquote>\n<p><strong>Note</strong>: Here I have used the <code>filesToCache</code> array as a list of static files just to demonstrate the purpose of PWA, it will stop working in production if even one file fails to load.</p>\n</blockquote>\n<p>Finally, we will load our service worker, for that create <code>js/main.js</code> file and copy the below code.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"js\" data-index=\"12\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk12\">window</span><span class=\"mtk1\">.</span><span class=\"mtk11\">onload</span><span class=\"mtk1\"> = () </span><span class=\"mtk4\">=&gt;</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk8\">&quot;use strict&quot;</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=\"mtk8\">&quot;serviceWorker&quot;</span><span class=\"mtk1\"> </span><span class=\"mtk4\">in</span><span class=\"mtk1\"> </span><span class=\"mtk12\">navigator</span><span class=\"mtk1\">) {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk12\">navigator</span><span class=\"mtk1\">.</span><span class=\"mtk12\">serviceWorker</span><span class=\"mtk1\">.</span><span class=\"mtk11\">register</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;./sw.js&quot;</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  }</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">};</span></span></code></pre>\n<p>And add this script in the <code>index.html</code> file.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"html\" data-index=\"13\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">...</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">script</span><span class=\"mtk1\"> </span><span class=\"mtk12\">src</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;js/main.js&quot;</span><span class=\"mtk17\">&gt;&lt;/</span><span class=\"mtk4\">script</span><span class=\"mtk17\">&gt;</span></span></code></pre>\n<p>So the final version of our <code>index.html</code> file will look like:</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"html\" data-index=\"14\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">&lt;!</span><span class=\"mtk12\">DOCTYPE</span><span class=\"mtk1\"> </span><span class=\"mtk12\">html</span><span class=\"mtk1\">&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">html</span><span class=\"mtk1\"> </span><span class=\"mtk12\">lang</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;en&quot;</span><span class=\"mtk17\">&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">head</span><span class=\"mtk17\">&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">meta</span><span class=\"mtk1\"> </span><span class=\"mtk12\">charset</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;utf-8&quot;</span><span class=\"mtk1\"> </span><span class=\"mtk17\">/&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">title</span><span class=\"mtk17\">&gt;</span><span class=\"mtk1\">Hello World</span><span class=\"mtk17\">&lt;/</span><span class=\"mtk4\">title</span><span class=\"mtk17\">&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">link</span><span class=\"mtk1\"> </span><span class=\"mtk12\">rel</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;apple-touch-icon&quot;</span><span class=\"mtk1\"> </span><span class=\"mtk12\">href</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;images/pwa-icon-256.png&quot;</span><span class=\"mtk1\"> </span><span class=\"mtk17\">/&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">link</span><span class=\"mtk1\"> </span><span class=\"mtk12\">rel</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;stylesheet&quot;</span><span class=\"mtk1\"> </span><span class=\"mtk12\">href</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;css/style.css&quot;</span><span class=\"mtk1\"> </span><span class=\"mtk17\">/&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">link</span><span class=\"mtk1\"> </span><span class=\"mtk12\">rel</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;manifest&quot;</span><span class=\"mtk1\"> </span><span class=\"mtk12\">href</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;/manifest.json&quot;</span><span class=\"mtk1\"> </span><span class=\"mtk17\">/&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">meta</span><span class=\"mtk1\"> </span><span class=\"mtk12\">name</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;viewport&quot;</span><span class=\"mtk1\"> </span><span class=\"mtk12\">content</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;width=device-width, initial-scale=1.0&quot;</span><span class=\"mtk1\"> </span><span class=\"mtk17\">/&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">meta</span><span class=\"mtk1\"> </span><span class=\"mtk12\">name</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;theme-color&quot;</span><span class=\"mtk1\"> </span><span class=\"mtk12\">content</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;white&quot;</span><span class=\"mtk1\"> </span><span class=\"mtk17\">/&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk17\">&lt;/</span><span class=\"mtk4\">head</span><span class=\"mtk17\">&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">body</span><span class=\"mtk1\"> </span><span class=\"mtk12\">class</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;fullscreen&quot;</span><span class=\"mtk17\">&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">div</span><span class=\"mtk1\"> </span><span class=\"mtk12\">class</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;container&quot;</span><span class=\"mtk17\">&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">      </span><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">h1</span><span class=\"mtk1\"> </span><span class=\"mtk12\">class</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;title&quot;</span><span class=\"mtk17\">&gt;</span><span class=\"mtk1\">Hello World!</span><span class=\"mtk17\">&lt;/</span><span class=\"mtk4\">h1</span><span class=\"mtk17\">&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk17\">&lt;/</span><span class=\"mtk4\">div</span><span class=\"mtk17\">&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk17\">&lt;</span><span class=\"mtk4\">script</span><span class=\"mtk1\"> </span><span class=\"mtk12\">src</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;js/main.js&quot;</span><span class=\"mtk17\">&gt;&lt;/</span><span class=\"mtk4\">script</span><span class=\"mtk17\">&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk17\">&lt;/</span><span class=\"mtk4\">body</span><span class=\"mtk17\">&gt;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk17\">&lt;/</span><span class=\"mtk4\">html</span><span class=\"mtk17\">&gt;</span></span></code></pre>\n<p>Now our application is made as fully PWA supported, you can verify it by running the lighthouse test.</p>\n<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 768px; \"\n    >\n      <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 58.769230769230774%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAYAAABiDJ37AAAACXBIWXMAABYlAAAWJQFJUiTwAAAB4ElEQVQoz42SXWsaQRSG/RFNum4I3Zn9/nI/dFeTDYUYKJQW8ldCb1ITelXb/kPBCy9T9cY7Lbjq2zOz1W5Kiz3wMMxcPLxnzmkMv3zD5+FXDImHx0+4//hQcT/AYPCIu7sP6GRdhGGEOE7RihJERJy05d22Xbiuj37/BtfXfTRwpH6slnj/9g3yTht5niFKIvihB8s24XgOLMeEaZmwTMKy0NhsNqhTlhXr9VoKvz89IUsTqM0mVF2FwhScnL+AHdtQeROn5yf09hKKqkBRFDR2ux3+xna7lcL5fI4sy6CeqeAeg8EN+I6Pd7e36HZ70DUD3OHgFgNnvGpZCP6s/dtsNkNRFPRXNqyI2mqZCDsB3NhBQKcdu2CBDo2/gqaxKqGosiyxXC6xWq0k4i6F0xkurgrE1HbezdHO2giiAIxr4AJdg64zMErHOf8tXCwWGI1GmEwmGI/HUl4JpyS8pCFYCHwfvsDz4RomPF2X2CRijFXCoy2T8PLmNUKarqEblKxKIk6NJIK97FnCfw1FtNyjhFESI01T2r3qdF23Ev0SHhIeE05pKFc0lDRJpEy0bNLOsZqozjNhvQ4JSdgrLhBGLbk+AsMwaKLaoc06/yUUQ/HDQCYUhGEo16iedC/8CYFTXfCHL/ezAAAAAElFTkSuQmCC'); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"Full PWA Supported\"\n        title=\"Full PWA Supported\"\n        src=\"/static/909cf0352662de4275cd17be5d1e96c0/e5715/6.png\"\n        srcset=\"/static/909cf0352662de4275cd17be5d1e96c0/a6d36/6.png 650w,\n/static/909cf0352662de4275cd17be5d1e96c0/e5715/6.png 768w,\n/static/909cf0352662de4275cd17be5d1e96c0/34e83/6.png 2852w\"\n        sizes=\"(max-width: 768px) 100vw, 768px\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        loading=\"lazy\"\n      />\n    </span></p>\n<h4 id=\"finishing-up\" style=\"position:relative;\"><a href=\"#finishing-up\" aria-label=\"finishing up 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>Finishing Up</h4>\n<p>We are done with the code, now the last thing remaining in to host it in any of the <code>https</code> domain. As the PWA will be required to run in <a href=\"/everything-you-want-to-know-about-authorization-headers/\">the secure domain</a>.</p>\n<p>You can get the full source code of this example in this <a href=\"https://github.com/LoginRadius/engineering-blog-samples/tree/master/ProgressiveWebApp/MyFirstPWA\">Github repo</a></p>\n<p>I hope you enjoyed the progressive web apps using vanilla js tutorial and found it useful. Please let me know what you think in the comments below.</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 .mtk11 { color: #DCDCAA; }\n  .dark-default-dark .mtk12 { color: #9CDCFE; }\n  .dark-default-dark .mtk8 { color: #CE9178; }\n  .dark-default-dark .mtk6 { color: #D7BA7D; }\n  .dark-default-dark .mtk14 { color: #F44747; }\n  .dark-default-dark .mtk17 { color: #808080; }\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</style>","frontmatter":{"date":"June 26, 2020","updated_date":null,"description":"A simple step-by-step tutorial, all done with pure JavaScript, to set up a simple PWA that can be accessed offline using a web app manifest and a service worker.","title":"How to Build a PWA in Vanilla JS","tags":["PWA","JavaScript"],"pinned":null,"coverImage":{"childImageSharp":{"fluid":{"aspectRatio":1.7699115044247788,"src":"/static/1c496ce8fd476e70f4dbf1a97f08619a/ee604/cover.png","srcSet":"/static/1c496ce8fd476e70f4dbf1a97f08619a/69585/cover.png 200w,\n/static/1c496ce8fd476e70f4dbf1a97f08619a/497c6/cover.png 400w,\n/static/1c496ce8fd476e70f4dbf1a97f08619a/ee604/cover.png 800w,\n/static/1c496ce8fd476e70f4dbf1a97f08619a/f3583/cover.png 1200w,\n/static/1c496ce8fd476e70f4dbf1a97f08619a/e4d72/cover.png 1280w","sizes":"(max-width: 800px) 100vw, 800px"}}},"author":{"id":"Mohammed Modi","github":"mohammed786","avatar":null}}}},{"node":{"excerpt":"In this blog, we’ll be implementing authentication with password hashing in a Node.js web application. For this, we’ll be using crypto, a…","fields":{"slug":"/engineering/password-hashing-with-nodejs/"},"html":"<p>In this blog, we’ll be implementing authentication with password hashing in a Node.js web application. For this, we’ll be using <strong>crypto</strong>, a package password hashing for Node.js.</p>\n<p>The Crypto module for Node JS helps developers to hash user passwords.</p>\n<p>Pre-requisites: </p>\n<ul>\n<li>Basic knowledge of HTML/JavaScript</li>\n<li>Node js should be installed in your system.</li>\n<li>express module for creating the server.</li>\n<li>mongoose module for MongoDB connection and queries.</li>\n<li>Crypto module for hashing.</li>\n<li>body-parser for parsing JSON data</li>\n</ul>\n<p>Step 1. First, create a directory structure as below :</p>\n<p><code>hashApp</code></strong></p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"\" data-index=\"0\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">--model</span>\n<span class=\"grvsc-line\">----user.js</span>\n<span class=\"grvsc-line\">--route</span>\n<span class=\"grvsc-line\">----user.js</span>\n<span class=\"grvsc-line\">--server.js</span></code></pre>\n<p>  Step 2. Create <strong>model/user.js</strong> file and add the following code :</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"js\" data-index=\"1\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk3\">// Importing modules </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">const</span><span class=\"mtk1\"> </span><span class=\"mtk12\">mongoose</span><span class=\"mtk1\"> = </span><span class=\"mtk11\">require</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&#39;mongoose&#39;</span><span class=\"mtk1\">); </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">var</span><span class=\"mtk1\"> </span><span class=\"mtk12\">crypto</span><span class=\"mtk1\"> = </span><span class=\"mtk11\">require</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&#39;crypto&#39;</span><span class=\"mtk1\">); </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk3\">// Creating user schema </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">const</span><span class=\"mtk1\"> </span><span class=\"mtk12\">UserSchema</span><span class=\"mtk1\"> = </span><span class=\"mtk12\">mongoose</span><span class=\"mtk1\">.</span><span class=\"mtk11\">Schema</span><span class=\"mtk1\">({ </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk12\">name :</span><span class=\"mtk1\"> { </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk12\">type :</span><span class=\"mtk1\"> </span><span class=\"mtk10\">String</span><span class=\"mtk1\">, </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk12\">required :</span><span class=\"mtk1\"> </span><span class=\"mtk4\">true</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    }, </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk12\">email :</span><span class=\"mtk1\"> { </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk12\">type :</span><span class=\"mtk1\"> </span><span class=\"mtk10\">String</span><span class=\"mtk1\">, </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk12\">required :</span><span class=\"mtk1\"> </span><span class=\"mtk4\">true</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    }, </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk12\">hash :</span><span class=\"mtk1\"> </span><span class=\"mtk10\">String</span><span class=\"mtk1\">, </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk12\">salt :</span><span class=\"mtk1\"> </span><span class=\"mtk10\">String</span><span class=\"mtk1\"> </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">}); </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk3\">// Method to set salt and hash the password for a user </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk12\">UserSchema</span><span class=\"mtk1\">.</span><span class=\"mtk12\">methods</span><span class=\"mtk1\">.</span><span class=\"mtk11\">setPassword</span><span class=\"mtk1\"> = </span><span class=\"mtk4\">function</span><span class=\"mtk1\">(</span><span class=\"mtk12\">password</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=\"mtk3\">// Creating a unique salt for a particular user </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk4\">this</span><span class=\"mtk1\">.</span><span class=\"mtk12\">salt</span><span class=\"mtk1\"> = </span><span class=\"mtk12\">crypto</span><span class=\"mtk1\">.</span><span class=\"mtk11\">randomBytes</span><span class=\"mtk1\">(</span><span class=\"mtk7\">16</span><span class=\"mtk1\">).</span><span class=\"mtk11\">toString</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&#39;hex&#39;</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=\"mtk3\">// Hashing user&#39;s salt and password with 1000 iterations, </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">     </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk4\">this</span><span class=\"mtk1\">.</span><span class=\"mtk12\">hash</span><span class=\"mtk1\"> = </span><span class=\"mtk12\">crypto</span><span class=\"mtk1\">.</span><span class=\"mtk11\">pbkdf2Sync</span><span class=\"mtk1\">(</span><span class=\"mtk12\">password</span><span class=\"mtk1\">, </span><span class=\"mtk4\">this</span><span class=\"mtk1\">.</span><span class=\"mtk12\">salt</span><span class=\"mtk1\">,  </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk7\">1000</span><span class=\"mtk1\">, </span><span class=\"mtk7\">64</span><span class=\"mtk1\">, </span><span class=\"mtk8\">`sha512`</span><span class=\"mtk1\">).</span><span class=\"mtk11\">toString</span><span class=\"mtk1\">(</span><span class=\"mtk8\">`hex`</span><span class=\"mtk1\">); </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">}; </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk3\">// Method to check the entered password is correct or not </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk12\">UserSchema</span><span class=\"mtk1\">.</span><span class=\"mtk12\">methods</span><span class=\"mtk1\">.</span><span class=\"mtk11\">validPassword</span><span class=\"mtk1\"> = </span><span class=\"mtk4\">function</span><span class=\"mtk1\">(</span><span class=\"mtk12\">password</span><span class=\"mtk1\">) { </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk4\">var</span><span class=\"mtk1\"> </span><span class=\"mtk12\">hash</span><span class=\"mtk1\"> = </span><span class=\"mtk12\">crypto</span><span class=\"mtk1\">.</span><span class=\"mtk11\">pbkdf2Sync</span><span class=\"mtk1\">(</span><span class=\"mtk12\">password</span><span class=\"mtk1\">,  </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk4\">this</span><span class=\"mtk1\">.</span><span class=\"mtk12\">salt</span><span class=\"mtk1\">, </span><span class=\"mtk7\">1000</span><span class=\"mtk1\">, </span><span class=\"mtk7\">64</span><span class=\"mtk1\">, </span><span class=\"mtk8\">`sha512`</span><span class=\"mtk1\">).</span><span class=\"mtk11\">toString</span><span class=\"mtk1\">(</span><span class=\"mtk8\">`hex`</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\">this</span><span class=\"mtk1\">.</span><span class=\"mtk12\">hash</span><span class=\"mtk1\"> === </span><span class=\"mtk12\">hash</span><span class=\"mtk1\">; </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">}; </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk3\">// Exporting module to allow it to be imported in other files </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">const</span><span class=\"mtk1\"> </span><span class=\"mtk12\">User</span><span class=\"mtk1\"> = </span><span class=\"mtk10\">module</span><span class=\"mtk1\">.</span><span class=\"mtk10\">exports</span><span class=\"mtk1\"> = </span><span class=\"mtk12\">mongoose</span><span class=\"mtk1\">.</span><span class=\"mtk11\">model</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&#39;User&#39;</span><span class=\"mtk1\">, </span><span class=\"mtk12\">UserSchema</span><span class=\"mtk1\">); </span></span></code></pre>\n<p>Step 3. Create <strong>route/user.js</strong> file and add the following code:</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=\"mtk3\">// Importing modules </span></span>\n<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\">router</span><span class=\"mtk1\"> = </span><span class=\"mtk12\">express</span><span class=\"mtk1\">.</span><span class=\"mtk11\">Router</span><span class=\"mtk1\">(); </span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk3\">// Importing User Schema </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">const</span><span class=\"mtk1\"> </span><span class=\"mtk12\">User</span><span class=\"mtk1\"> = </span><span class=\"mtk11\">require</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&#39;../model/user&#39;</span><span class=\"mtk1\">); </span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk3\">// User login api </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk12\">router</span><span class=\"mtk1\">.</span><span class=\"mtk11\">post</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&#39;/login&#39;</span><span class=\"mtk1\">, (</span><span class=\"mtk12\">req</span><span class=\"mtk1\">, </span><span class=\"mtk12\">res</span><span class=\"mtk1\">) </span><span class=\"mtk4\">=&gt;</span><span class=\"mtk1\"> { </span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk3\">// Find user with requested email </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk12\">User</span><span class=\"mtk1\">.</span><span class=\"mtk11\">findOne</span><span class=\"mtk1\">({ </span><span class=\"mtk12\">email :</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\">email</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\">user</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\">user</span><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=\"mtk15\">return</span><span class=\"mtk1\"> </span><span class=\"mtk12\">res</span><span class=\"mtk1\">.</span><span class=\"mtk11\">status</span><span class=\"mtk1\">(</span><span class=\"mtk7\">400</span><span class=\"mtk1\">).</span><span class=\"mtk11\">send</span><span class=\"mtk1\">({ </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                </span><span class=\"mtk12\">message :</span><span class=\"mtk1\"> </span><span class=\"mtk8\">&quot;User not found.&quot;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            }); </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        } </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">else</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\">user</span><span class=\"mtk1\">.</span><span class=\"mtk11\">validPassword</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\">password</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\">status</span><span class=\"mtk1\">(</span><span class=\"mtk7\">201</span><span class=\"mtk1\">).</span><span class=\"mtk11\">send</span><span class=\"mtk1\">({ </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                    </span><span class=\"mtk12\">message :</span><span class=\"mtk1\"> </span><span class=\"mtk8\">&quot;User Logged In&quot;</span><span class=\"mtk1\">, </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                }) </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            } </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk15\">else</span><span class=\"mtk1\"> { </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> </span><span class=\"mtk12\">res</span><span class=\"mtk1\">.</span><span class=\"mtk11\">status</span><span class=\"mtk1\">(</span><span class=\"mtk7\">400</span><span class=\"mtk1\">).</span><span class=\"mtk11\">send</span><span class=\"mtk1\">({ </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                    </span><span class=\"mtk12\">message :</span><span class=\"mtk1\"> </span><span class=\"mtk8\">&quot;Wrong Password&quot;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                }); </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            } </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        } </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    }); </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">}); </span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk3\">// User signup api </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk12\">router</span><span class=\"mtk1\">.</span><span class=\"mtk11\">post</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&#39;/signup&#39;</span><span class=\"mtk1\">, (</span><span class=\"mtk12\">req</span><span class=\"mtk1\">, </span><span class=\"mtk12\">res</span><span class=\"mtk1\">, </span><span class=\"mtk12\">next</span><span class=\"mtk1\">) </span><span class=\"mtk4\">=&gt;</span><span class=\"mtk1\"> { </span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk3\">// Creating empty user object </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk4\">let</span><span class=\"mtk1\"> </span><span class=\"mtk12\">newUser</span><span class=\"mtk1\"> = </span><span class=\"mtk4\">new</span><span class=\"mtk1\"> </span><span class=\"mtk10\">User</span><span class=\"mtk1\">(); </span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk3\">// Initialize newUser object with request data </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk12\">newUser</span><span class=\"mtk1\">.</span><span class=\"mtk12\">name</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\">name</span><span class=\"mtk1\">, </span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk12\">newUser</span><span class=\"mtk1\">.</span><span class=\"mtk12\">email</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\">email</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk12\">newUser</span><span class=\"mtk1\">.</span><span class=\"mtk12\">password</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\">password</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                    </span><span class=\"mtk3\">// Call setPassword function to hash password </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                    </span><span class=\"mtk12\">newUser</span><span class=\"mtk1\">.</span><span class=\"mtk11\">setPassword</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\">password</span><span class=\"mtk1\">); </span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk3\">// Save newUser object to database </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk12\">newUser</span><span class=\"mtk1\">.</span><span class=\"mtk11\">save</span><span class=\"mtk1\">((</span><span class=\"mtk12\">err</span><span class=\"mtk1\">, </span><span class=\"mtk12\">User</span><span class=\"mtk1\">) </span><span class=\"mtk4\">=&gt;</span><span class=\"mtk1\"> { </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"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=\"mtk15\">return</span><span class=\"mtk1\"> </span><span class=\"mtk12\">res</span><span class=\"mtk1\">.</span><span class=\"mtk11\">status</span><span class=\"mtk1\">(</span><span class=\"mtk7\">400</span><span class=\"mtk1\">).</span><span class=\"mtk11\">send</span><span class=\"mtk1\">({ </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                </span><span class=\"mtk12\">message :</span><span class=\"mtk1\"> </span><span class=\"mtk8\">&quot;Failed to add user.&quot;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            }); </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        } </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">else</span><span class=\"mtk1\"> { </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> </span><span class=\"mtk12\">res</span><span class=\"mtk1\">.</span><span class=\"mtk11\">status</span><span class=\"mtk1\">(</span><span class=\"mtk7\">201</span><span class=\"mtk1\">).</span><span class=\"mtk11\">send</span><span class=\"mtk1\">({ </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                </span><span class=\"mtk12\">message :</span><span class=\"mtk1\"> </span><span class=\"mtk8\">&quot;User added successfully.&quot;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            }); </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        } </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    }); </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">}); </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk3\">// Export module to allow it to be imported in other files </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk10\">module</span><span class=\"mtk1\">.</span><span class=\"mtk10\">exports</span><span class=\"mtk1\"> = </span><span class=\"mtk12\">router</span><span class=\"mtk1\">; </span></span></code></pre>\n<p>Step 4. Create <strong>server.js</strong> file :</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"js\" data-index=\"3\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk3\">// Importing modules</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">var</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\">var</span><span class=\"mtk1\"> </span><span class=\"mtk12\">mongoose</span><span class=\"mtk1\"> = </span><span class=\"mtk11\">require</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&#39;mongoose&#39;</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">var</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=\"mtk1\">  </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk3\">// Initialize express app</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">var</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 class=\"mtk1\">  </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk3\">// Mongodb connection url</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">var</span><span class=\"mtk1\"> </span><span class=\"mtk12\">MONGODB_URI</span><span class=\"mtk1\"> = </span><span class=\"mtk8\">&quot;mongodb://localhost:27017/hashAppDb&quot;</span><span class=\"mtk1\">;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk3\">// Connect to MongoDB</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk12\">mongoose</span><span class=\"mtk1\">.</span><span class=\"mtk11\">connect</span><span class=\"mtk1\">(</span><span class=\"mtk12\">MONGODB_URI</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk12\">mongoose</span><span class=\"mtk1\">.</span><span class=\"mtk12\">connection</span><span class=\"mtk1\">.</span><span class=\"mtk11\">on</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&#39;connected&#39;</span><span class=\"mtk1\">, () </span><span class=\"mtk4\">=&gt;</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk10\">console</span><span class=\"mtk1\">.</span><span class=\"mtk11\">log</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&#39;Connected to MongoDB @ 27017&#39;</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">});</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk3\">// Using bodyparser to parse json data</span></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 class=\"mtk1\">  </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk3\">// Importing routes</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">const</span><span class=\"mtk1\"> </span><span class=\"mtk12\">user</span><span class=\"mtk1\"> = </span><span class=\"mtk11\">require</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&#39;./route/user&#39;</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk3\">// Use user route when url matches /api/user/</span></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=\"mtk8\">&#39;/api/user&#39;</span><span class=\"mtk1\">, </span><span class=\"mtk12\">user</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk3\">// Creating server</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">const</span><span class=\"mtk1\"> </span><span class=\"mtk12\">port</span><span class=\"mtk1\"> = </span><span class=\"mtk7\">3000</span><span class=\"mtk1\">;</span></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=\"mtk12\">port</span><span class=\"mtk1\">, () </span><span class=\"mtk4\">=&gt;</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk10\">console</span><span class=\"mtk1\">.</span><span class=\"mtk11\">log</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;Server r</span><span class=\"mtk14\">u</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk12\">nning</span><span class=\"mtk1\"> </span><span class=\"mtk12\">at</span><span class=\"mtk1\"> </span><span class=\"mtk12\">port</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot; + port)</span><span class=\"mtk14\">;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">});</span></span></code></pre>\n<p>Step 5. Run server.js file using command </p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"\" data-index=\"4\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">node server.js</span></code></pre>\n<p>Step 6. Open Postman and create a post request to <strong>localhost:3000/api/user/signup</strong> with following body parameter: </p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"\" data-index=\"5\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">{</span>\n<span class=\"grvsc-line\">&quot;name&quot; : &quot;test&quot;.</span>\n<span class=\"grvsc-line\">&quot;email&quot; : &quot;test@test.com&quot;,</span>\n<span class=\"grvsc-line\">&quot;password&quot; : &quot;test1234&quot;</span>\n<span class=\"grvsc-line\">}</span></code></pre>\n<p>Run the request and you will get  a success response:</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"\" data-index=\"6\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">{</span>\n<span class=\"grvsc-line\">&quot;message&quot; : &quot;user added sucessfully&quot;</span>\n<span class=\"grvsc-line\">}</span></code></pre>\n<p>User data is stored in the database as below:</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"\" data-index=\"7\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">    &quot;_id&quot;: {</span>\n<span class=\"grvsc-line\">        &quot;$oid&quot;: &quot;5ab71ef2afb6db0148052f6f&quot;</span>\n<span class=\"grvsc-line\">    },</span>\n<span class=\"grvsc-line\">    &quot;name&quot;: &quot;test&quot;,</span>\n<span class=\"grvsc-line\">    &quot;email&quot;: &quot;test@test.com&quot;,</span>\n<span class=\"grvsc-line\">    &quot;salt&quot;: &quot;ddee18ef6a6804fbb919b25f790005e3&quot;,</span>\n<span class=\"grvsc-line\">    &quot;hash&quot;: &quot;bbf13ae4db87d475ca0ee5f97e397248a23509fc10c82f1e3cf110</span>\n<span class=\"grvsc-line\">     b352c3ca6cc057955ace9d541573929cd7a74a280a02e8cb549136b43df7704caaa555b38a&quot;,</span>\n<span class=\"grvsc-line\">    &quot;__v&quot;: 0</span>\n<span class=\"grvsc-line\">}</span></code></pre>\n<p>If we have sensitive data or information that you need to be protected, ensuring it is secured correctly is important. With the above process, we can now successfully store our hashed password into our database with a bit of additional security.</p>\n<p>You can check the code on <a href=\"https://github.com/LoginRadius/engineering-blog-samples/tree/master/NodeJs/PasswordHasingNodejs\">Github</a>.</p>\n<style class=\"grvsc-styles\">\n  .grvsc-container {\n    overflow: auto;\n    -webkit-overflow-scrolling: touch;\n    padding-top: 1rem;\n    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));\n    padding-bottom: 1rem;\n    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));\n    border-radius: 8px;\n    border-radius: var(--grvsc-border-radius, 8px);\n    font-feature-settings: normal;\n  }\n  \n  .grvsc-code {\n    display: inline-block;\n    min-width: 100%;\n  }\n  \n  .grvsc-line {\n    display: inline-block;\n    box-sizing: border-box;\n    width: 100%;\n    padding-left: 1.5rem;\n    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));\n    padding-right: 1.5rem;\n    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));\n  }\n  \n  .grvsc-line-highlighted {\n    background-color: var(--grvsc-line-highlighted-background-color, transparent);\n    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, transparent);\n  }\n  \n  .dark-default-dark {\n    background-color: #1E1E1E;\n    color: #D4D4D4;\n  }\n  .dark-default-dark .mtk3 { color: #6A9955; }\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 .mtk10 { color: #4EC9B0; }\n  .dark-default-dark .mtk7 { color: #B5CEA8; }\n  .dark-default-dark .mtk15 { color: #C586C0; }\n  .dark-default-dark .mtk14 { color: #F44747; }\n</style>","frontmatter":{"date":"June 25, 2020","updated_date":null,"description":null,"title":"Password hashing with NodeJS","tags":["Security","NodeJs"],"pinned":null,"coverImage":{"childImageSharp":{"fluid":{"aspectRatio":1.4598540145985401,"src":"/static/3500f6f614e274d34fe0b6c1213a16a2/ee604/cover.png","srcSet":"/static/3500f6f614e274d34fe0b6c1213a16a2/69585/cover.png 200w,\n/static/3500f6f614e274d34fe0b6c1213a16a2/497c6/cover.png 400w,\n/static/3500f6f614e274d34fe0b6c1213a16a2/ee604/cover.png 800w,\n/static/3500f6f614e274d34fe0b6c1213a16a2/f3583/cover.png 1200w,\n/static/3500f6f614e274d34fe0b6c1213a16a2/3bf79/cover.png 1440w","sizes":"(max-width: 800px) 100vw, 800px"}}},"author":{"id":"Ashish Sharma","github":"ashish8947","avatar":null}}}}]},"markdownRemark":{"excerpt":"Identity is evolving, and developers are at the forefront of this transformation. Every day brings a new learning—adapting to new standards…","fields":{"slug":"/identity/developer-first-identity-provider-loginradius/"},"html":"<p>Identity is evolving, and developers are at the forefront of this transformation. Every day brings a new learning—adapting to new standards and refining approaches to building secure, seamless experiences.</p>\n<p>We’re here to support developers on that journey. We know how important simplicity, efficiency, and well-structured documentation are when working with identity and access management solutions. That’s why we’ve redesigned the <a href=\"https://www.loginradius.com/\">LoginRadius website</a>—to be faster, more intuitive, and developer-first in every way.</p>\n<p>The goal? Having them spend less time searching and more time building.</p>\n<h2 id=\"whats-new-and-improved-on-the-loginradius-website\" style=\"position:relative;\"><a href=\"#whats-new-and-improved-on-the-loginradius-website\" aria-label=\"whats new and improved on the loginradius website 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’s New and Improved on the LoginRadius Website?</h2>\n<p>LoginRadius’ vision is to give developers a product that simplifies identity management so they can focus on building, deploying, and scaling their applications. To enhance this experience, we’ve spent the last few months redesigning our interface— making navigation more intuitive and reassuring that essential resources are easily accessible.</p>\n<p>Here’s a closer look at what’s new and why it’s important:</p>\n<h3 id=\"a-developer-friendly-dark-theme\" style=\"position:relative;\"><a href=\"#a-developer-friendly-dark-theme\" aria-label=\"a developer friendly dark theme 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>A Developer-Friendly Dark Theme</h3>\n<p><img src=\"/f46881583c7518a93bb24e94c32320de/a-developer-friendly-dark-theme.webp\" alt=\"This image shows how LoginRadius offers several authentication methods like traditional login, social login, passwordless login, passkeys and more in a dark mode.\">    </p>\n<p>Developers spend long hours working in dark-themed IDEs and terminals, so we’ve designed the LoginRadius experience to be developer-friendly and align with that preference.</p>\n<p>The new dark mode reduces eye strain, enhances readability, and provides a seamless transition between a coding environment and our platform. Our new design features a clean, modern aesthetic with a consistent color scheme and Barlow typography, ensuring better readability. High-quality graphics and icons are thoughtfully placed to enhance the content without adding visual clutter.</p>\n<p>So, whether you’re navigating our API docs or configuring authentication into your system, our improved interface will make those extended development hours more comfortable and efficient.</p>\n<h3 id=\"clear-categorization-for-loginradius-capabilities\" style=\"position:relative;\"><a href=\"#clear-categorization-for-loginradius-capabilities\" aria-label=\"clear categorization for loginradius capabilities 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>Clear Categorization for LoginRadius Capabilities</h3>\n<p><img src=\"/e5358b82be414940f3fb146013845933/capabilities.webp\" alt=\"This image shows a breakdown of all the LoginRadius CIAM capabilities, including authentication, security, UX, scalability and multi-brand management.\"></p>\n<p>We’ve restructured our website to provide a straightforward breakdown of our customer identity and access management platform capabilities, helping you quickly find what you need:</p>\n<ul>\n<li>Authentication: Easily understand <a href=\"https://www.loginradius.com/blog/identity/authentication-option-for-your-product/\">how to choose the right login method</a>, from traditional passwords and OTPs to social login, federated SSO, and passkeys with few lines of code.</li>\n<li>Security: Implement no-code security features like bot detection, IP throttling, breached password alerts, DDoS protection, and adaptive MFA to safeguard user accounts.</li>\n<li>User Experience: Leverage AI builder, hosted pages, and drag-and-drop workflows to create smooth, branded sign-up and login experiences.</li>\n<li>High Performance &#x26; Scalability: Confidently scale with sub-100ms API response times, 100% uptime, 240K+ RPS, and 28+ global data center regions.</li>\n<li>Multi-Brand Management: Efficiently manage multiple identity apps, choosing isolated or shared data stores based on your brand’s unique needs.</li>\n</ul>\n<p>This structured layout ensures you can quickly understand each capability and how it integrates into your identity ecosystem.</p>\n<h3 id=\"developer-first-navigation\" style=\"position:relative;\"><a href=\"#developer-first-navigation\" aria-label=\"developer first navigation 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>Developer-First Navigation</h3>\n<p><img src=\"/a8c155c2b6faf3d5f4b4de4e2b14d763/developers-menu.webp\" alt=\"This image shows the LoginRadius menu bar, highlighting the developer dropdown.\">   </p>\n<p>We’ve been analyzing developer workflows to identify how you access key resources. That’s why we redesigned our navigation with one goal in mind: to reduce clicks and make essential resources readily available.</p>\n<p>The new LoginRadius structure puts APIs, SDKs, and integration guides right at the menu bar under the Developers dropdown so you can get started faster. Our Products, Solutions, and Customer Services are also clearly categorized, helping development teams quickly find the right tools and make informed decisions.</p>\n<h3 id=\"quick-understanding-of-integration-benefits\" style=\"position:relative;\"><a href=\"#quick-understanding-of-integration-benefits\" aria-label=\"quick understanding of integration benefits 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>Quick Understanding of Integration Benefits</h3>\n<p><img src=\"/b2f9a964a2da0ea83e2f8596b833bba7/we-support-your-tech-stack.webp\" alt=\"This image shows a list of popular programming languages and frameworks offered by LoginRadius.\"></p>\n<p>Developers now have a clear view of the tech stack available with LoginRadius, designed to support diverse business needs.</p>\n<p>Our platform offers pre-built SDKs for Node.js, Python, Java, and more, making CIAM integration seamless across popular programming languages and frameworks.</p>\n<h2 id=\"over-to-you-now\" style=\"position:relative;\"><a href=\"#over-to-you-now\" aria-label=\"over to you now 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>Over to You Now!</h2>\n<p>Check out our <a href=\"https://www.loginradius.com/\">revamped LoginRadius website</a> and see how the improved experience makes it easier to build, scale, and secure your applications.</p>\n<p>Do not forget to explore the improved navigation and API documentation, and get started with our free trial today. We’re excited to see what you’ll build with LoginRadius!</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":"February 21, 2025","updated_date":null,"description":"LoginRadius’ vision is to give developers a product that simplifies identity management so they can focus on building, deploying, and scaling their applications. To enhance this experience, we’ve redesigned our website interface, making navigation more intuitive and reassuring that essential resources are easily accessible.","title":"Revamped & Ready: Introducing the New Developer-First LoginRadius Website","tags":["Developer tools","API","Identity Management","User Authentication"],"pinned":true,"coverImage":{"childImageSharp":{"fluid":{"aspectRatio":1.7857142857142858,"src":"/static/80b4e4fbe176a10a327d273504607f32/58556/hero-section.webp","srcSet":"/static/80b4e4fbe176a10a327d273504607f32/61e93/hero-section.webp 200w,\n/static/80b4e4fbe176a10a327d273504607f32/1f5c5/hero-section.webp 400w,\n/static/80b4e4fbe176a10a327d273504607f32/58556/hero-section.webp 800w,\n/static/80b4e4fbe176a10a327d273504607f32/99238/hero-section.webp 1200w,\n/static/80b4e4fbe176a10a327d273504607f32/7c22d/hero-section.webp 1600w,\n/static/80b4e4fbe176a10a327d273504607f32/1258b/hero-section.webp 2732w","sizes":"(max-width: 800px) 100vw, 800px"}}},"author":{"id":"Rakesh Soni","github":"oyesoni","avatar":"rakesh-soni.jpg"}}}},"pageContext":{"limit":6,"skip":762,"currentPage":128,"type":"///","numPages":161,"pinned":"ee8a4479-3471-53b1-bf62-d0d8dc3faaeb"}},"staticQueryHashes":["1171199041","1384082988","2100481360","23180105","528864852"]}