<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Karan Gandhi</title>
    <description>The latest articles on DEV Community by Karan Gandhi (@karandpr).</description>
    <link>https://dev.to/karandpr</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F246346%2Ffd63e9da-cab8-41b1-adf0-a32b141c2290.gif</url>
      <title>DEV Community: Karan Gandhi</title>
      <link>https://dev.to/karandpr</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/karandpr"/>
    <language>en</language>
    <item>
      <title>Happy new year !</title>
      <dc:creator>Karan Gandhi</dc:creator>
      <pubDate>Wed, 01 Jan 2025 13:56:05 +0000</pubDate>
      <link>https://dev.to/karandpr/happy-new-year--5geh</link>
      <guid>https://dev.to/karandpr/happy-new-year--5geh</guid>
      <description></description>
      <category>newyearchallenge</category>
    </item>
    <item>
      <title>MASVS &amp; MSTG: A Quick Guide To Mobile App Security</title>
      <dc:creator>Karan Gandhi</dc:creator>
      <pubDate>Mon, 25 Jan 2021 12:47:37 +0000</pubDate>
      <link>https://dev.to/jscrambler/masvs-mstg-a-quick-guide-to-mobile-app-security-5hkc</link>
      <guid>https://dev.to/jscrambler/masvs-mstg-a-quick-guide-to-mobile-app-security-5hkc</guid>
      <description>&lt;p&gt;While dealing with mobile application security, we often hear of the OWASP Mobile Top Ten list - as its name implies, it’s a list of the top ten security risks associated with mobile applications.&lt;/p&gt;

&lt;p&gt;However, seasoned developers and testers might feel the list is inadequate. Let us look at some caveats of OWASP Top Ten.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It's not a guide; it's a &lt;a href="https://owasp.org/www-project-top-ten/2017/Methodology_and_Data.html"&gt;crowdsourced list&lt;/a&gt; of vulnerability categories;&lt;/li&gt;
&lt;li&gt;The list was last updated in 2016 and there are no immediate plans to update it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As developers, we would like a comprehensive set of standards that can be used to design applications. Likewise, security testers would like to test an application against a list of items using predefined methodologies.&lt;/p&gt;

&lt;p&gt;To meet these needs, we can look at the OWASP Mobile Application Security Verification Standard (MASVS) and OWASP Mobile Security Testing Guide (MSTG), which provide enough info to facilitate secure application development and adequate testing.&lt;/p&gt;

&lt;h2&gt;
  
  
  OWASP MASVS
&lt;/h2&gt;

&lt;p&gt;MASVS is an application standard for mobile app security. It helps developers to develop secure mobile applications. Testers can use the standard to highlight relevant security risks.&lt;/p&gt;

&lt;p&gt;This standard provides a list of requirements an application should adhere to, defining two security levels. MASVS-L1 contains generic security requirements that are &lt;strong&gt;recommended for all apps&lt;/strong&gt;; MASVS-L2 contains requirements for &lt;strong&gt;defense-in-depth&lt;/strong&gt;. Then, we also have MASVS-R, a set of &lt;strong&gt;reverse engineering requirements&lt;/strong&gt; that is useful for providing client-side defenses. These levels will be explored in more detail in the next section.&lt;/p&gt;

&lt;p&gt;Currently, the verification requirements are segregated into 8 types. They are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;V1 - Architecture Design and Threat Modelling Requirements&lt;/li&gt;
&lt;li&gt;V2 - Data Storage and Privacy Requirements&lt;/li&gt;
&lt;li&gt;V3 - Cryptography Requirements&lt;/li&gt;
&lt;li&gt;V4 - Authentication and Session Management Requirements&lt;/li&gt;
&lt;li&gt;V5 - Network Communication Requirements&lt;/li&gt;
&lt;li&gt;V6 - Platform Interaction Requirements&lt;/li&gt;
&lt;li&gt;V7 - Code Quality and Build Setting Requirements&lt;/li&gt;
&lt;li&gt;V8 - Resilience Requirements&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;V1-V7 provides requirements for MASVS-L1 and MASVS-L2. MASVS-R is a separate requirement. Enforcing a control requirement is dependent on the business use-case.&lt;/p&gt;

&lt;h2&gt;
  
  
  OWASP MSTG
&lt;/h2&gt;

&lt;p&gt;MSTG is a comprehensive manual that can be used to test if an application fulfills the requirements outlined in MASVS. Likewise, Developers can use the manual to get an idea of how the application can be hacked.&lt;/p&gt;

&lt;p&gt;MASVS has broken down its requirements in the form of MSTG-IDs. Each MSTG-ID in MASVS maps to a relevant test case in MSTG. The Architecture section includes references to other materials like secure &lt;a href="https://owasp.org/www-pdf-archive/Jim_Manico_(Hamburg)_-_Securiing_the_SDLC.pdf"&gt;SDLC&lt;/a&gt; and the OWASP &lt;a href="https://owasp.org/www-pdf-archive/OWASP_Cheatsheets_Book.pdf"&gt;Cheatsheet series&lt;/a&gt;. MSTG has a list of tools and methods specifically to analyze a mobile application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding the MASVS verification Levels
&lt;/h2&gt;

&lt;h3&gt;
  
  
  MASVS-L1
&lt;/h3&gt;

&lt;p&gt;MASVS-L1 is termed as &lt;strong&gt;standard security&lt;/strong&gt;. It adheres to mobile security best practices and fulfills basic requirements in terms of code quality, handling sensitive data, and interaction with the mobile OS. As of MASVS 1.2, it's recommended for L1 Apps to fulfill the following requirements&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MSTG-ARCH 1-4 &amp;amp; 12

&lt;ul&gt;
&lt;li&gt;All app components are identified and needed.&lt;/li&gt;
&lt;li&gt;Security controls are enforced on both server and client.&lt;/li&gt;
&lt;li&gt;High-Level Architecture has been devised and its security is accounted for.&lt;/li&gt;
&lt;li&gt;All sensitive data for the business case has been identified.&lt;/li&gt;
&lt;li&gt;The app complies with relevant privacy laws and &lt;a href="https://jscrambler.com/resources/white-papers/compliance-with-regulations-digital-banking?utm_source=dev.to&amp;amp;utm_medium=referral&amp;amp;utm_campaign=masvs-mstg"&gt;regulations&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;MSTG-STORAGE 1-7

&lt;ul&gt;
&lt;li&gt;System Credential Facilities are used to save sensitive data.&lt;/li&gt;
&lt;li&gt;Sensitive Data is not stored outside the credential facilities, not logged, not shared with third-parties unless part of the architecture, not exposed to IPC mechanisms, and not exposed through a user interface.&lt;/li&gt;
&lt;li&gt;The keyboard cache is disabled while handling sensitive data.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;MSTG-CRYPTO 1-6

&lt;ul&gt;
&lt;li&gt;The app doesn't rely solely on symmetric cryptography with hardcoded keys.&lt;/li&gt;
&lt;li&gt;The app uses proven implementations of &lt;a href="https://blog.jscrambler.com/cryptography-introduction-block-ciphers/?utm_source=dev.to&amp;amp;utm_medium=referral&amp;amp;utm_campaign=masvs-mstg"&gt;cryptography&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;The app doesn't use deprecated standards.&lt;/li&gt;
&lt;li&gt;The app doesn't use the same key for multiple purposes.&lt;/li&gt;
&lt;li&gt;The app uses high entropy RNG.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;MSTG AUTH 1-7 &amp;amp; 12

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://blog.jscrambler.com/authentication-authorization-in-web-apps/?utm_source=dev.to&amp;amp;utm_medium=referral&amp;amp;utm_campaign=masvs-mstg"&gt;Authentication and Authorization&lt;/a&gt; are performed on the remote endpoint. A password policy is present at the remote endpoint.&lt;/li&gt;
&lt;li&gt;Stateful sessions should associate the client with randomly generated session identifiers.&lt;/li&gt;
&lt;li&gt;Stateless Auth tokens should be signed using a &lt;a href="https://blog.jscrambler.com/hashing-algorithms/?utm_source=dev.to&amp;amp;utm_medium=referral&amp;amp;utm_campaign=masvs-mstg"&gt;secure algorithm&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Sessions are invalidated after tokens expire.&lt;/li&gt;
&lt;li&gt;On Logout, the session should be terminated remotely.&lt;/li&gt;
&lt;li&gt;Remote Endpoints are configured to disallow multiple login attempts. &lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;MSTG-NETWORK 1-3

&lt;ul&gt;
&lt;li&gt;Use TLS with recommended best practices.&lt;/li&gt;
&lt;li&gt;Verify x.509 of the remote endpoint. Trust verified CAs only.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;MSTG-PLATFORM- 1-8

&lt;ul&gt;
&lt;li&gt;Manage permissions properly.&lt;/li&gt;
&lt;li&gt;Sanitize external inputs, viz data from external URLs, and intents.&lt;/li&gt;
&lt;li&gt;Avoid exporting sensitive functionality.&lt;/li&gt;
&lt;li&gt;Disable JS in WebView.&lt;/li&gt;
&lt;li&gt;Restrict protocols in WebView.&lt;/li&gt;
&lt;li&gt;Restrict Native code access to JS in the app package.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;MSTG-CODE 1-9

&lt;ul&gt;
&lt;li&gt;The app is signed with a valid certificate with a private key.&lt;/li&gt;
&lt;li&gt;The published build is in release mode.&lt;/li&gt;
&lt;li&gt;Debugging symbols have been removed.&lt;/li&gt;
&lt;li&gt;Third-party libraries and components have been identified and tested against vulnerabilities.&lt;/li&gt;
&lt;li&gt;Access is denied by default.&lt;/li&gt;
&lt;li&gt;Security features offered by toolchain are used.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Typically, enforcing L1 requirements won’t have a significant impact on the SDLC. Depending on the business and use-cases, it's recommended to employ L1 requirements in all apps.&lt;/p&gt;

&lt;h3&gt;
  
  
  MASVS-L2
&lt;/h3&gt;

&lt;p&gt;MASVS-L2 is termed as a defense-in-depth. To fulfill L2 requirements, a threat model must exist and security should be a part of the app life cycle. For example:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A separate secure life cycle has to be defined for sensitive data. &lt;/li&gt;
&lt;li&gt;2FA is enforced mandatorily. &lt;a href="https://blog.jscrambler.com/ssl-pinning/?utm_source=dev.to&amp;amp;utm_medium=referral&amp;amp;utm_campaign=masvs-mstg"&gt;Certificate Pinning&lt;/a&gt; is enforced. &lt;/li&gt;
&lt;li&gt;Custom keyboards are blocked from accessing sensitive data.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The following requirements are necessary for L2 Apps. We will be highlighting the ones above the L1 requirements:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MSTG-ARCH 1-12

&lt;ul&gt;
&lt;li&gt;The app components should be defined in terms of business and security functions.&lt;/li&gt;
&lt;li&gt;A threat model for the mobile application should be defined and possible countermeasures should be recorded.&lt;/li&gt;
&lt;li&gt;A separate policy for cryptography should be established.&lt;/li&gt;
&lt;li&gt;A mechanism for enforcing updates should be implemented.&lt;/li&gt;
&lt;li&gt;Security should be addressed across all components.&lt;/li&gt;
&lt;li&gt;A responsible disclosure policy should be in place.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;MSTG-STORAGE 1-15

&lt;ul&gt;
&lt;li&gt;Sensitive data should not be present in the provided backups.&lt;/li&gt;
&lt;li&gt;The app removes sensitive data when it moves to the background.&lt;/li&gt;
&lt;li&gt;The app doesn't hold sensitive data in memory for long. Memory should be cleared explicitly after usage.&lt;/li&gt;
&lt;li&gt;The app should enforce minimum device security policy like forcing the user to set a device passcode.&lt;/li&gt;
&lt;li&gt;The app educates the user about the sensitive data the app uses and the security best practices it follows.&lt;/li&gt;
&lt;li&gt;Sensitive data should not be present on the phone. It should be stored at a remote endpoint and retrieved from the endpoint.&lt;/li&gt;
&lt;li&gt;In case sensitive data needs to be stored on the mobile device, it should be encrypted with a key derived from hardware-backed storage that requires authentication.&lt;/li&gt;
&lt;li&gt;The app's local storage should be wiped out after multiple unsuccessful attempts.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;MSTG-CRYPTO 1-6

&lt;ul&gt;
&lt;li&gt;Same as L1.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;MSTG AUTH 1-12

&lt;ul&gt;
&lt;li&gt;Biometric Authentication should not be event-bound.&lt;/li&gt;
&lt;li&gt;2FA is consistently enforced.&lt;/li&gt;
&lt;li&gt;Sensitive transactions require step-up authentication.&lt;/li&gt;
&lt;li&gt;The app informs the user about all sensitive activities in their accounts. As in, users should be able to see all logged-in sessions, locations from where a device logged in, and device info of logged-in users.&lt;/li&gt;
&lt;li&gt;Controls for blocking devices should be made available to users.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;MSTG-NETWORK 1-6

&lt;ul&gt;
&lt;li&gt;The app uses its own certificate or pins an endpoint certificate. The app doesn't trust an endpoint with a different certificate.&lt;/li&gt;
&lt;li&gt;The app doesn't rely on a single insecure communication (email, SMS) for operations like enrollment or account recovery.&lt;/li&gt;
&lt;li&gt;The app depends on updated, secure libraries.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;MSTG-PLATFORM- 1-11

&lt;ul&gt;
&lt;li&gt;The app should protect itself against screen overlay attacks.&lt;/li&gt;
&lt;li&gt;WebView's cache, storage, and resources should be destroyed after a WebView is destroyed.&lt;/li&gt;
&lt;li&gt;The app prevents the usage of third-party keyboards when a user is entering sensitive data&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;MSTG-CODE 1-9

&lt;ul&gt;
&lt;li&gt;Same as L1.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As you can see, L2 has a considerably high development overhead. Such requirements are usually applicable to financial and healthcare apps. These domains require certain compliances (HIPAA, &lt;a href="https://jscrambler.com/solutions/finance/whitepaper-psd2?utm_source=dev.to&amp;amp;utm_medium=referral&amp;amp;utm_campaign=masvs-mstg"&gt;PSD2&lt;/a&gt;, and &lt;a href="https://jscrambler.com/resources/webinars/pci-dss-compliance-and-magecart-web-skimming-attacks?utm_source=dev.to&amp;amp;utm_medium=referral&amp;amp;utm_campaign=masvs-mstg"&gt;PCI-DSS&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;While MASVS-R is a separate level for &lt;strong&gt;client-side attacks&lt;/strong&gt;, it's safe to assume that an L2-compliant app should employ the R level as well. One of the requirements of L2 is to threat model an application. And client-side security should be a part of that threat model.&lt;/p&gt;

&lt;h3&gt;
  
  
  MASVS-R
&lt;/h3&gt;

&lt;p&gt;The MASVS - R is a specially defined level for defense against client-side attacks. That includes attacks like tampering, modifying, and reverse engineering. As such, an application should: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Detect rooted/jailbroken devices and emulators.&lt;/li&gt;
&lt;li&gt;Prevent debugging.&lt;/li&gt;
&lt;li&gt;Detect application and asset tampering.&lt;/li&gt;
&lt;li&gt;Verify client integrity.&lt;/li&gt;
&lt;li&gt;Identify popular dynamic analysis tools like Frida and impede them.&lt;/li&gt;
&lt;li&gt;Have multiple strategies to achieve the points above.&lt;/li&gt;
&lt;li&gt;Employ &lt;a href="https://blog.jscrambler.com/introduction-to-device-fingerprinting/?utm_source=dev.to&amp;amp;utm_medium=referral&amp;amp;utm_campaign=masvs-mstg"&gt;device fingerprinting&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Impede static analysis by encryption and &lt;a href="https://jscrambler.com/products/code-integrity/javascript-obfuscation?utm_source=dev.to&amp;amp;utm_medium=referral&amp;amp;utm_campaign=masvs-mstg"&gt;obfuscation&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Have solid hardened communication strategies.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;MASVS-R can be used with L1 or L2 controls. As mentioned earlier, we can safely assume an L2-compliant app already might employ MASVS-R controls. There are some unique cases when you don't need sensitive data management but require client-side security. Let's see some of the use cases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Games: Gaming is a booming industry that is traditionally targeted by hackers. You can see unique and aggressive client-side defenses in games like &lt;a href="https://www.xda-developers.com/pokemon-go-aggressive-root-checking-twrp-folder/"&gt;Pokemon Go&lt;/a&gt; and &lt;a href="https://medium.com/@topjohnwu/from-anime-game-to-android-system-security-vulnerability-9b955a182f20"&gt;Fate Grand Order&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Mobile apps that require client-side IP protection. Like apps interfacing with hardware like IoT devices, biometric devices, wearables, etc.&lt;/li&gt;
&lt;li&gt;Business use-cases that require offline functionality. If you read the list, a lot of the security controls require an internet connection to enforce them. For offline apps, client-side security has to be thought out extensively.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Framing MASVS to Cross-Platform Frameworks
&lt;/h3&gt;

&lt;p&gt;Cross-platform frameworks allow developing applications for both Android and iOS using a shared codebase. Some of the most &lt;a href="https://blog.jscrambler.com/10-frameworks-for-mobile-hybrid-apps/?utm_source=dev.to&amp;amp;utm_medium=referral&amp;amp;utm_campaign=masvs-mstg"&gt;popular cross-platform frameworks&lt;/a&gt; include React Native, Ionic, Cordova, Flutter, Xamarin, NativeScript, and Unity (for games).&lt;/p&gt;

&lt;p&gt;MSTG covers cross-platform frameworks rather briefly. However, it’s recommended to test them as Native Apps. This makes sense from the standpoint of a tester but it's problematic from a developer perspective. For brevity, we will be considering JavaScript frameworks.&lt;/p&gt;

&lt;p&gt;One of the biggest selling points of cross-platform frameworks is that we can leverage existing web technologies to develop an application on multiple platforms. A developer doesn't need to have a very extensive knowledge of native code to create mobile apps.&lt;/p&gt;

&lt;p&gt;While there are good practices outlined in the documentation, to develop a secure solution, a developer needs a deep understanding of web technologies and native platforms. &lt;/p&gt;

&lt;p&gt;We have outlined some good practices in our guides to &lt;a href="https://blog.jscrambler.com/securing-ionic-4-cordova-apps/?utm_source=dev.to&amp;amp;utm_medium=referral&amp;amp;utm_campaign=masvs-mstg"&gt;Secure Ionic&lt;/a&gt; and &lt;a href="https://blog.jscrambler.com/securing-react-native-applications/?utm_source=dev.to&amp;amp;utm_medium=referral&amp;amp;utm_campaign=masvs-mstg"&gt;Securing React Native&lt;/a&gt;. If you’re working with either of these frameworks, make sure to follow these guides.&lt;/p&gt;

&lt;p&gt;Even so, some of the security controls outlined in MASVS have to be enforced as native code. This adds quite a bit of overhead while developing the applications. So, it's recommended to develop a security model based on MASVS with WebView risks and utility overhead and then proceed to development.&lt;/p&gt;

&lt;h3&gt;
  
  
  Addressing MASVS-R With Jscrambler
&lt;/h3&gt;

&lt;p&gt;As stated before, MASVS-R outlines certain security controls that must be implemented in mobile applications that are especially critical. Examples include mobile banking apps, fintech services, healthcare apps, apps with in-app purchases, and mostly every client-facing app that handles sensitive user data or contains proprietary logic.&lt;/p&gt;

&lt;p&gt;Jscrambler directly addresses the client-side security requirements of MASVS-R. Specifically, it:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Allows &lt;a href="https://docs.jscrambler.com/7.1/code-integrity/documentation/transformations/root-jailbreak-detection-lock"&gt;detecting rooted/jailbroken devices&lt;/a&gt; and triggering countermeasures to prevent the app (or some app features) from running on these risky devices;&lt;/li&gt;
&lt;li&gt;Actively prevents debugging and tampering, using a &lt;a href="https://docs.jscrambler.com/code-integrity/documentation/transformations/self-defending"&gt;Self-Defending&lt;/a&gt; feature that scatters integrity checks throughout the code and breaks the app when a debugger is opened or when the source code has been tampered with;&lt;/li&gt;
&lt;li&gt;Allows preventing tampering attempts at runtime without disturbing the user experience, using a &lt;a href="https://docs.jscrambler.com/code-integrity/documentation/transformations/self-healing"&gt;Self-Healing&lt;/a&gt; feature that uses checksum techniques to verify the app’s integrity and guarantees that only the correct code is executed;&lt;/li&gt;
&lt;li&gt;Ensures the integrity of the client environment, providing a series of &lt;a href="https://blog.jscrambler.com/jscrambler-101-code-locks/?utm_source=dev.to&amp;amp;utm_medium=referral&amp;amp;utm_campaign=masvs-mstg"&gt;Code Locks&lt;/a&gt; that can be used to only allow app execution in allowed domains, browsers, OSes, and timeframes;&lt;/li&gt;
&lt;li&gt;Includes a &lt;a href="https://docs.jscrambler.com/code-integrity/documentation/code-hardening"&gt;Code Hardening&lt;/a&gt; feature that prevents the usage of reverse engineering tools, which is constantly updated to cover new versions of these tools;&lt;/li&gt;
&lt;li&gt;Provides state-of-the-art &lt;a href="https://docs.jscrambler.com/code-integrity/documentation/transformations"&gt;obfuscation&lt;/a&gt;, with a combination of 20+ transformations like control flow flattening, string concealing, and identifiers renaming, which provide maximum potency and resilience;&lt;/li&gt;
&lt;li&gt;Has a polymorphic behavior, ensuring that each new deployment of protected code is completely different, but still works just like the original code;&lt;/li&gt;
&lt;li&gt;Has specific features to protect sensitive data, namely &lt;a href="https://docs.jscrambler.com/7.1/code-integrity/documentation/transformations/memory-protection"&gt;Memory Protection&lt;/a&gt;, which ciphers sensitive data when it’s not being used by the app.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can directly test these transformations in your own code with a Jscrambler &lt;a href="https://jscrambler.com/signup?utm_source=dev.to&amp;amp;utm_medium=referral&amp;amp;utm_campaign=masvs-mstg"&gt;free trial&lt;/a&gt;. Plus, you can use Jscrambler to protect &lt;a href="https://jscrambler.com/products/hybrid-apps-protection?utm_source=dev.to&amp;amp;utm_medium=referral&amp;amp;utm_campaign=masvs-mstg"&gt;JavaScript, C/C++, Objective-C/C++, Java, Swift, and Kotlin&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In case you’re working with a hybrid framework, check the integration tutorials for &lt;a href="https://blog.jscrambler.com/how-to-protect-react-native-apps-with-jscrambler/?utm_source=dev.to&amp;amp;utm_medium=referral&amp;amp;utm_campaign=masvs-mstg"&gt;React Native&lt;/a&gt;, &lt;a href="https://blog.jscrambler.com/protecting-hybrid-mobile-apps-with-ionic-and-jscrambler/?utm_source=dev.to&amp;amp;utm_medium=referral&amp;amp;utm_campaign=masvs-mstg"&gt;Ionic&lt;/a&gt;, and &lt;a href="https://blog.jscrambler.com/protecting-your-nativescript-source-code-with-jscrambler/?utm_source=dev.to&amp;amp;utm_medium=referral&amp;amp;utm_campaign=masvs-mstg"&gt;NativeScript&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Final Thoughts
&lt;/h3&gt;

&lt;p&gt;This was a brief overview of what OWASP MASVS and MSTG can offer to mobile app developers and testers.&lt;/p&gt;

&lt;p&gt;We recommend that you check the &lt;a href="https://github.com/OWASP/owasp-mstg/tree/master/Checklists"&gt;Mobile App Security Checklist&lt;/a&gt;, which maps MASVS and MSTG as an Excel sheet.&lt;/p&gt;

&lt;p&gt;In case you have specific security concerns, feel free to &lt;a href="https://jscrambler.com/products#contact-form" class="book-demo-link"&gt;request a meeting&lt;/a&gt; with one of Jscrambler's Application Security Experts.&lt;/p&gt;

</description>
      <category>security</category>
      <category>javascript</category>
      <category>mobile</category>
      <category>owasp</category>
    </item>
    <item>
      <title>Setting Up A Parse Server As An Alternative Backend</title>
      <dc:creator>Karan Gandhi</dc:creator>
      <pubDate>Thu, 24 Sep 2020 16:23:09 +0000</pubDate>
      <link>https://dev.to/jscrambler/setting-up-a-parse-server-as-an-alternative-backend-414b</link>
      <guid>https://dev.to/jscrambler/setting-up-a-parse-server-as-an-alternative-backend-414b</guid>
      <description>&lt;p&gt;Sometimes, we encounter situations when it's not feasible to develop a full-fledged backend from the ground up. In such situations, we rely on services like &lt;a href="https://blog.jscrambler.com/integrating-firebase-with-react-native/?utm_source=dev.to&amp;amp;utm_medium=referral&amp;amp;utm_campaign=parse-server"&gt;Firebase&lt;/a&gt; to speed up development.&lt;/p&gt;

&lt;p&gt;Parse is an open-source mobile Backend As a Service (mBAAS) platform. Previously, Parse was a backend platform similar to Firebase. In 2016, Facebook open-sourced the platform code and sunsetted their hosting services. In this article, we will be taking a brief look at Parse and seeing how it allows us to deploy applications quickly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Overview
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://parseplatform.org/"&gt;Parse&lt;/a&gt; is a full-fledged backend with support for REST API and GraphQL which can be self-hosted. It is open source and is being actively maintained by communities.&lt;/p&gt;

&lt;p&gt;It has SDKs available for iOS, Android, JavaScript, and other platforms, as well as support for Push Notifications including campaigns, out-of-the-box user management, support for &lt;a href="https://docs.parseplatform.org/parse-server/guide/#oauth-and-3rd-party-authentication"&gt;OAuth providers&lt;/a&gt; (including Facebook, Twitter, Google, GitHub, and LDAP), support for Docker, deployment options to various &lt;a href="https://github.com/parse-community/parse-server/wiki#community-links"&gt;platforms&lt;/a&gt; (including AWS and Heroku), as well as support for different storage adapters.&lt;/p&gt;

&lt;p&gt;Parse is extensible with webhooks, jobs, and config, and has quite a few community plugins. You can use it together with Express.js.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up Parse
&lt;/h2&gt;

&lt;p&gt;Parse requires Node 8+, MongoDB or PostgreSQL to set up. On UNIX like systems, it's advisable to use NVM for Node.js installations. The steps are as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; parse-server mongodb-runner
mongodb-runner start
parse-server &lt;span class="nt"&gt;--appId&lt;/span&gt; APPLICATION_ID &lt;span class="nt"&gt;--masterKey&lt;/span&gt; MASTER_KEY &lt;span class="nt"&gt;--databaseURI&lt;/span&gt; mongodb://localhost/test
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can also use Docker to start Parse:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/parse-community/parse-server
&lt;span class="nb"&gt;cd &lt;/span&gt;parse-server
docker build &lt;span class="nt"&gt;--tag&lt;/span&gt; parse-server &lt;span class="nb"&gt;.&lt;/span&gt;
docker run &lt;span class="nt"&gt;--name&lt;/span&gt; my-mongo &lt;span class="nt"&gt;-d&lt;/span&gt; mongo
docker run &lt;span class="nt"&gt;--name&lt;/span&gt; my-parse-server &lt;span class="nt"&gt;-v&lt;/span&gt; cloud-code-vol:/parse-server/cloud &lt;span class="nt"&gt;-v&lt;/span&gt; config-vol:/parse-server/config &lt;span class="nt"&gt;-p&lt;/span&gt; 1337:1337 &lt;span class="nt"&gt;--link&lt;/span&gt; my-mongo:mongo &lt;span class="nt"&gt;-d&lt;/span&gt; parse-server &lt;span class="nt"&gt;--appId&lt;/span&gt; APPLICATION_ID &lt;span class="nt"&gt;--masterKey&lt;/span&gt; MASTER_KEY &lt;span class="nt"&gt;--databaseURI&lt;/span&gt; mongodb://mongo/test
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;APPLICATION_ID&lt;/code&gt; is the name of the application and can be user-generated. &lt;code&gt;MASTER_KEY&lt;/code&gt; is a key that can override all permissions. Other parameters are listed below:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;databaseURI&lt;/code&gt;: Connection string URI for your MongoDB.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;cloud&lt;/code&gt;: Path to your app’s Cloud Code.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;appId&lt;/code&gt;: A unique identifier for your app.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;fileKey&lt;/code&gt;: A key that specifies a prefix used for file storage. For migrated apps, this is necessary to provide access to files already hosted on Parse.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;masterKey&lt;/code&gt;: A key that overrides all permissions. Keep this secret.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;clientKey&lt;/code&gt;: The client key for your app. (optional)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;restAPIKey&lt;/code&gt;: The REST API key for your app. (optional)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;javascriptKey&lt;/code&gt;: The JavaScript key for your app. (optional)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;dotNetKey&lt;/code&gt;: The .NET key for your app. (optional)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;push&lt;/code&gt;: An object containing push configuration. See Push&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;filesAdapter&lt;/code&gt;: An object that implements the FilesAdapter interface. For example, the S3 files adapter&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;auth&lt;/code&gt;: Configure support for 3rd party authentication.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;maxUploadSize&lt;/code&gt;: Maximum file upload size. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And that's it! We have a Parse backend running successfully in minutes. &lt;/p&gt;

&lt;p&gt;For convenience, we can install the Parse dashboard - a visual admin panel for the Parse server. To run &lt;code&gt;parse-dashboard&lt;/code&gt;, we need to install it globally.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm -i g parse-dashboard

parse-dashboard --dev --appId APPLICATION_ID --masterKey MASTER_KEY --serverURL "http://localhost:1337/parse/" --appName SimpleFileStorage
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can access the dashboard on &lt;code&gt;localhost:4040&lt;/code&gt;. For this tutorial, we will be using the REST API.&lt;/p&gt;

&lt;h2&gt;
  
  
  Backend Features
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Storing Data
&lt;/h3&gt;

&lt;p&gt;As mentioned earlier, Parse allows us to store data easily. The base unit of all data is the objects API. For example, if we define a vehicle class with the keys manufacturer and model, we can perform CRUD REST operations using a simple curl request.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -X POST \
  -H "X-Parse-Application-Id: simple_file_storage" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{"manufacturer": "Lamborghini", "model":  "Gallardo"}' \
  http://localhost:1337/parse/classes/vehicle

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We get &lt;code&gt;objectId&lt;/code&gt; and &lt;code&gt;created _date&lt;/code&gt; in response. Further operations on the object can be performed using &lt;code&gt;objectid&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -X GET \
  -H "X-Parse-Application-Id: simple_file_storage" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "Content-Type: application/json" \
  http://localhost:1337/parse/classes/vehicle/objectId
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -X PUT \
  -H "X-Parse-Application-Id: simple_file_storage" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  -H "Content-Type: application/json" \
  -d '{"manufacturer": "Lamborghini", "model":  "Murcielago"}' \
  http://localhost:1337/parse/classes/vehicle/objectId
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -X DELETE \
  -H "X-Parse-Application-Id: simple_file_storage" \
  -H "X-Parse-REST-API-Key: ${REST_API_KEY}" \
  http://localhost:1337/parse/classes/objectId

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In case a class is not predefined, it will be created by the server. We can use Parse Dashboard to create custom classes. As far as data types are concerned, Parse has support for string, number, boolean, arrays, JSON Objects, Date-Time, File, and Null. Additionally Parse has two custom datatypes, Pointer to Another Parse Object and Relation to another Parse Class. Data types in Parse are locked in. Once a datatype is set, it will return an error if you try to save anything else.&lt;/p&gt;

&lt;h2&gt;
  
  
  Files
&lt;/h2&gt;

&lt;p&gt;As with data, file upload is straightforward. The files URL is the &lt;code&gt;/files&lt;/code&gt; route and the file name.&lt;br&gt;
However, we have to manually handle the content type.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;curl -X POST \
  -H "X-Parse-Application-Id: simple_file_storage" \
  -H "X-Parse-REST-API-Key: REST_API_KEY" \
  -H "Content-Type: image/jpeg" \
  --data-binary '@myPicture.jpg' \
  http://localhost:1337/parse/files/pic.jpg
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As a response, we receive the file location and name of the saved file. A unique identifier is appended to the file name.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "url": "http://localhost:1337/parse/files/simple_file_storage/d840137c22d89d126075ec7fa875c54f_pic.jpg",
  "name": "d840137c22d89d126075ec7fa875c54f_pic.jpg"
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Authentication &amp;amp; Security
&lt;/h2&gt;

&lt;p&gt;Parse provides out-of-the-box user authentication. This includes token-based authentication, user actions like sign up, login, email verification, reset passwords, token-based session management, and role-based access management. The routes for users are &lt;code&gt;/parse/users&lt;/code&gt;, the routes for roles are &lt;code&gt;/parse/roles&lt;/code&gt; and the routes for sessions are &lt;code&gt;/parse/sessions&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;To secure data, Parse provides Class Level Permissions (CLP) and Access Control Lists (ACL). CLP provides fine-grained control over data access to roles. Using Class Level Permissions we can define Roles which will have the ability to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create new Classes;&lt;/li&gt;
&lt;li&gt;Add Fields to Classes;&lt;/li&gt;
&lt;li&gt;Read or Query Data from classes;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Furthermore, using ACLs we can restrict access to objects to individuals and roles. An example snippet of ACL is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="err"&gt;classLevelPermissions:&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"find"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"requiresAuthentication"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"role:admin"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"get"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"requiresAuthentication"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"role:admin"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"create"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"role:admin"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"update"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"role:admin"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"delete"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"role:admin"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This particular object:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;is inaccessible to guests;&lt;/li&gt;
&lt;li&gt;requires authentication to view and query objects;&lt;/li&gt;
&lt;li&gt;has a predefined role admin, can perform all operations.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The picture below, from the Parse docs, demonstrates how CLPs and ACLs interact.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8p3LONDM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.jscrambler.com/content/images/2020/09/clp_vs_acl_diagram.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8p3LONDM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.jscrambler.com/content/images/2020/09/clp_vs_acl_diagram.png" alt="clp_vs_acl_diagram"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Miscellaneous Features
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Cloud Functions allow us to define custom functions in the Parse backend. &lt;/li&gt;
&lt;li&gt;Hooks allow us to run custom code in other languages and extend server-side logic.&lt;/li&gt;
&lt;li&gt;Jobs allow us to run long-running functions so we don't have to wait for a response.&lt;/li&gt;
&lt;li&gt;Triggers allow us to write custom code before/after data is modified.&lt;/li&gt;
&lt;li&gt;Analytics allows us to add dimensions and metrics to our application.&lt;/li&gt;
&lt;li&gt;Push Dashboard allows us to create custom push campaigns for our mobile apps.&lt;/li&gt;
&lt;li&gt;Geo points allow us to associate real-world latitudes and longitudes with an object.&lt;/li&gt;
&lt;li&gt;Config allows us to save config parameters on the server.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Extending Parse with Chisel and Parse Auditor
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Chisel CMS
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://chiselcms.com/"&gt;Chisel&lt;/a&gt; is an API-first headless CMS built upon Parse. Setting up Chisel over Parse is quite straightforward.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; chisel-cms
chisel-cms &lt;span class="nt"&gt;--appId&lt;/span&gt; &lt;span class="s2"&gt;"APP_ID"&lt;/span&gt; &lt;span class="nt"&gt;--serverURL&lt;/span&gt; &lt;span class="s2"&gt;"https://YOURSERVER.com/parse"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Chisel will start at &lt;code&gt;localhost:9000&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Chisel provides an admin panel where we can set up multiple sites. Additionally, it has its own &lt;a href="https://github.com/beachio/chisel-parse-server-starter"&gt;Parse server&lt;/a&gt;. While you can run Chisel on any Parse server, Chisel's server has helpful templates like blog and knowledge base.&lt;br&gt;
It's advisable to check the &lt;a href="https://chiselcms.com/docs/data-structure"&gt;data structures&lt;/a&gt; and &lt;a href="https://chiselcms.com/docs/content-publishing-lifecycle"&gt;content publishing&lt;/a&gt; life cycle before diving in.&lt;/p&gt;
&lt;h3&gt;
  
  
  Parse Auditor
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/Blackburn-Labs/parse-auditor"&gt;Parse auditor&lt;/a&gt; is a module inspired by the Envers Project. It adds automated data tracking/auditing to classes. This is useful when the app is needed to adhere to regulations like HIPAA. Parse Auditor has to be used in the cloud code. Let's take a look at how Parse Auditor works&lt;/p&gt;

&lt;p&gt;Let's assume we have &lt;code&gt;ImportantData&lt;/code&gt; and &lt;code&gt;SortOfImportanData&lt;/code&gt; classes in Parse. We would like to track data changes in both classes and know if &lt;code&gt;ImportantData&lt;/code&gt; was accessed. &lt;/p&gt;

&lt;p&gt;To set up Parse Auditor, we need to edit the cloud code. First, shut down any running instance of the Parse server and dashboard. Then, navigate to the cloud folder of your Parse installation. If there is no cloud folder, then create a &lt;code&gt;main.js&lt;/code&gt; file inside a cloud folder. We need the absolute path of the cloud folder. It should look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;C:\somefolder\Parse\cloud\main.js
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Inside the cloud folder, add &lt;code&gt;parse-auditor&lt;/code&gt; to the dependencies in &lt;code&gt;package.json&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"dependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"parse-auditor"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"*"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, edit the &lt;code&gt;main.js&lt;/code&gt; file as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ParseAuditor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;parse-auditor&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;ParseAuditor&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ImportantData&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SortOfImportantData&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ImportantData&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first param takes an array of Class names and tracks them in a separate &lt;code&gt;Class_AUD&lt;/code&gt; class. The second param takes an array of Class names and tracks views in the &lt;code&gt;Class_AUD&lt;/code&gt; class.&lt;/p&gt;

&lt;p&gt;By default, changes to &lt;code&gt;ImportantData&lt;/code&gt; and &lt;code&gt;SortOfImportantData&lt;/code&gt; will be tracked in &lt;code&gt;ImportantData_AUD&lt;/code&gt; and &lt;code&gt;SortOfImportantData_AUD&lt;/code&gt;. Views of &lt;code&gt;ImportantData&lt;/code&gt; will be tracked in &lt;code&gt;SortOfImportantData_AUD&lt;/code&gt;. Four extra fields are attached to audit logs:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;meta_actor: The user involved in this event. Either the user who made the update or the one who viewed this record.&lt;/li&gt;
&lt;li&gt;meta_action: Will be "SAVE", "DELETE", or "FIND" depending on the action the user took.&lt;/li&gt;
&lt;li&gt;meta_class: The name of the class, convenient when combining complex audit histories across many classes.&lt;/li&gt;
&lt;li&gt;meta_subject: The row being edited/viewed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The plugin can be configured further using these fields:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;classPrefix&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;//Class Prefix&lt;/span&gt;
    &lt;span class="nx"&gt;classPostfix&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;_AUD&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;//Class Postfix&lt;/span&gt;
    &lt;span class="nx"&gt;fieldPrefix&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;meta_&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;//field Postfix&lt;/span&gt;
    &lt;span class="nx"&gt;fieldPostfix&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// field Postfix&lt;/span&gt;
    &lt;span class="nx"&gt;parseSDK&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Parse&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;//SDK Object&lt;/span&gt;
    &lt;span class="nx"&gt;useMasterKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;//MasterKey&lt;/span&gt;
    &lt;span class="nx"&gt;clp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt; &lt;span class="c1"&gt;//Class Level Permissions &lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Consider the example below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ParseAuditor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;parse-auditor&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;customConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;classPostfix&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;_LOGS&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="nx"&gt;ParseAuditor&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ImportantData&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SortOfImportantData&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ImportantData&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="nx"&gt;customConfig&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will log the data to a class sufficed with _LOGS. To start the server, we will have to pass &lt;code&gt;main.js&lt;/code&gt; to the cloud param as below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;parse-server --appId APPLICATION_ID --masterKey MASTER_KEY --databaseURI mongodb://localhost/test --cloud "C:\somefolder\Parse\cloud\main.js"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this, we have successfully set up Parse with custom logging.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;In this article, we have seen how we quickly generate an app backend using Parse.&lt;/p&gt;

&lt;p&gt;We have covered how Parse handles permissions and how they can be used to secure data. Also, we have covered two useful tools that can be used with Parse: Chisel CMS and Parse Auditor.&lt;/p&gt;

</description>
      <category>parse</category>
      <category>api</category>
      <category>node</category>
      <category>backend</category>
    </item>
    <item>
      <title>SSL Pinning</title>
      <dc:creator>Karan Gandhi</dc:creator>
      <pubDate>Fri, 29 May 2020 13:33:39 +0000</pubDate>
      <link>https://dev.to/jscrambler/ssl-pinning-3f48</link>
      <guid>https://dev.to/jscrambler/ssl-pinning-3f48</guid>
      <description>&lt;h2&gt;
  
  
  Introduction to TLS/SSL
&lt;/h2&gt;

&lt;p&gt;Transport Layer Security (TLS) is a cryptographic protocol that is used to secure communications over the network. TLS was preceded by Secure Sockets Layer (SSL). Websites use TLS to secure communications between servers and web browsers. &lt;br&gt;
The common flow in a TLS connection is as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A client initiates a connection to the server;&lt;/li&gt;
&lt;li&gt;The server responds with a certificate containing its public key;&lt;/li&gt;
&lt;li&gt;The client verifies the certificate with preinstalled Certified Authority (CA) certificates on the computer;&lt;/li&gt;
&lt;li&gt;On success, the client creates a new secret key which is encrypted using Server's Public key;&lt;/li&gt;
&lt;li&gt;The server decrypts the new key with its private key;&lt;/li&gt;
&lt;li&gt;All further communications are carried using this secret key.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;CAs play a key role in securing the connections. They issue digital certificates that certify ownership of public keys, usually X.509.&lt;/p&gt;

&lt;h2&gt;
  
  
  Digital Certificates
&lt;/h2&gt;

&lt;p&gt;Asymmetric Cryptography is a system that uses a pair of public and private keys to secure a system. A user can distribute his public key which in turn can be used by others to sign a message. A user can verify the authenticity of the message using his private key. A digital certificate is an electronic document that certifies ownership of a public key. If the signature is valid and the issuer is trusted, then that key can be used to communicate securely. In our context, the Certificate Authority is the issuer. Let's take a look at the different types of certificates.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Root Certificates: this is a certificate that identifies a Certificate Authority. These certificates are self-signed. Usually CAs issue certificates in a tree format. Root certificates are used to sign an intermediate certificate and establish a root chain. Intermediate certificates inherit the trustworthiness of the root chain. Major software companies like Microsoft, Apple, Mozilla, Google, Oracle have their Root Programs to store root certificates. Root stores are certificates installed in operating systems.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Intermediate certificates: CAs don't issue server certificates directly from a root certificate. They usually sign an intermediate certificate with its private key. As mentioned earlier, the certificate inherits the trustworthiness of a parent. This process can be repeated multiple times to form a certificate chain. The end-user certificate or Leaf certificate is usually signed by an intermediate certificate. There is a huge risk involved in signing with root - it's easier to revoke an intermediate certificate.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Leaf Certificate: this refers to certificates that cannot be used to sign other certificates. SSL/TLS server certificates are usually leaf certificates.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Self Signed Certificates: lastly, if a certificate is not signed by a CA, then it's a self-signed certificate. Self-signed certificates can be created using tools like Apples' Keychain, OpenSSL, and Java's Keytool. Self-signed certificates are useful for testing. However, they are susceptible to Man-in-the-Middle (MiTM) attacks. It's advised to avoid self-signed certificates in production.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Certificate Chain
&lt;/h3&gt;

&lt;p&gt;As mentioned earlier, a CA doesn't sign a leaf certificate with its root. A complex chain of intermediate certificates is established, with each intermediate certificate inheriting the trustworthiness of its parent. &lt;/p&gt;

&lt;p&gt;Usually, while connecting to a secure server, the client downloads the server certificate. Unless the certificate is self-signed, the certificate used to sign a leaf certificate is downloaded. If the intermediate certificate is not root, then the process is repeated. If the final certificate is a root certificate and it is verified, the entire chain of certificates is trusted and hence the connection is trusted. If the root is not verified or if the last certificate is not a root certificate, then the chain is untrusted.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://jscrambler.com/signup?utm_source=dev.to&amp;amp;utm_medium=referral&amp;amp;utm_campaign=ssl-pinning"&gt;&lt;img alt="Try Jscrambler For Free" src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fmedia.jscrambler.com%2Fblog%2FV1-freetrial.jpg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Pinning
&lt;/h2&gt;

&lt;p&gt;HTTPS traffic can potentially be intercepted by installing malicious CA certificates in a device. Tools like OWASP ZAP, Burp, and mitmproxy auto-generate CAs to intercept traffic from the browser. Usually, malicious actors use social engineering to install rogue CAs on devices. Unlike home computers, it's relatively easier to install certificates on mobiles. Commonly, WiFi hotspots can be used to install such rogue CAs.&lt;/p&gt;

&lt;p&gt;We can use certificate pinning to add an extra layer of defense. Certificate pinning is a technique with which we can directly associate the host/app to a certificate or its public key instead of accepting any certificate signed by a trusted CA. By revoking trust from CA, we are reducing the attack surface. As such, even if an attacker manages to install a rogue CA on a device, he won't be able to intercept traffic easily. The best practice is to pin the server's leaf certificate. However, a developer can choose to pin an intermediate certificate to increase compatibility. This will allow us to change the server's leaf certificate periodically - but it also increases the attack surface. &lt;/p&gt;

&lt;p&gt;We can implement pinning in two ways.&lt;/p&gt;

&lt;p&gt;First, we can directly pin the certificate by bundling the certificate in our apps. However, once the certificate expires, a transition plan will have to be implemented beforehand. Once the certificate expires, older apps will throw errors.&lt;/p&gt;

&lt;p&gt;Second, we can pin the Public Key of the certificate. By pinning a public key, we won't have to worry about the certificate expiring as long as the public key remains the same. We can pin multiple certificates - such an arrangement is known as a pinset.&lt;/p&gt;

&lt;p&gt;Let's take a look at commonly used plugins in React Native and Ionic.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pinning in React Native.
&lt;/h3&gt;

&lt;p&gt;In a previous &lt;a href="https://blog.jscrambler.com/securing-react-native-applications/" rel="noopener noreferrer"&gt;article&lt;/a&gt;, we have mentioned plugins that can be used for certificate pinning. We will list them here again.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/MaxToyberman/react-native-ssl-pinning#" rel="noopener noreferrer"&gt;react-native-ssl-pinning&lt;/a&gt;: This plugin uses OkHttp3 on Android and AFNetworking on iOS to provide SSL pinning and cookie handling. It supports both Certificate and Public Key Pinning. We will be using &lt;code&gt;fetch&lt;/code&gt; from the library to consume APIs. This library uses promises and supports multi-part form data. It has support for React Native 0.60 and above. &lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/localz/react-native-pinch" rel="noopener noreferrer"&gt;react-native-pinch&lt;/a&gt;: React Native Pinch is used to pin certificates. Both callbacks and promises are supported.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/approov/react-native-cert-pinner" rel="noopener noreferrer"&gt;react-native-cert-pinner&lt;/a&gt;: This plugin allows us to pin the public key. Unlike the plugins above, we can use &lt;code&gt;fetch&lt;/code&gt; and other utilities directly. The pinning occurs before native JS is run. Also, there is no requirement to define hashes in the request itself.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://github.com/equinor/react-native-trustkit" rel="noopener noreferrer"&gt;react-native-trustkit&lt;/a&gt;: this is a wrapper plugin for the iOS &lt;a href="https://github.com/datatheorem/TrustKit" rel="noopener noreferrer"&gt;Trustkit&lt;/a&gt; library. This library is available for iOS only.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Pinning in Ionic Apps
&lt;/h3&gt;

&lt;p&gt;Currently, certificate pinning is only available via &lt;a href="https://github.com/silkimen/cordova-plugin-advanced-http" rel="noopener noreferrer"&gt;cordova-plugin-advanced-http&lt;/a&gt;. Advanced HTTP is a versatile plugin that can be used to perform complex HTTP operations like SSL pinning, certificate-based auth, and complex file operations.&lt;/p&gt;

&lt;h3&gt;
  
  
  Pinning Caveats
&lt;/h3&gt;

&lt;p&gt;Theoretically, pinning secures the connection between the client (app) and the server. Practically, rogue pinsets can be inserted via tampered apps. Therefore, it's advisable to use Pinning with Attestation Checks like &lt;a href="https://blog.jscrambler.com/extended-guide-to-safetynet/?utm_source=dev.to&amp;amp;utm_medium=referral&amp;amp;utm_campaign=ssl-pinning"&gt;SafetyNet&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If the pinned certificate changes regularly, the application has to be updated too. App Store updates can take multiple days and have a certain level of uncertainty involved. This may cause unintended service outages to end-users.&lt;/p&gt;




&lt;p&gt;While this article was more focused on network security, you should protect your JavaScript source code as well. See our tutorials on protecting &lt;a href="https://blog.jscrambler.com/protecting-your-react-js-source-code-with-jscrambler/?utm_source=dev.to&amp;amp;utm_medium=referral&amp;amp;utm_campaign=ssl-pinning"&gt;React&lt;/a&gt;, &lt;a href="https://blog.jscrambler.com/how-to-protect-angular-code-against-theft-and-reverse-engineering/?utm_source=dev.to&amp;amp;utm_medium=referral&amp;amp;utm_campaign=ssl-pinning"&gt;Angular&lt;/a&gt;, &lt;a href="https://blog.jscrambler.com/how-to-protect-your-vue-js-application-with-jscrambler/?utm_source=dev.to&amp;amp;utm_medium=referral&amp;amp;utm_campaign=ssl-pinning"&gt;Vue&lt;/a&gt;, &lt;a href="https://blog.jscrambler.com/how-to-protect-react-native-apps-with-jscrambler/?utm_source=dev.to&amp;amp;utm_medium=referral&amp;amp;utm_campaign=ssl-pinning"&gt;React Native&lt;/a&gt;, &lt;a href="https://blog.jscrambler.com/protecting-hybrid-mobile-apps-with-ionic-and-jscrambler/?utm_source=dev.to&amp;amp;utm_medium=referral&amp;amp;utm_campaign=ssl-pinning"&gt;Ionic&lt;/a&gt;, and &lt;a href="https://blog.jscrambler.com/protecting-your-nativescript-source-code-with-jscrambler/?utm_source=dev.to&amp;amp;utm_medium=referral&amp;amp;utm_campaign=ssl-pinning"&gt;NativeScript&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>security</category>
      <category>webdev</category>
      <category>ssl</category>
    </item>
    <item>
      <title>Authentication &amp; Authorization in Web Apps</title>
      <dc:creator>Karan Gandhi</dc:creator>
      <pubDate>Thu, 02 Apr 2020 16:45:30 +0000</pubDate>
      <link>https://dev.to/jscrambler/authentication-authorization-in-web-apps-52l6</link>
      <guid>https://dev.to/jscrambler/authentication-authorization-in-web-apps-52l6</guid>
      <description>&lt;p&gt;Most modern applications require individuals to verify their identity. Authentication is the process of verifying the identity of an individual. A user can interact with a web application using multiple actions. Access to certain actions or pages can be restricted using user levels. Authorization is the process of controlling user access via assigned roles &amp;amp; privileges.&lt;/p&gt;

&lt;p&gt;In this post, we will be covering some Authentication &amp;amp; Authorization concepts as well as security recommendations.&lt;/p&gt;

&lt;h2&gt;
  
  
  Authentication
&lt;/h2&gt;

&lt;p&gt;As mentioned before, authentication is the process of verifying identity. A unique identifier is associated with a user which is the username or userid. Traditionally, we use a combination of username and password to authenticate a user. The authentication logic has to be maintained locally so we will term it local authentication. Apart from local authentication, we can use OpenID, Oauth &amp;amp; SAML can also be used as Auth providers. Let's cover them step by step.&lt;/p&gt;

&lt;h3&gt;
  
  
  Local Authentication
&lt;/h3&gt;

&lt;p&gt;The most common authentication technique is using a username and password.&lt;br&gt;&lt;br&gt;
The common flow while implementing it is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The user registers using an identifier like username/email/mobile;&lt;/li&gt;
&lt;li&gt;The application stores user credentials in the database;&lt;/li&gt;
&lt;li&gt;The application sends a verification email/message to validate the registration;&lt;/li&gt;
&lt;li&gt;Post successful registration, the user enters credentials for logging in;&lt;/li&gt;
&lt;li&gt;On successful authentication, the user is allowed access to specific resources;&lt;/li&gt;
&lt;li&gt;The user state is maintained via &lt;a href="https://blog.jscrambler.com/best-practices-for-secure-session-management-in-node/"&gt;Sessions&lt;/a&gt; or JWT.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  OpenID / OAuth
&lt;/h3&gt;

&lt;p&gt;OpenID is an authentication protocol that allows us to authenticate users without using a local auth system. In such a scenario, a user has to be registered with an OpenID Provider and the same provider should be integrated with our authentication flow. To verify the details, we have to forward the authentication requests to the provider. On successful authentication, we receive a success message and/or profile details with which we can execute the necessary flow.&lt;/p&gt;

&lt;p&gt;OAuth is an authorization mechanism that allows our application user access to a provider. On successful response, we receive a token with which we can access certain APIs on behalf of a user. OAuth is convenient in case your business use case requires some certain user-facing APIs like access to Google Drive or sending tweets on your behalf. Most OAuth 2.0 providers can be used for pseudo authentication. Having said that, it can get pretty complicated if you are using multiple OAuth providers to authenticate users on top of the local authentication system.  &lt;/p&gt;
&lt;h3&gt;
  
  
  Multi-Factor Authentication
&lt;/h3&gt;

&lt;p&gt;Users are generally recommended to have different passwords for different websites or use password managers to secure their identity. However, in reality, a major chunk of people reuse their passwords. This makes them vulnerable to credential sniffing (as this &lt;a href="https://xkcd.com/792/"&gt;XKCD comic&lt;/a&gt; brilliantly explains). If an attacker has access to unsalted passwords from a &lt;a href="https://haveibeenpwned.com/"&gt;dump of breached applications&lt;/a&gt; then he can use it to log in to our application.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://services.google.com/fh/files/blogs/google_security_infographic.pdf"&gt;&lt;img alt="Google Survey" src="https://res.cloudinary.com/practicaldev/image/fetch/s--qUwvqWLc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://blog.jscrambler.com/content/images/2020/04/jscrambler-blog-authentication-authorization-in-web-apps-password-reuse-statistics.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To reduce the risk we can implement multi-factor authentication in our application. Multi-Factor authentication is when a user is authenticated using two or more factors as authentication methods. The factors are listed below.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Factor&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Something You Know&lt;/td&gt;
&lt;td&gt;Passwords, PINs, TAN, security questions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Something You Have&lt;/td&gt;
&lt;td&gt;USB keys, Software tokens, certificates, email, SMS, phone calls.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Something You Are&lt;/td&gt;
&lt;td&gt;Biometrics(fingerprints/iris scans, Facial Recognition), typing speed, key pattern interval&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Location&lt;/td&gt;
&lt;td&gt;Source IP ranges and geolocation&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The common second factors implemented in applications are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Email &lt;/li&gt;
&lt;li&gt;OTP via SMS / Phones &lt;/li&gt;
&lt;li&gt;TOTP (Time-based OTP) apps like Google Authenticator / Authy&lt;/li&gt;
&lt;li&gt;x.509 certificates&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The location-based factor is used to implement geographical restrictions.  IP addresses can be used to allow/block users from certain countries. This is common practice in streaming and banking applications. It's easier to access geographical data from a mobile phone or any GPS enabled device.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://fidoalliance.org/what-is-fido/"&gt;FIDO2&lt;/a&gt;-compliant biometric devices and USB keys can leverage WebAuthn API to handle the authentication. &lt;a href="https://fidoalliance.org/fido2/fido2-web-authentication-webauthn/"&gt;WebAuthn&lt;/a&gt; is a new browser API that makes it easier to implement a second factor for authentication.&lt;/p&gt;
&lt;h3&gt;
  
  
  Mobile Device User Authentication vs User Authentication
&lt;/h3&gt;

&lt;p&gt;This is a somewhat newer scenario. Under most circumstances, we login to our mobile phones using our Google/iCloud accounts. As a device user, the account can store our private data, has access to multiple apps with persistent logins and is associated with multiple payment providers. There can be a case where our application user and the device user can be different.&lt;/p&gt;

&lt;p&gt;While executing a critical transaction, we would like to associate a device owner with our application user OR we would like a device owner to authenticate the application users. In such cases, we have to add an extra layer of security. On Android, we can use &lt;a href="https://developer.android.com/training/sign-in/biometric-auth"&gt;biometric auth&lt;/a&gt; and  &lt;a href="https://developer.android.com/reference/android/app/KeyguardManager"&gt;keyguard manager&lt;/a&gt;. On iOS, we can use &lt;a href="https://developer.apple.com/documentation/localauthentication"&gt;Local Authentication&lt;/a&gt; to verify the device user.&lt;/p&gt;
&lt;h3&gt;
  
  
  Authentication Libraries
&lt;/h3&gt;

&lt;p&gt;Let’s take a look at common Node.JS authentication libraries.&lt;/p&gt;
&lt;h3&gt;
  
  
  PassportJS
&lt;/h3&gt;

&lt;p&gt;&lt;a href="http://www.passportjs.org/"&gt;PassportJS&lt;/a&gt; is one of the most popular auth libraries for Express. Apart from Local Authentication, Passport has support for OpenID, OAuth 1.0, SAML and OAuth 2.0.&lt;/p&gt;

&lt;p&gt;There are around 500 providers/strategies which can be used with Passport. You can check our recent tutorial which covers Passport &lt;a href="https://blog.jscrambler.com/setting-up-authentication-using-angular-node-and-passport/"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Grant
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/simov/grant"&gt;Grant&lt;/a&gt; is another auth library. It has support for Express, Hapi and Koa. Like Passport, &lt;code&gt;grant&lt;/code&gt; supports OpenID connect OAuth 1.0a &amp;amp; OAuth 2.0. There are currently 180 supported providers.&lt;/p&gt;
&lt;h3&gt;
  
  
  Firebase Authentication
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://firebase.google.com/docs/auth/"&gt;Firebase Auth&lt;/a&gt; has limited OAuth providers (Facebook, Github, Twitter, Google, Apple, Microsoft). However, it does provide Auth for email login, anonymous login, and phone number login.&lt;/p&gt;

&lt;p&gt;A full authentication workflow is provided by the Firebase Auth API. Also, we can link Multiple OAuth users to a single user. Coupled with other Firebase products (Push, Database, Storage, Hosting, Crashlytics, Functions), this can be a very good fit for small projects.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://jscrambler.com/signup?utm_source=dev.to&amp;amp;utm_medium=referral&amp;amp;utm_campaign=authentication-authorization"&gt;&lt;img alt="Try Jscrambler For Free" src="https://res.cloudinary.com/practicaldev/image/fetch/s--vh1vlUdJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://media.jscrambler.com/blog/V1-freetrial.jpg"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Authentication through OWASP's Lens
&lt;/h3&gt;

&lt;p&gt;Broken Authentication is ranked #2 in &lt;a href="https://owasp.org/www-project-top-ten/OWASP_Top_Ten_2017/Top_10-2017_A2-Broken_Authentication"&gt;OWASP Top 10&lt;/a&gt; and #4 in &lt;a href="https://owasp.org/www-project-mobile-top-10/2016-risks/m4-insecure-authentication"&gt;OWASP Mobile Top 10&lt;/a&gt;. From OWASP itself:&lt;/p&gt;

&lt;p&gt;Confirmation of the user’s identity, authentication, and session management is critical to protect against authentication-related attacks. &lt;/p&gt;

&lt;p&gt;There may be authentication weaknesses if the application:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Permits automated attacks such as credential stuffing, where the attacker has a list of valid usernames and passwords.&lt;/li&gt;
&lt;li&gt;Permits brute force or other automated attacks.&lt;/li&gt;
&lt;li&gt;Permits default, weak, or well-known passwords, such as “Password1” or “admin/admin“.&lt;/li&gt;
&lt;li&gt;Uses weak or ineffective credential recovery and forgot-password processes, such as “knowledge-based answers”, which cannot be made safe.&lt;/li&gt;
&lt;li&gt;Uses plain text, encrypted, or weakly hashed passwords (see A3:2017-Sensitive Data Exposure).&lt;/li&gt;
&lt;li&gt;Has missing or ineffective multi-factor authentication.&lt;/li&gt;
&lt;li&gt;Exposes Session IDs in the URL (e.g., URL rewriting).&lt;/li&gt;
&lt;li&gt;Does not rotate Session IDs after successful login.&lt;/li&gt;
&lt;li&gt;Does not properly invalidate Session IDs. User sessions or authentication tokens (particularly single sign-on (SSO) tokens) &amp;gt;* aren’t properly invalidated during logout or a period of inactivity.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Taken these points into account, we can strengthen our application by:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hashing and salting the passwords - plaintext passwords are a huge security risk. Use libraries like &lt;code&gt;bcrypt&lt;/code&gt; to implement hashes with the &lt;a href="https://security.stackexchange.com/questions/3959/recommended-of-iterations-when-using-pkbdf2-sha256/3993#3993"&gt;maximum rounds&lt;/a&gt; your CPU can afford (also, check this blog post for further reading on &lt;a href="https://blog.jscrambler.com/hashing-algorithms/"&gt;hashing algorithms&lt;/a&gt;);&lt;/li&gt;
&lt;li&gt;Using password strength estimators like &lt;a href="https://www.npmjs.com/package/owasp-password-strength-test"&gt;owasp-password-strength-test&lt;/a&gt; to enforce a strong password policy;&lt;/li&gt;
&lt;li&gt;Not truncating the passwords;&lt;/li&gt;
&lt;li&gt;Notifying users to update passwords regularly;&lt;/li&gt;
&lt;li&gt;Reauthenticating users while performing a critical transaction like payment or account update;&lt;/li&gt;
&lt;li&gt;Transmitting passwords over TLS (https) only;&lt;/li&gt;
&lt;li&gt;Not leaking any information in error messages. &lt;code&gt;Login failed. Password for user Karan is wrong&lt;/code&gt; is a bad message. &lt;code&gt;Login failed: Invalid user or password&lt;/code&gt; is a good message.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For resetting passwords, we will take the following points into consideration:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Send an email to the user;&lt;/li&gt;
&lt;li&gt;Create a temporary session for a password reset;&lt;/li&gt;
&lt;li&gt;Do not display user credentials on screen;&lt;/li&gt;
&lt;li&gt;Verify the user using security questions / TOTP codes;&lt;/li&gt;
&lt;li&gt;Redirect the user to a form;&lt;/li&gt;
&lt;li&gt;Change the password in the same session.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So far, we have covered some techniques and best practices associated with Authentication. Now, let's look at Authorization.&lt;/p&gt;
&lt;h2&gt;
  
  
  Authorization
&lt;/h2&gt;

&lt;p&gt;Authorization is a process with which we can allow or restrict resources. Depending on the business logic, the requirement of user authorization can vary. &lt;/p&gt;

&lt;p&gt;Let's take a CMS as an example.  Blog readers can read content without authentication. To create a post in the blog, a user will have to sign up as an author. To publish a post, the user must have editor privileges. To make site-wide changes he must have Administrator privileges. &lt;/p&gt;

&lt;p&gt;In this example, user authentication is not required to read a post but it's required to publish one. &lt;/p&gt;

&lt;p&gt;For the sake of this example let’s define &amp;amp; assign some routes.&lt;/p&gt;

&lt;p&gt;The reader role has access to &lt;code&gt;/blog routes&lt;/code&gt; &amp;amp; can read all published posts. The author role has access to &lt;code&gt;/blog/posts&lt;/code&gt; routes &amp;amp; can write a post. The editor role has access to &lt;code&gt;/blog/editor&lt;/code&gt; routes &amp;amp; can publish posts. The administrator role has access to &lt;code&gt;/blog/admin&lt;/code&gt; routes &amp;amp; can do whatever he wants. &lt;/p&gt;

&lt;p&gt;Let's assume the business expands and there is a requirement for separate Security &amp;amp; JS editors.&lt;/p&gt;

&lt;p&gt;Now, in an enhanced role:&lt;/p&gt;

&lt;p&gt;Security Editor has access to &lt;code&gt;/blog/editor&lt;/code&gt; but can only publish posts marked with &lt;code&gt;security&lt;/code&gt; tag. JS Editor has access to &lt;code&gt;/blog/editor&lt;/code&gt; but can only publish posts marked with &lt;code&gt;js&lt;/code&gt; tag. Global Editor has access to &lt;code&gt;/blog/editor&lt;/code&gt; and can publish posts with all tags.&lt;/p&gt;

&lt;p&gt;Let's expand the scenario further. A chief editor is chosen from 10 editors. One of the additional duties of the chief editor is to create reports for the authors. This action is usually assigned to administrators. The developer creates a custom action and adds the privilege to a user. The chief editor can now create reports using the &lt;code&gt;/blog/reports&lt;/code&gt; route.&lt;/p&gt;

&lt;p&gt;Post registration, a user can be assigned certain roles like Author or Editor. The author role doesn't have access to &lt;code&gt;/posts/editor&lt;/code&gt;, so he is authenticated but not authorized. In enhanced role management, two new sub-roles were created which had authorization levels of an editor but with restriction placed with help of tags. This is roughly the basis of any authorization scenario: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create defined roles as per specific use cases.&lt;/li&gt;
&lt;li&gt;Extend or restrict certain roles depending on use cases&lt;/li&gt;
&lt;li&gt;Assign custom actions to a user to fine grain.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Implementing Authorized Routes (Express / Angular)
&lt;/h3&gt;

&lt;p&gt;Consider a function Auth which checks user authentication.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function Auth(){
  ...
    return auth.role; 
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can implement Auth middleware in express using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;checkAuth&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;Auth&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Editor&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;redirect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/blog&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/blog/editor&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;checkAuth&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Success&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Angular has the &lt;code&gt;CanActivate&lt;/code&gt; interface which acts as a Route Guard. First, we define an &lt;code&gt;AuthRouteGuard&lt;/code&gt; class:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;CanActivate&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/router&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Injectable&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/core&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


&lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;Injectable&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;AuthRouteGuard&lt;/span&gt; &lt;span class="k"&gt;implements&lt;/span&gt; &lt;span class="nx"&gt;CanActivate&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

  &lt;span class="nx"&gt;canActivate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Auth&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;Auth&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;editor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In Route config, we define:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Routes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;CanActivate&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@angular/router&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;EditorPage&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./angular/editor-page&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;AuthRouteGuard&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./auth-route-guard&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;ROUTES&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Routes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; 
  &lt;span class="p"&gt;{&lt;/span&gt; 
    &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;protected&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;component&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;ProtectedPage&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;canActivate&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;AuthRouteGuard&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; 
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;**&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;redirectTo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When &lt;code&gt;CanActivate&lt;/code&gt; returns true, the user can activate the route. We have to define auth logic in the Auth() or in a separate service. &lt;/p&gt;

&lt;p&gt;In the Express snippet, we are blocking disallowed access to a specific user role (Editor). In the Angular snippet, we have assumed a boolean &lt;code&gt;editor.status&lt;/code&gt; which is a custom privilege assigned to every user.&lt;/p&gt;

&lt;h3&gt;
  
  
  Authorization through OWASP's Lens
&lt;/h3&gt;

&lt;p&gt;The most common attack associated with Authorization is privilege escalation. An example of this would be an author discovering a vulnerability and publishing Java tutorials on a JavaScript blog.&lt;/p&gt;

&lt;p&gt;Broken Access Control in &lt;a href="https://owasp.org/www-project-top-ten/OWASP_Top_Ten_2017/Top_10-2017_A5-Broken_Access_Control"&gt;OWASP Top Ten&lt;/a&gt; &amp;amp; Insecure Authorization in &lt;a href="https://owasp.org/www-project-mobile-top-10/2016-risks/m6-insecure-authorization"&gt;OWASP Mobile Top Ten&lt;/a&gt; are the risks associated with Authorization.&lt;/p&gt;

&lt;p&gt;As OWASP puts it:&lt;/p&gt;

&lt;p&gt;Access control enforces policy such that users cannot act outside of their intended permissions. Failures typically lead to unauthorized information disclosure, modification or destruction of all data, or performing a business function outside of the limits of the user. Common access control vulnerabilities include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Bypassing access control checks by modifying the URL, internal application state, or the HTML page, or simply using a custom API attack tool.&lt;/li&gt;
&lt;li&gt;Allowing the primary key to be changed to another’s users' record, permitting viewing or editing someone else’s account.&lt;/li&gt;
&lt;li&gt;Elevation of privilege. Acting as a user without being logged in, or acting as an admin when logged in as a user.&lt;/li&gt;
&lt;li&gt;Metadata manipulation, such as replaying or tampering with a JSON Web Token (JWT) access control token or a cookie or hidden field manipulated to elevate privileges, or abusing JWT invalidation&lt;/li&gt;
&lt;li&gt;CORS misconfiguration allows unauthorized API access.&lt;/li&gt;
&lt;li&gt;Force browsing to authenticated pages as an unauthenticated user or privileged pages as a standard user. Accessing API with missing access controls for POST, PUT and DELETE.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To strengthen Authorization, we should:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;code&gt;Reject-All&lt;/code&gt; strategy for everything except public routes. &lt;/li&gt;
&lt;li&gt;Implement logging for all privileged actions&lt;/li&gt;
&lt;li&gt;Invalidate sessions &amp;amp; tokens after logout/timeout.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;In this article, we have covered some concepts of Authentication &amp;amp; Authorization. Authentication is still a major security risk. OWASP features it as an A2 risk in the &lt;a href="https://owasp.org/www-project-top-ten/OWASP_Top_Ten_2017/Top_10-2017_Top_10"&gt;OWASP Top Ten Web Application Security Risks&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As a developer, it's important to invest in secure coding practices. Web attacks are growing and extra efforts have to be made to secure Web apps.&lt;/p&gt;




&lt;p&gt;Besides the topics we covered here today, another important security practice in web apps is protecting their JavaScript source code. See our tutorials on protecting &lt;a href="https://blog.jscrambler.com/protecting-your-react-js-source-code-with-jscrambler/?utm_source=dev.to&amp;amp;utm_medium=referral&amp;amp;utm_campaign=authentication-authorization"&gt;React&lt;/a&gt;, &lt;a href="https://blog.jscrambler.com/how-to-protect-angular-code-against-theft-and-reverse-engineering/?utm_source=dev.to&amp;amp;utm_medium=referral&amp;amp;utm_campaign=authentication-authorization"&gt;Angular&lt;/a&gt;, &lt;a href="https://blog.jscrambler.com/how-to-protect-your-vue-js-application-with-jscrambler/?utm_source=dev.to&amp;amp;utm_medium=referral&amp;amp;utm_campaign=authentication-authorization"&gt;Vue&lt;/a&gt;, &lt;a href="https://blog.jscrambler.com/how-to-protect-react-native-apps-with-jscrambler/?utm_source=dev.to&amp;amp;utm_medium=referral&amp;amp;utm_campaign=authentication-authorization"&gt;React Native&lt;/a&gt;, &lt;a href="https://blog.jscrambler.com/protecting-hybrid-mobile-apps-with-ionic-and-jscrambler/?utm_source=dev.to&amp;amp;utm_medium=referral&amp;amp;utm_campaign=authentication-authorization"&gt;Ionic&lt;/a&gt;, and &lt;a href="https://blog.jscrambler.com/protecting-your-nativescript-source-code-with-jscrambler/?utm_source=dev.to&amp;amp;utm_medium=referral&amp;amp;utm_campaign=authentication-authorization"&gt;NativeScript&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>security</category>
      <category>node</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Securing React Native Applications</title>
      <dc:creator>Karan Gandhi</dc:creator>
      <pubDate>Mon, 24 Feb 2020 15:41:52 +0000</pubDate>
      <link>https://dev.to/jscrambler/securing-react-native-applications-4a1e</link>
      <guid>https://dev.to/jscrambler/securing-react-native-applications-4a1e</guid>
      <description>&lt;p&gt;React Native is a popular &lt;a href="https://blog.jscrambler.com/react-native-vs-ionic-vs-nativescript-a-practical-guide/?utm_source=dev.to&amp;amp;utm_medium=referral&amp;amp;utm_campaign=securing-react-native"&gt;cross-platform JavaScript framework&lt;/a&gt;. Components of React Native apps are rendered in Native UI. In this article, we will focus on the security side of the framework. &lt;/p&gt;

&lt;h3&gt;
  
  
  Analyzing React Native
&lt;/h3&gt;

&lt;p&gt;React Native has an alternative approach for cross-platform development. Traditionally, &lt;a href="https://blog.jscrambler.com/introduction-to-ionic-4/?utm_source=dev.to&amp;amp;utm_medium=referral&amp;amp;utm_campaign=securing-react-native"&gt;Cordova-based frameworks&lt;/a&gt; used WebView to render the whole application. In contrast, React Native applications run the JS code in a JavaScript VM based on JavaScriptCore. The application uses native JavaScriptCore on iOS and JavaScriptCore libs are bundled on an APK on Android.&lt;/p&gt;

&lt;p&gt;In React Native, the communication between Native and JavaScript code is handled by a JavaScript Bridge. The source JS files are compiled into one single bundle file known as &lt;code&gt;entry-file&lt;/code&gt;. In development mode, the file is bundled on a local server and fetched by the application. For production, the application logic is usually bundled in a single file, usually &lt;code&gt;index.android.bundle&lt;/code&gt; or &lt;code&gt;index.ios.bundle&lt;/code&gt;. Similarly to Cordova, the bundle file is present in the &lt;code&gt;assets&lt;/code&gt; folder and, as also happens with Cordova, we can assume React Native apps as containers that run JS code. This logic is implemented in &lt;code&gt;expo&lt;/code&gt;. Under certain limitations, Expo can run different business logic in a single application. At this moment, it's fair to assume the &lt;code&gt;entry-file&lt;/code&gt; as the core application logic. &lt;/p&gt;

&lt;p&gt;We will be dividing the article into the following sections:  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Securing app to server connection&lt;/li&gt;
&lt;li&gt;Securing local data &lt;/li&gt;
&lt;li&gt;Advanced integrity checks &lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Securing App to Server Connection
&lt;/h2&gt;

&lt;p&gt;Usually, smartphone apps communicate with the backend server via APIs. Insecure Communication is highlighted in the OWASP Mobile Top 10 at #3: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Mobile applications frequently do not protect network traffic. They may use SSL/TLS during authentication but not elsewhere. This inconsistency leads to the risk of exposing data and session IDs to interception. The use of transport security does not mean the app has implemented it correctly. To detect basic flaws, observe the phone's network traffic. More subtle flaws require inspecting the design of the application and the applications configuration. - &lt;a href="https://www.owasp.org/index.php/Mobile_Top_10_2016-M3-Insecure_Communication" rel="noopener noreferrer"&gt;M3-Insecure Communication&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Starting from iOS 9 and Android Pie, SSL is required by default. We can enable cleartext traffic but it's not recommended. To secure the connection further, we can pin our server certificates.&lt;/p&gt;

&lt;h3&gt;
  
  
  SSL Pinning in React Native
&lt;/h3&gt;

&lt;p&gt;Apps are dependent on Certificate Authorities (CA) and Domain Name Servers (DNS) to validate domains for TLS. Unsafe certificates can be installed on a user device, thereby opening the device to a Man-in-the-Middle attack. SSL pinning can be used to mitigate this risk.&lt;/p&gt;

&lt;p&gt;We use the &lt;code&gt;fetch&lt;/code&gt; API or libraries like &lt;code&gt;axios&lt;/code&gt; or &lt;code&gt;frisbee&lt;/code&gt; to consume APIs in our React Native applications. However, these libraries don't have support for SSL pinning. Let's explore the available plugins. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/MaxToyberman/react-native-ssl-pinning#" rel="noopener noreferrer"&gt;react-native-ssl-pinning&lt;/a&gt;: this plugin uses OkHttp3 on Android and AFNetworking on iOS to provide SSL pinning and cookie handling. In this case, we will be using &lt;code&gt;fetch&lt;/code&gt; from the library to consume APIs. For this library, we will have to bundle the certificates inside the app. Necessary error handling needs to be implemented in older apps to handle certificate expiry. The app needs to be updated with newer certificates before certificates expire. This library uses promises and supports multi-part form data.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/localz/react-native-pinch" rel="noopener noreferrer"&gt;react-native-pinch&lt;/a&gt;: this plugin is similar to &lt;code&gt;react-native-ssl-pinning&lt;/code&gt;. We have to bundle certificates inside the app. This library supports both promises and callbacks.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To use HPKP (Http Public Key Pinning), we can consider these plugins:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/approov/react-native-cert-pinner" rel="noopener noreferrer"&gt;react-native-cert-pinner&lt;/a&gt;: this plugin allows us to use public hashes to pin the server. Unlike the plugins above, we can use &lt;code&gt;fetch&lt;/code&gt; and other utilities directly. The pinning occurs before native JS is run. Also, there is no requirement to define hashes in the request itself.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/equinor/react-native-trustkit" rel="noopener noreferrer"&gt;react-native-trustkit&lt;/a&gt;: this is a wrapper plugin for the iOS &lt;a href="https://github.com/datatheorem/TrustKit" rel="noopener noreferrer"&gt;Trustkit&lt;/a&gt; library. This library is available for iOS only.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Alternatively, we can use native implementations as outlined by Javier Muñoz. He has implemented pinning for &lt;a href="https://medium.com/@jaedmuva/react-native-ssl-pinning-is-back-e317e6682642" rel="noopener noreferrer"&gt;Android&lt;/a&gt; and &lt;a href="https://medium.com/@jaedmuva/react-native-ssl-pinning-is-back-ios-version-814dfce2400c" rel="noopener noreferrer"&gt;iOS&lt;/a&gt; natively.&lt;/p&gt;

&lt;h2&gt;
  
  
  Securing Local Storage
&lt;/h2&gt;

&lt;p&gt;Quite often, we store data inside our application. There are multiple ways to store persistent data in React Native. &lt;code&gt;Async-storage&lt;/code&gt;, &lt;code&gt;sqlite&lt;/code&gt;, &lt;code&gt;pouchdb&lt;/code&gt; and &lt;code&gt;realm&lt;/code&gt; are some of the methods to store data. Insecure storage is highlighted at #2 in the OWASP Mobile Top 10:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Insecure data storage vulnerabilities occur when development teams assume that users or malware will not have access to a mobile device's filesystem and subsequent sensitive information in data-stores on the device. Filesystems are easily accessible. Organizations should expect a malicious user or malware to inspect sensitive data stores. Usage of poor encryption libraries is to be avoided. Rooting or jailbreaking a mobile device circumvents any encryption protections. When data is not protected properly, specialized tools are all that is needed to view application data. - &lt;a href="https://www.owasp.org/index.php/Mobile_Top_10_2016-M2-Insecure_Data_Storage" rel="noopener noreferrer"&gt;M2-Insecure Data Storage&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let's take a look at some plugins which add a layer of security to our application.  Also, we will be exploring some plugins which use native security features like &lt;code&gt;Keychain&lt;/code&gt; &amp;amp; &lt;code&gt;Keystore Access&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  SQLite
&lt;/h3&gt;

&lt;p&gt;SQLite is the most common way to store data. A very popular and open-source extension for SQLite encryption is &lt;a href="https://www.zetetic.net/sqlcipher/design/" rel="noopener noreferrer"&gt;SQLCipher&lt;/a&gt;. Data in SQLCipher is encrypted via 256 bit AES which can't be read without a key. React Native has two libraries that provide SQLCipher:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/sreejithkrishnanr/react-native-sqlcipher-2" rel="noopener noreferrer"&gt;react-native-sqlcipher-2&lt;/a&gt; : this is a fork of &lt;a href="https://github.com/craftzdog/react-native-sqlite-2" rel="noopener noreferrer"&gt;react-native-sqlite-2&lt;/a&gt;. We can use &lt;code&gt;pouchdb&lt;/code&gt; as an ORM provider with this library, so it's an additional bonus.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/axsy-dev/react-native-sqlcipher-storage" rel="noopener noreferrer"&gt;react-native-sqlcipher-storage&lt;/a&gt; : this is a fork of &lt;a href="https://github.com/andpor/react-native-sqlite-storage" rel="noopener noreferrer"&gt;react-native-sqlite-storage&lt;/a&gt;. The library has to be set up manually since it doesn't seem to support &lt;code&gt;react-native link&lt;/code&gt;. Interestingly, the library is based on the Cordova &lt;a href="https://github.com/litehelpers/Cordova-sqlite-storage" rel="noopener noreferrer"&gt;implementation&lt;/a&gt;. &lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Realm
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://realm.io/products/realm-database/" rel="noopener noreferrer"&gt;Realm&lt;/a&gt; is a nice alternative database provider to React Native Apps. It's much faster than SQLite and it has support for encryption by default. It uses the AES256 algorithm and the encrypted realm is verified using SHA-2 HMAC hash. Details of the library can be found &lt;a href="https://github.com/realm/realm-js" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Keychain and Keystore Access
&lt;/h3&gt;

&lt;p&gt;Both iOS and Android have native techniques to store secure data. &lt;a href="https://developer.apple.com/documentation/security/keychain_services" rel="noopener noreferrer"&gt;Keychain services&lt;/a&gt; allows developers to store small chunks of data in an encrypted database. On Android, most plugins use the &lt;a href="https://developer.android.com/training/articles/keystore.html" rel="noopener noreferrer"&gt;Android keystore&lt;/a&gt; system for API 23(Marshmallow) and above. For lower APIs, Facebook's &lt;a href="https://github.com/facebook/conceal" rel="noopener noreferrer"&gt;conceal&lt;/a&gt; provides the necessary crypto functions. Another alternative is to store encrypted data in shared preferences. &lt;/p&gt;

&lt;p&gt;React Native has three libraries that provide secure storage along with biometric/face authentication:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/oblador/react-native-keychain" rel="noopener noreferrer"&gt;React Native KeyChain&lt;/a&gt;: as the name implies, this plugin provides access to keychain/keystore. It uses Keychain (iOS), Keystore (Android 23+), and conceal. There is support for Biometric Auth. This plugin has multiple methods and options for both Android and iOS. However, it only allows the storage of the username &amp;amp; password.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/mcodex/react-native-sensitive-info" rel="noopener noreferrer"&gt;React Native Sensitive Info&lt;/a&gt;: this plugin is similar to React Native Keychain. It uses Keychain (iOS) and shared preferences (Android) to store data. We can store multiple key-value pairs using this plugin.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/talut/rn-secure-storage" rel="noopener noreferrer"&gt;RN Secure Storage&lt;/a&gt;: this plugin is similar to React Native Sensitive Info. It uses Keychain (iOS), Keystore (Android 23+), and &lt;a href="https://github.com/scottyab/secure-preferences/" rel="noopener noreferrer"&gt;Secure Preferences&lt;/a&gt; to store data. We can store multiple key-value pairs.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Advanced Integrity Checks
&lt;/h2&gt;

&lt;h3&gt;
  
  
  JailMonkey and SafetyNet
&lt;/h3&gt;

&lt;p&gt;Rooted and jailbroken devices should be considered insecure by intent. Root privileges allow users to circumvent OS security features, spoof data, analyze algorithms, and access secured storage. As a rule of thumb, the execution of the app on a rooted device should be avoided. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/GantMan/jail-monkey" rel="noopener noreferrer"&gt;JailMonkey&lt;/a&gt; allows React Native applications to detect root or jailbreak. Apart from that, it can detect if mock locations can be set using developer tools.&lt;/p&gt;

&lt;p&gt;SafetyNet is an Android-only API for detecting rooted devices and bootloader unlocks. We have covered SafetyNet extensively in a previous &lt;a href="https://blog.jscrambler.com/extended-guide-to-safetynet/?utm_source=dev.to&amp;amp;utm_medium=referral&amp;amp;utm_campaign=securing-react-native"&gt;article&lt;/a&gt;. &lt;a href="https://github.com/rajivshah3/react-native-google-safetynet" rel="noopener noreferrer"&gt;react-native-google-safetynet&lt;/a&gt; is a wrapper plugin for SafetyNet's attestation API. It can be used to verify the user's device.&lt;/p&gt;

&lt;p&gt;Additionally, we can use &lt;a href="https://github.com/react-native-community/react-native-device-info#isemulator" rel="noopener noreferrer"&gt;react-native-device-info&lt;/a&gt; to check if an app is running in an emulator.&lt;/p&gt;

&lt;h2&gt;
  
  
  Protecting the Application Logic
&lt;/h2&gt;

&lt;p&gt;Earlier in the article, we mentioned how the application logic in &lt;code&gt;entry-file&lt;/code&gt; is available in plain sight. In other words, a third-party can retrieve the code, reverse-engineer sensitive logic, or even tamper with the code to abuse the app (such as unlocking features or violating license agreements).&lt;/p&gt;

&lt;p&gt;Protecting the application logic is a recommendation in the OWASP Mobile Top 10. Specifically, the main concerns include code tampering:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Mobile code runs within an environment that is not under the control of the organization producing the code. At the same time, there are plenty of different ways of altering the environment in which that code runs. These changes allow an adversary to tinker with the code and modify it at will. — &lt;a href="https://www.owasp.org/index.php/Mobile_Top_10_2016-M8-Code_Tampering" rel="noopener noreferrer"&gt;M8-Code Tampering&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And reverse engineering:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Generally, most applications are susceptible to reverse engineering due to the inherent nature of code. Most languages used to write apps today are rich in metadata that greatly aides a programmer in debugging the app. This same capability also greatly aides an attacker in understanding how the app works. — &lt;a href="https://www.owasp.org/index.php/Mobile_Top_10_2016-M9-Reverse_Engineering" rel="noopener noreferrer"&gt;M9-Reverse Engineering&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let’s highlight two different strategies to address this risk.&lt;/p&gt;

&lt;h3&gt;
  
  
  Hermes
&lt;/h3&gt;

&lt;p&gt;Facebook introduced &lt;a href="https://facebook.github.io/react-native/docs/hermes" rel="noopener noreferrer"&gt;Hermes&lt;/a&gt; with the react-native 0.60.1 &lt;a href="https://github.com/react-native-community/releases/blob/master/CHANGELOG.md#v0601" rel="noopener noreferrer"&gt;release&lt;/a&gt;. Hermes is a new JavaScript Engine optimized for mobile apps. Currently, it is only available with Android and it’s usage is optional. Hermes can be used in the project with react-native &lt;code&gt;0.60.4&lt;/code&gt; by changing the &lt;code&gt;enableHermes&lt;/code&gt; flag in &lt;code&gt;build.gradle&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Its key benefits are improved start-up time, decreased memory usage, and smaller app size. One of the strategies that Hermes uses to achieve this is precompiling JavaScript to bytecode. At first glance, this appears to make &lt;code&gt;entry-file&lt;/code&gt; unreadable. But let's look at a real example.&lt;/p&gt;

&lt;p&gt;Let's assume that our &lt;code&gt;entry-file&lt;/code&gt; is the one found below:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;createDecipheriv&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;createCipheriv&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;randomBytes&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;crypto&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;60adba1cf391d89a3a71c72a615cbba8&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hex&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;algorithm&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;aes-128-cbc&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;softwareVersion&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;2.0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;expireDate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;expireDate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;softwareVersion&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;json&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;utf8&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;iv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;randomBytes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cipher&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createCipheriv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;algorithm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;iv&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;encoded&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;cipher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;encoded&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;encoded&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cipher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;final&lt;/span&gt;&lt;span class="p"&gt;()]);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;joined&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;iv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hex&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;encoded&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hex&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;joined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;utf8&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;base64&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;validateLicense&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;license&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;licenseFields&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;license&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;base64&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;utf8&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;fields&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;licenseFields&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;;&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;iv&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hex&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hex&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;decipher&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createDecipheriv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;algorithm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;iv&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;decoded&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;decipher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;update&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="nx"&gt;decoded&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;Buffer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;concat&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;decoded&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;decipher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;final&lt;/span&gt;&lt;span class="p"&gt;()]);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;decoded&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Wrong user&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;expireDate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Expired license&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;softwareVersion&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="nx"&gt;softwareVersion&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;This license is not valid for this program version&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;After Hermes compiles this file, the resulting bytecode can easily be decompiled using &lt;a href="https://github.com/facebook/hermes/tree/master/tools/hbcdump" rel="noopener noreferrer"&gt;hbcdump&lt;/a&gt; and, among the decompiled code, we find some easy to read code:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

s0[ASCII, 0..-1]: 
s1[ASCII, 0..2]: 2.0
s2[ASCII, 3..34]: 60adba1cf391d89a3a71c72a615cbba8
s3[ASCII, 35..35]: ;
s4[ASCII, 36..50]: Expired license
s5[ASCII, 71..120]: This license is not valid for this program version
s6[ASCII, 121..130]: Wrong user
s7[ASCII, 133..143]: aes-128-cbc
s8[ASCII, 143..148]: crypto
s9[ASCII, 154..159]: global
s10[ASCII, 160..165]: base64
s11[ASCII, 166..168]: hex
s12[ASCII, 177..180]: utf8
i13[ASCII, 50..56] #C765D706: exports
i14[ASCII, 56..70] #FF849242: softwareVersion
i15[ASCII, 127..132] #6FE51CD4: userId
i16[ASCII, 147..154] #1E019520: toString
i17[ASCII, 167..176] #68A06D42: expireDate
i18[ASCII, 173..176] #CD347266: Date
i19[ASCII, 181..186] #5AA7C487: Buffer
i20[ASCII, 186..196] #FD81EB01: randomBytes
i21[ASCII, 196..200] #0EC469F8: split
i22[ASCII, 201..205] #9102A3D0: Error
i23[ASCII, 205..211] #EB75CA32: require
i24[ASCII, 212..215] #971CE5C7: JSON
i25[ASCII, 216..221] #CB8DFA65: concat
i26[ASCII, 222..235] #96C7181F: createCipheriv
i27[ASCII, 235..249] #D60B6B51: validateLicense
i28[ASCII, 250..265] #723D6A80: createDecipheriv
i29[ASCII, 266..274] #01D3AE7D: createKey
i30[ASCII, 275..279] #47993A63: final
i31[ASCII, 280..283] #EAF03666: from
i32[ASCII, 283..288] #2A322C6E: module
i33[ASCII, 289..293] #958EDB02: parse
i34[ASCII, 294..302] #807C5F3D: prototype
i35[ASCII, 303..311] #8D1543BD: stringify
i36[ASCII, 312..317] #60396F4B: update

Function&amp;lt;global&amp;gt;0(1 params, 15 registers, 4 symbols):
Offset in debug table: src 0x0, vars 0x0
license.js[1:1]
    CreateEnvironment r0
    GetGlobalObject   r1
    TryGetById        r4, r1, 1, "require"
    LoadConstUndefined r3
    LoadConstString   r2, "crypto"
    Call2             r2, r4, r3, r2
    GetByIdShort      r3, r2, 2, "createDecipheriv"
    StoreToEnvironment r0, 0, r3
    GetByIdShort      r3, r2, 3, "createCipheriv"
    StoreToEnvironment r0, 1, r3
    GetByIdShort      r2, r2, 4, "randomBytes"
    StoreToEnvironment r0, 2, r2
    TryGetById        r5, r1, 5, "Buffer"
    GetByIdShort      r4, r5, 6, "from"
    LoadConstString   r3, "60adba1cf391d89a3"...
    LoadConstString   r2, "hex"
    Call3             r2, r4, r5, r3, r2
    StoreToEnvironment r0, 3, r2
    TryGetById        r2, r1, 7, "module"
    GetByIdShort      r3, r2, 8, "exports"
    CreateClosure     r2, r0, 1
    PutById           r3, r2, 1, "createKey"
    TryGetById        r1, r1, 7, "module"
    GetByIdShort      r1, r1, 8, "exports"
    CreateClosure     r0, r0, 2
    PutById           r1, r0, 2, "validateLicense"
    Ret               r0


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;So, while Hermes introduces a certain degree of complexity to the &lt;code&gt;entry-file&lt;/code&gt; code, it doesn't actually conceal the code nor do anything to prevent code tampering, which means that it won't stop an attacker ⁠— let's not forget that this is not even the purpose of Hermes.&lt;/p&gt;

&lt;p&gt;And this leads us to an approach that obfuscates React Native’s JavaScript source code to effectively mitigate the risk of code tampering and reverse engineering: Jscrambler.&lt;/p&gt;

&lt;h3&gt;
  
  
  Jscrambler
&lt;/h3&gt;

&lt;p&gt;Jscrambler provides a series of layers to protect JavaScript. Unlike most tools that only include (basic) obfuscation, Jscrambler provides three security layers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://jscrambler.com/products/code-integrity/javascript-obfuscation?utm_source=dev.to&amp;amp;utm_medium=referral&amp;amp;utm_campaign=securing-react-native"&gt;Polymorphic JavaScript &amp;amp; HTML5 obfuscation&lt;/a&gt;;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.jscrambler.com/code-integrity/tutorials/code-locks?utm_source=dev.to&amp;amp;utm_medium=referral&amp;amp;utm_campaign=securing-react-native"&gt;Code locks&lt;/a&gt; (domain, OS, browser, time frame);&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://blog.jscrambler.com/jscrambler-101-self-defending/?utm_source=dev.to&amp;amp;utm_medium=referral&amp;amp;utm_campaign=securing-react-native"&gt;Self-defending&lt;/a&gt; (anti-tampering &amp;amp; anti-debugging);&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;By protecting the source code of React Native apps with Jscrambler, the resulting code is highly obfuscated, as can be observed below:&lt;/p&gt;

&lt;center&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jscrambler.com%2Fcontent%2Fimages%2F2019%2F12%2Fjscrambler-blog-securing-react-native-applications-jscrambler-protection.png" alt="React Native Code Protected by Jscrambler"&gt;&lt;/center&gt;

&lt;p&gt;On top of this obfuscation, there's a Self-Defending layer that provides anti-debugging and anti-tampering capabilities and enables setting &lt;a href="https://blog.jscrambler.com/jscrambler-101-countermeasures/?utm_source=dev.to&amp;amp;utm_medium=referral&amp;amp;utm_campaign=securing-react-native"&gt;countermeasures&lt;/a&gt; like breaking the application, deleting cookies, or &lt;a href="https://docs.jscrambler.com/code-integrity/documentation/client-side-countermeasures#self-destruct" rel="noopener noreferrer"&gt;destroying the attacker’s environment&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To get started with protecting React Native source code with Jscrambler, check the &lt;a href="https://blog.jscrambler.com/how-to-protect-react-native-apps-with-jscrambler/?utm_source=dev.to&amp;amp;utm_medium=referral&amp;amp;utm_campaign=securing-react-native"&gt;official guide&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;This article provides an overview of techniques to harden a React Native application.&lt;/p&gt;

&lt;p&gt;Developer &lt;a href="https://2019.stateofjs.com/mobile-desktop/" rel="noopener noreferrer"&gt;surveys&lt;/a&gt; show that React Native is still a framework of choice, even among development teams of large enterprises.&lt;/p&gt;

&lt;p&gt;It’s then crucial to create a threat model and, depending on the application’s use case, employ the required measures to ensure that the application is properly secured.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Feel free to test how Jscrambler protects your React Native source code by using a &lt;a href="https://blog.jscrambler.com/how-to-protect-react-native-apps-with-jscrambler/?utm_source=dev.to&amp;amp;utm_medium=referral&amp;amp;utm_campaign=securing-react-native"&gt;free trial&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>reactnative</category>
      <category>javascript</category>
      <category>mobile</category>
      <category>security</category>
    </item>
    <item>
      <title>Best Practices for Secure Session Management in Node</title>
      <dc:creator>Karan Gandhi</dc:creator>
      <pubDate>Thu, 13 Feb 2020 16:57:27 +0000</pubDate>
      <link>https://dev.to/jscrambler/best-practices-for-secure-session-management-in-node-3f01</link>
      <guid>https://dev.to/jscrambler/best-practices-for-secure-session-management-in-node-3f01</guid>
      <description>&lt;p&gt;In a web application, data is transferred from a browser to a server over HTTP. In modern applications, we use the HTTPS protocol, which is HTTP over TLS/SSL (secure connection), to transfer data securely.&lt;/p&gt;

&lt;p&gt;Looking at common use cases, we often encounter situations where we need to retain user state and information. However, HTTP is a stateless protocol. Sessions are used to store user information between HTTP requests.&lt;/p&gt;

&lt;p&gt;We can use sessions to store users' settings like when not authenticated. Post authentication sessions are used to identify authenticated users. Sessions fulfill an important role between user authentication and authorization.&lt;/p&gt;

&lt;h2&gt;
  
  
  Exploring Sessions
&lt;/h2&gt;

&lt;p&gt;Traditionally, sessions are identifiers sent from the server and stored on the client-side. On the next request, the client sends the session token to the server. Using the identifier, the server can associate a request with a user.&lt;/p&gt;

&lt;p&gt;Session identifiers can be stored in cookies, localStorage, and sessionStorage. Session identifiers can be sent back to the server via cookies, URL params, hidden form fields or a custom header. Additionally, a server can accept session identifiers by multiple means. This is usually the case when a back-end is used for websites and mobile applications.&lt;/p&gt;

&lt;h3&gt;
  
  
  Session Identifiers
&lt;/h3&gt;

&lt;p&gt;A session identifier is a token stored on the client-side. Data associated with a session identifier lies on the server.&lt;/p&gt;

&lt;p&gt;Generally speaking, a session identifier:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Must be random;&lt;/li&gt;
&lt;li&gt;Should be stored in a cookie.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The recommended session ID must have a length of 128 bits or 16 bytes. A good pseudorandom number generator (PNRG) is recommended to generate entropy, usually 50% of ID length.&lt;/p&gt;

&lt;p&gt;Cookies are ideal because they are sent with every request and can be secured easily. LocalStorage doesn't have an expiry attribute so it persists. On the other hand, SessionStorage doesn't persist across multiple tabs/windows and is cleared when a tab is closed. Extra client code is required to be written to handle LocalStorage / SessionStorage. Additionally, both are an API so, theoretically, they are vulnerable to &lt;a href="https://blog.jscrambler.com/exploring-the-owasp-top-10-by-exploiting-vulnerable-node-applications/#a7xsscrosssitescripting"&gt;XSS&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Usually, the communication between client and server should be over HTTPS. Session identifiers should not be shared among the protocols. Sessions should be refreshed if the request is redirected. Also, if the redirect is to HTTPS, the cookie should set after the redirect. In case multiple cookies are set, the back-end should verify all cookies. &lt;/p&gt;

&lt;h3&gt;
  
  
  Securing Cookie Attributes
&lt;/h3&gt;

&lt;p&gt;Cookies can be secured using the following attributes.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;Secure&lt;/code&gt; attribute instructs the browser to set cookies over HTTPS only. This attribute prevents MITM attacks since the transfer is over TLS.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;HttpOnly&lt;/code&gt; attribute blocks the ability to use the &lt;code&gt;document.cookie&lt;/code&gt; object. This prevents XSS attacks from stealing the session identifier.&lt;/li&gt;
&lt;li&gt;The &lt;code&gt;SameSite&lt;/code&gt; attribute blocks the ability to send a cookie in a cross-origin request. This provides limited protection against &lt;a href="https://blog.jscrambler.com/what-is-cross-site-request-forgery/?utm_source=dev.to&amp;amp;utm_medium=referral"&gt;CSRF attacks&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Setting &lt;code&gt;Domain&lt;/code&gt; &amp;amp; &lt;code&gt;Path&lt;/code&gt; attributes can limit the exposure of a cookie. By default, &lt;code&gt;Domain&lt;/code&gt; should not be set and &lt;code&gt;Path&lt;/code&gt; should be restricted.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Expire&lt;/code&gt; &amp;amp; &lt;code&gt;Max-Age&lt;/code&gt; allow us to set the persistence of a cookie. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Typically, a session library should be able to generate a unique session, refresh an existing session and revoke sessions. We will be exploring the &lt;code&gt;express-session&lt;/code&gt; library ahead.&lt;/p&gt;

&lt;h2&gt;
  
  
  Enforcing Best Practices Using express-session
&lt;/h2&gt;

&lt;p&gt;In Node.js apps using Express, &lt;a href="https://github.com/expressjs/session"&gt;express-session&lt;/a&gt; is the &lt;em&gt;de facto&lt;/em&gt; library for managing sessions. This library offers:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Cookie-based Session Management.&lt;/li&gt;
&lt;li&gt;Multiple modules for managing session stores.&lt;/li&gt;
&lt;li&gt;An API to generate, regenerate, destroy and update sessions.&lt;/li&gt;
&lt;li&gt;Settings to secure cookies (Secure / HttpOnly / Expire /SameSite / Max Age / Expires /Domain / Path)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We can generate a session using the following command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app.use(session({
  secret: 'veryimportantsecret',  
}))

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The secret is used to sign the cookie using the &lt;a href="https://www.npmjs.com/package/cookie-signature"&gt;cookie-signature&lt;/a&gt; library. Cookies are signed using &lt;a href="https://blog.jscrambler.com/hashing-algorithms/?utm_source=dev.to&amp;amp;utm_medium=referral"&gt;Hmac-sha256&lt;/a&gt; and converted to a &lt;code&gt;base64&lt;/code&gt; string. We can have multiple secrets as an array. The first secret will be used to sign the cookie. The rest will be used in verification.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;secret&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;veryimportantsecret&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;notsoimportantsecret&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;highlyprobablysecret&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;}))&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To use a custom session ID generator, we can use the &lt;code&gt;genid&lt;/code&gt; param. By default, &lt;a href="https://www.npmjs.com/package/uid-safe"&gt;uid-safe&lt;/a&gt; is used to generate session IDs with a byte length of 24. It's recommended to stick to default implementation unless there is a specific requirement to harden &lt;code&gt;uuid&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app.use(session({
    secret: 'veryimportantsecret', 
    genid: function(req) {
      return genuuid() // use UUIDs for session IDs
     }
}))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The default name of the cookie is &lt;code&gt;connect.sid&lt;/code&gt;. We can change the name using the name &lt;code&gt;param&lt;/code&gt;. It's advisable to change the name to avoid fingerprinting.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app.use(session({
  secret: ['veryimportantsecret','notsoimportantsecret','highlyprobablysecret'], 
  name: "secretname" 
}))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By default, the cookies are set to&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{ path: '/', httpOnly: true, secure: false, maxAge: null }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To harden our session cookies, we can assign the following options:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;secret&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;veryimportantsecret&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;notsoimportantsecret&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;highlyprobablysecret&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;  
   &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;secretname&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;cookie&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;httpOnly&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;secure&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;sameSite&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;maxAge&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;600000&lt;/span&gt; &lt;span class="c1"&gt;// Time is in miliseconds&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The caveats here are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;sameSite: true&lt;/code&gt; blocks CORS requests on cookies. This will affect the workflow on API calls and mobile applications.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;secure&lt;/code&gt; requires HTTPS connections. Also, if the Node app is behind a proxy (like Nginx), we will have to set proxy to true, as shown below.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app.set('trust proxy', 1)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By default, the sessions are stored in &lt;code&gt;MemoryStore&lt;/code&gt;. This is not recommended for production use. Instead, it's advisable to use alternative &lt;a href="https://www.npmjs.com/package/express-session#compatible-session-stores"&gt;session stores&lt;/a&gt; for production. We have multiple options to store the data, like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Databases like MySQL, MongoDB. &lt;/li&gt;
&lt;li&gt;Memory stores like &lt;code&gt;Redis&lt;/code&gt;. &lt;/li&gt;
&lt;li&gt;ORM libraries like &lt;code&gt;sequelize&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We will be using Redis as an example here.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install redis connect-redis 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;redis&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express-session&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;RedisStore&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;connect-redis&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;redisClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;redis&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createClient&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;secret&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;veryimportantsecret&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;notsoimportantsecret&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;highlyprobablysecret&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; 
     &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;secretname&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
     &lt;span class="na"&gt;cookie&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;httpOnly&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;secure&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;sameSite&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;maxAge&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;600000&lt;/span&gt; &lt;span class="c1"&gt;// Time is in miliseconds&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="na"&gt;store&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;RedisStore&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;client&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;redisClient&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="na"&gt;ttl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;86400&lt;/span&gt;&lt;span class="p"&gt;}),&lt;/span&gt;   
    &lt;span class="na"&gt;resave&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
  &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;ttl&lt;/code&gt; (time to live) param is used to create an expiration date. If the &lt;code&gt;Expire&lt;/code&gt; attribute is set on the cookie, it will override the &lt;code&gt;ttl&lt;/code&gt;. By default, &lt;code&gt;ttl&lt;/code&gt; is one day.&lt;/p&gt;

&lt;p&gt;We have also set &lt;code&gt;resave&lt;/code&gt; to false. This param forces the session to be saved to the session store. This param should be set after checking the store docs.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;session&lt;/code&gt; object is associated with all routes and can be accessed on all requests.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;somevalue&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;  
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;index&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sessions should be regenerated after logins and privilege escalations. This prevents session fixation attacks. To regenerate a session, we will use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;regenerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// will have a new session here&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sessions should be expired when the user logs out or times out. To destroy a session, we can use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;destroy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// cannot access session here&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;br&gt;
&lt;strong&gt;Side Note&lt;/strong&gt;: While this article focuses on back-end security, you should protect your front-end as well. See these tutorials on protecting &lt;a href="https://blog.jscrambler.com/protecting-your-react-js-source-code-with-jscrambler/?utm_source=dev.to&amp;amp;utm_medium=referral"&gt;React&lt;/a&gt;, &lt;a href="https://blog.jscrambler.com/how-to-protect-angular-code-against-theft-and-reverse-engineering/?utm_source=dev.to&amp;amp;utm_medium=referral"&gt;Angular&lt;/a&gt;, &lt;a href="https://blog.jscrambler.com/how-to-protect-your-vue-js-application-with-jscrambler/?utm_source=dev.to&amp;amp;utm_medium=referral"&gt;Vue&lt;/a&gt;, &lt;a href="https://blog.jscrambler.com/how-to-protect-react-native-apps-with-jscrambler/?utm_source=dev.to&amp;amp;utm_medium=referral"&gt;React Native&lt;/a&gt;, &lt;a href="https://blog.jscrambler.com/protecting-hybrid-mobile-apps-with-ionic-and-jscrambler/?utm_source=dev.to&amp;amp;utm_medium=referral"&gt;Ionic&lt;/a&gt;, and &lt;a href="https://blog.jscrambler.com/protecting-your-nativescript-source-code-with-jscrambler/?utm_source=dev.to&amp;amp;utm_medium=referral"&gt;NativeScript&lt;/a&gt;.&lt;br&gt;

&lt;h2&gt;
  
  
  Extra Security with Helmet.js (Cache-Control)
&lt;/h2&gt;

&lt;p&gt;Web Caching allows us to serve requests faster. Some sensitive data might be cached on the client computer. Even if we timeout the session, there might be a possibility that the data can be retrieved from the web cache. To prevent this, we need to disable cache.&lt;/p&gt;

&lt;p&gt;From the POV of this article, we are interested in setting the  &lt;code&gt;Cache-Control&lt;/code&gt; header to disable client-side caching. &lt;/p&gt;

&lt;p&gt;Helmet.js is an Express library that can be used to secure our Express apps.&lt;br&gt;
The &lt;code&gt;noCache&lt;/code&gt; method will set &lt;code&gt;Cache-Control&lt;/code&gt;, &lt;code&gt;Surrogate-Control&lt;/code&gt;, &lt;code&gt;Pragma&lt;/code&gt;, and &lt;code&gt;Expires&lt;/code&gt; HTTP headers for us.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;helmet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;helmet&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;helmet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;noCache&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, in general, it's wise to use the other options too. Helmet.js provides:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;dnsPrefetchControl&lt;/code&gt; to control browser DNS prefetching.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;frameguard&lt;/code&gt; to prevent clickjacking.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;hidePoweredBy&lt;/code&gt; to hide &lt;code&gt;X-Powered-By&lt;/code&gt; header.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;hsts&lt;/code&gt; for HTTP Strict transport Security&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;noSniff&lt;/code&gt; to keep clients from sniffing MIME types&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;xssFilter&lt;/code&gt; to add some XSS protection. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Alternatively, if the site has the requirement to be cached, at the very least, the &lt;code&gt;Cache-Control&lt;/code&gt; header must be set to &lt;code&gt;Cache-Control: no-cache="Set-Cookie, Set-Cookie2"&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Cache-Control&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;no-cache='Set-Cookie, Set-Cookie2'&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// Route Logic&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Logging Sessions
&lt;/h2&gt;

&lt;p&gt;Whenever a new session is created, regenerated, or destroyed, it should be logged. Namely, activities like user-role escalation or financial transactions should be logged.&lt;/p&gt;

&lt;p&gt;A typical log should contain the timestamp, client IP, resource requested, user ID, and session ID.&lt;/p&gt;

&lt;p&gt;This will be helpful to detect session anomalies in case of an attack. We can use &lt;code&gt;winston&lt;/code&gt;, &lt;code&gt;morgan&lt;/code&gt; or &lt;code&gt;pino&lt;/code&gt; to log these requests. By default, Express comes with &lt;code&gt;morgan&lt;/code&gt; preinstalled. The default &lt;code&gt;combined&lt;/code&gt; setting provides us standard Apache combined log output.&lt;/p&gt;

&lt;p&gt;We can modify morgan to include session identifiers using custom morgan &lt;code&gt;tokens&lt;/code&gt;. Depending on the use-case we add additional data to output. Similar processes can be implemented in other logging libraries.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;express&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;morgan&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;morgan&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;app&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;express&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="nx"&gt;morgan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;sessionid&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;param&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sessionID&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nx"&gt;morgan&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;param&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;morgan&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;:remote-addr - :remote-user [:date[clf]] ":method :url HTTP/:http-version" :status :res[content-length] ":referrer" ":user-agent" :user :sessionid&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

&lt;span class="nx"&gt;app&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hello, world!&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Depending on the use case, logging scenarios should be built and implemented.&lt;/p&gt;

&lt;h2&gt;
  
  
  Additional Client-Side Defenses
&lt;/h2&gt;

&lt;p&gt;There are some other client-side measures we can take to expire sessions.&lt;/p&gt;

&lt;h3&gt;
  
  
  Session Timeouts on Browser Events
&lt;/h3&gt;

&lt;p&gt;We can use JavaScript to detect if the &lt;code&gt;window.close&lt;/code&gt; event is fired and subsequently force a session logout.&lt;/p&gt;

&lt;h3&gt;
  
  
  Timeout Warnings
&lt;/h3&gt;

&lt;p&gt;A user can be notified of session timeouts on the client-side. This will notify the user that his session is going to expire soon. This is helpful when a long business process is involved. Users can save their work before timeout OR continue working.&lt;/p&gt;

&lt;h3&gt;
  
  
  Initial Login Timeout
&lt;/h3&gt;

&lt;p&gt;A client-side timeout can be set between the page that was loaded and the user that was authenticated. This is to prevent session fixation attacks, especially when the user is using a public/shared computer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Alternatives
&lt;/h2&gt;

&lt;p&gt;Currently, &lt;a href="https://blog.jscrambler.com/implementing-jwt-using-passport/?utm_source=dev.to&amp;amp;utm_medium=referral"&gt;JWT&lt;/a&gt; is a viable alternative to the session. JWT is a stateless Auth mechanism. A &lt;code&gt;Bearer&lt;/code&gt; token is sent in the header of every authenticated request. The payload of the JWT token contains the necessary details used for authorization. This is useful when we want to expose some part of our data as an API resource. However, unlike sessions, JWT is stateless and hence the logout code has to be implemented on the client-side. You can set an expiry timestamp in JWT payload but cannot force a logout.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;As we explored in this tutorial, managing sessions securely in Node/Express apps is a key security requirement.&lt;/p&gt;

&lt;p&gt;We have highlighted some techniques to prevent some very serious attacks like CRSF, XSS, and others that might expose sensitive user information.&lt;/p&gt;

&lt;p&gt;At a time when web-based attacks are growing fast, these threats must be addressed while developing the app to minimize the application’s attack surface.&lt;/p&gt;




&lt;p&gt;For some further reading on security in JavaScript apps, check this &lt;a href="https://jscrambler.com/code-integrity/javascript-security-data-sheet?utm_source=dev.to&amp;amp;utm_medium=referral"&gt;data sheet&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>node</category>
      <category>express</category>
      <category>javascript</category>
      <category>security</category>
    </item>
    <item>
      <title>Background Services in Ionic Capacitor</title>
      <dc:creator>Karan Gandhi</dc:creator>
      <pubDate>Wed, 30 Oct 2019 14:23:53 +0000</pubDate>
      <link>https://dev.to/jscrambler/background-services-in-ionic-capacitor-37gi</link>
      <guid>https://dev.to/jscrambler/background-services-in-ionic-capacitor-37gi</guid>
      <description>&lt;p&gt;A few months back, the Ionic team introduced Capacitor, a new runtime for cross-platform development.  Capacitor supports Android, iOS, PWA, and Electron platforms. &lt;/p&gt;

&lt;p&gt;We covered PWA development with Capacitor in another &lt;a href="https://blog.jscrambler.com/create-an-ionic-4-pwa-with-capacitor?utm_source=dev.to&amp;amp;utm_medium=referral"&gt;article&lt;/a&gt;. In this article, we will be focusing on native workflow and functionalities.&lt;/p&gt;

&lt;h2&gt;
  
  
  Alternative to Cordova
&lt;/h2&gt;

&lt;p&gt;Both Cordova and Capacitor are runtimes providing native functionalities over WebView. Cordova is a quite mature runtime with numerous plugins and robust tooling. Capacitor is a relatively new runtime with a different approach.&lt;/p&gt;

&lt;p&gt;The Cordova framework provides a lot of native features like file management and camera to develop applications. The framework can be extended via multiple community plugins.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blog.jscrambler.com/10-frameworks-for-mobile-hybrid-apps/?utm_source=dev.to&amp;amp;utm_medium=referral"&gt;Frameworks&lt;/a&gt; like Ionic and OnsenUI were built on top Cordova and integrated the Cordova CLI into their tooling. The build process is handled by &lt;code&gt;cordova-cli&lt;/code&gt; which could be extended via hooks. Native App features can be controlled via the &lt;code&gt;config.xml&lt;/code&gt; file. The application logic is usually in the &lt;code&gt;www&lt;/code&gt; folder. Ionic applications usually have it in the &lt;code&gt;src&lt;/code&gt; folder which is then compiled to &lt;code&gt;www&lt;/code&gt; via the Ionic CLI. In this context, the &lt;code&gt;www&lt;/code&gt; or &lt;code&gt;src&lt;/code&gt; folders are important. The &lt;code&gt;platforms&lt;/code&gt; folder, which has native code, can be configured at build time. There is little need for the platforms to be a part of the developer workflow.&lt;/p&gt;

&lt;p&gt;This is where Capacitor differs from Cordova. Capacitor considers the platforms folder as a &lt;code&gt;source asset&lt;/code&gt; instead of a &lt;code&gt;build time&lt;/code&gt; asset. Developers are encouraged to use Native IDEs, namely &lt;strong&gt;Android Studio&lt;/strong&gt; and &lt;strong&gt;X-Code&lt;/strong&gt; for development. The native code in the &lt;code&gt;platforms&lt;/code&gt; folder is a part of the developer's git repository. Developers have more control over native code as compared to Cordova. Capacitor apps don't require a &lt;code&gt;deviceready&lt;/code&gt; event. All plugin methods are available as soon as the WebView loads. However, Capacitor has limited backward compatibility with Cordova plugins. Due to the lack of support for &lt;code&gt;hooks&lt;/code&gt;, the plugins have to be manually set up beforehand.&lt;/p&gt;

&lt;h2&gt;
  
  
  Starting a new project
&lt;/h2&gt;

&lt;p&gt;We can initialize a Capacitor project in multiple ways. The simplest way to create a new project is by using the Ionic CLI.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

ionic start CapacitorProject sidemenu &lt;span class="nt"&gt;--capacitor&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;We can add Capacitor to an existing Ionic project using &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

ionic integrations &lt;span class="nb"&gt;enable &lt;/span&gt;cordova


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Capacitor is platform-agnostic - which means that we can also add it to an existing web app using&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--save&lt;/span&gt; @capacitor/core @capacitor/cli
npx cap init


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Alternatively, we can start a project using the Capacitor CLI.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

npx @capacitor/cli create


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Capacitor Config
&lt;/h3&gt;

&lt;p&gt;We can configure Capacitor projects using &lt;code&gt;capacitor.config.json&lt;/code&gt;. This file provides configuration to the Capacitor's tooling. Here is the JSON which we used in the &lt;a href="https://blog.jscrambler.com/developing-a-real-world-app-in-ionic-react/?utm_source=dev.to&amp;amp;utm_medium=referral"&gt;RealWorldApp&lt;/a&gt; docs. &lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"appId"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"me.karandpr.conduit"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"appName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Conduit"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"bundledWebRuntime"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"npmClient"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"npm"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"webDir"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"build"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;


&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;code&gt;appID&lt;/code&gt; is the package identifier and &lt;code&gt;appName&lt;/code&gt; is the application name.  &lt;code&gt;npmClient&lt;/code&gt; is the package manager in use. &lt;code&gt;webDir&lt;/code&gt; is the directory where the build web assets are stored. The rest of the config options can be found &lt;a href="https://capacitor.ionicframework.com/docs/basics/configuring-your-app/" rel="noopener noreferrer"&gt;here&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Developer Workflow
&lt;/h2&gt;

&lt;p&gt;In Cordova projects, we simply used the following command to run on a device:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

ionic cordova run android


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The developer workflow for Capacitor projects is below.&lt;/p&gt;

&lt;center&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fblog.jscrambler.com%2Fcontent%2Fimages%2F2019%2F10%2Fjscrambler-blog-background-services-ionic-capacitor-workflow.png" alt="Cordova Workflow"&gt;&lt;/center&gt;

&lt;p&gt;As shown, we can build projects using relevant build command like &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

npm run build 


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

yarn run build


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

ionic build 


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The built web app should be available in folders like &lt;code&gt;www&lt;/code&gt; or &lt;code&gt;build&lt;/code&gt;. We have already specified the folder to be &lt;code&gt;webDir&lt;/code&gt; in &lt;code&gt;capacitor.config.json&lt;/code&gt;. To copy the assets to native platforms, we will execute&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

npx cap copy


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;If we have installed a new plugin, we will have to use the command &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

npx cap &lt;span class="nb"&gt;sync&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Lastly, we can open the project in a native IDE using &lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

npx cap open


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Background Tasks
&lt;/h2&gt;

&lt;p&gt;Now that we covered the main developer workflow, let’s zoom into how background services work in Capacitor.&lt;/p&gt;

&lt;p&gt;Capacitor has default plugins to ease up native development. The usual suspects &lt;code&gt;File&lt;/code&gt;, &lt;code&gt;Camera&lt;/code&gt;, &lt;code&gt;Geolocation&lt;/code&gt; and &lt;code&gt;Push&lt;/code&gt; are already present. One plugin API which caught our fancy is &lt;code&gt;Background Task&lt;/code&gt;. The &lt;a href="https://capacitor.ionicframework.com/docs/apis/background-task" rel="noopener noreferrer"&gt;Background Task API&lt;/a&gt; allows the Capacitor app to run short tasks in the background. This comes in handy if we want to finish some tasks after the app is pushed to the background. Currently, the plugin provides two functions.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;BackgroundTask.beforeExit&lt;/code&gt;: This function allows certain tasks to be run in the background. &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;BackgroundTask.finish&lt;/code&gt;: This function notifies the OS that the task is over. This is important for iOS.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In the future, the plugin may support background fetch operations. &lt;br&gt;
Let's look at a code snippet to see how Background Task works. The purpose of the snippet is to get the Latitude &amp;amp; Longitude of the device after the app is pushed to the background. We have used &lt;code&gt;Geolocation&lt;/code&gt; and &lt;code&gt;LocalNotifications&lt;/code&gt; API for that purpose.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;

 &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;appStateChange&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;     
      &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isActive&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// We are using the appStateChange event to detect a change.&lt;/span&gt;

        &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;taskId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;BackgroundTask&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;beforeExit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="c1"&gt;// We will be using this function to get geolocation.&lt;/span&gt;
          &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;location&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getCurrentPosition&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; 
          &lt;span class="c1"&gt;// The location is fetched using Geolocation service.&lt;/span&gt;

          &lt;span class="nx"&gt;LocalNotifications&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;schedule&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;notifications&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
              &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Last Known Location&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Latitude: &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;coords&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;latitude&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Longitude: &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;coords&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;longitude&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;schedule&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;at&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1000&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
                &lt;span class="na"&gt;sound&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;attachments&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;actionTypeId&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="na"&gt;extra&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
              &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;]&lt;/span&gt;
          &lt;span class="p"&gt;});&lt;/span&gt;   
          &lt;span class="c1"&gt;// We have scheduled a notification after 10 seconds.&lt;/span&gt;
          &lt;span class="nx"&gt;BackgroundTask&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;finish&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
              &lt;span class="nx"&gt;taskId&lt;/span&gt;
            &lt;span class="p"&gt;});&lt;/span&gt;         
            &lt;span class="c1"&gt;// We have notified the OS that the task is finished.&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;   
    &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;getCurrentPosition&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;coordinates&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;Geolocation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getCurrentPosition&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;      
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;coordinates&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The iOS &lt;a href="https://github.com/ionic-team/capacitor/blob/master/ios/Capacitor/Capacitor/Plugins/BackgroundTask.swift" rel="noopener noreferrer"&gt;implementation&lt;/a&gt; uses UIApplication's &lt;a href="https://developer.apple.com/documentation/uikit/uiapplication/1623051-beginbackgroundtask" rel="noopener noreferrer"&gt;Background Task&lt;/a&gt;. It's mandatory in iOS to invoke &lt;code&gt;finish&lt;/code&gt; - otherwise, the app may be labeled as &lt;code&gt;impacting battery life&lt;/code&gt;. The usual time allowed for running the task is around 180 seconds. After the time limit, iOS may close the app. Also, &lt;code&gt;setInterval&lt;/code&gt; and &lt;code&gt;setTimeout&lt;/code&gt; won't work once the app is in the background.&lt;/p&gt;

&lt;p&gt;The Android &lt;a href="https://github.com/ionic-team/capacitor/blob/master/android/capacitor/src/main/java/com/getcapacitor/plugin/background/BackgroundTaskService.java" rel="noopener noreferrer"&gt;Implementation&lt;/a&gt; uses &lt;a href="https://developer.android.com/reference/android/app/IntentService" rel="noopener noreferrer"&gt;IntentService&lt;/a&gt; to execute background tasks. &lt;code&gt;IntentService&lt;/code&gt; runs outside the application in a background process. Hence, a task can run independently even after the app is removed from memory. On Android, there is no restriction on the length of the task.&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing Thoughts
&lt;/h2&gt;

&lt;p&gt;Capacitor introduces us to a new way to develop WebView Apps. It has some interesting plugin APIs like Background Task. Currently, there are some incompatible &lt;a href="https://capacitor.ionicframework.com/docs/cordova/known-incompatible-plugins" rel="noopener noreferrer"&gt;plugins&lt;/a&gt; which might require some workarounds. If you are a seasoned developer, you should try Capacitor in your upcoming projects.&lt;/p&gt;

&lt;p&gt;As a drawback, old or private Cordova plugins might cause build issues with Capacitor. There is no specific guideline for integrating such plugins. In such cases, it's better to stick to current build processes and plan out a migration strategy. Also, it might be frustrating for new developers to work in three workspaces. If you don't want to work with native platforms, you can always use Cordova.&lt;/p&gt;

&lt;p&gt;As a final note, don't forget that, before deploying your commercial or enterprise Ionic apps to production, you should always protect their logic against reverse-engineering, abuse, and tampering by following &lt;a href="https://blog.jscrambler.com/protecting-hybrid-mobile-apps-with-ionic-and-jscrambler/?utm_source=dev.to&amp;amp;utm_medium=referral"&gt;this guide&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Originally published on the &lt;a href="https://blog.jscrambler.com/background-services-in-ionic-capacitor/?utm_source=dev.to&amp;amp;utm_medium=referral"&gt;Jscrambler Blog&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ionic</category>
      <category>capacitor</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Developing a Real World App in Ionic React</title>
      <dc:creator>Karan Gandhi</dc:creator>
      <pubDate>Fri, 07 Jun 2019 16:49:31 +0000</pubDate>
      <link>https://dev.to/jscrambler/developing-a-real-world-app-in-ionic-react-59e1</link>
      <guid>https://dev.to/jscrambler/developing-a-real-world-app-in-ionic-react-59e1</guid>
      <description>&lt;p&gt;Ionic recently added support for the React and Vue frameworks. Traditionally, Ionic used Angular and Cordova frameworks to create their apps. With &lt;a href="https://blog.jscrambler.com/introduction-to-ionic-4/"&gt;Ionic 4&lt;/a&gt;, we can develop framework-agnostic apps. In this tutorial, we will create a basic Ionic app in the React Framework. &lt;/p&gt;

&lt;h3&gt;
  
  
  RealWorld and Conduit
&lt;/h3&gt;

&lt;p&gt;The folks at Thinkster are behind a project known as RealWorld project. Conduit is a Medium clone which can be built using multiple stacks. We can mix and match different types of backends and frontends. Every backend and frontend follow the same &lt;a href="https://github.com/gothinkster/realworld/tree/master/spec"&gt;API spec&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Unlike simple CRUD ToDo Apps, Conduit is a full-fledged CMS. Implementing the project requires some effort.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting Started
&lt;/h2&gt;

&lt;p&gt;For this tutorial, we will be covering the following points. &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Home Page (With and Without Auth)

&lt;ul&gt;
&lt;li&gt;List of Articles &lt;/li&gt;
&lt;li&gt;Favorite an Article (Auth Required)&lt;/li&gt;
&lt;li&gt;Navigate to Article Page &lt;/li&gt;
&lt;li&gt;Navigate to Author Profile Page&lt;/li&gt;
&lt;li&gt;Display your Feed (Auth Required)&lt;/li&gt;
&lt;li&gt;Display Popular Tags. &lt;/li&gt;
&lt;li&gt;Filter Articles by Tags.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Article Page (With and Without Auth)

&lt;ul&gt;
&lt;li&gt;Read Article &lt;/li&gt;
&lt;li&gt;List Comments &lt;/li&gt;
&lt;li&gt;Add Comment (Auth Required)&lt;/li&gt;
&lt;li&gt;Navigate to Author Page&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Settings Page (Auth required)

&lt;ul&gt;
&lt;li&gt;Modify user Settings&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Profile Page (With and Without Auth)

&lt;ul&gt;
&lt;li&gt;Display User details&lt;/li&gt;
&lt;li&gt;Display Posts by user &lt;/li&gt;
&lt;li&gt;Display Posts Favorited by user &lt;/li&gt;
&lt;li&gt;Follow User (Auth Required)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Create Article (Auth Required)

&lt;ul&gt;
&lt;li&gt;Create Article&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;Login / Signup Page

&lt;ul&gt;
&lt;li&gt;Signup User&lt;/li&gt;
&lt;li&gt;Login User&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Understanding the Conduit API
&lt;/h3&gt;

&lt;p&gt;Conduit has a production API endpoint &lt;a href="https://conduit.productionready.io/api/"&gt;here&lt;/a&gt;. We will use that endpoint for this tutorial. Alternatively, you can set up your own backends using a variety of languages.&lt;/p&gt;

&lt;p&gt;We will be using:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;/articles:  For fetching articles, comments&lt;/li&gt;
&lt;li&gt;/users: For creating and Authenticating users&lt;/li&gt;
&lt;li&gt;/profiles: For following profiles&lt;/li&gt;
&lt;li&gt;/tags: For fetching tags&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Users are authenticated via a JWT token in headers. &lt;/p&gt;

&lt;h3&gt;
  
  
  Setting up the Project
&lt;/h3&gt;

&lt;p&gt;The Ionic CLI currently doesn't support React templates. We will be using create-react-app to set up our project. Use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm i -g create-react-app
create-react-app conduit --typescript
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Alternatively, we can use npx:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx create-react-app conduit --typescript
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Navigate to the folder and install Ionic and React router:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cd conduit
npm install @ionic/react react-router react-router-dom @types/react-router @types/react-router-dom
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's initialize Ionic in this project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ionic init "Conduit" --type=custom
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We need to enable Capacitor in our project&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ionic integrations enable capacitor
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A file &lt;code&gt;capacitor.config.json&lt;/code&gt; is generated in our project directory. In the file, we need to change the build directory from &lt;code&gt;"webDir": "www"&lt;/code&gt; to &lt;code&gt;"webDir": "build"&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Create a build folder OR generate a build using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm run build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, we can add a platform to our project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx capacitor add android

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Additionally, we will be using this folder structure.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;src

&lt;ul&gt;
&lt;li&gt;components/&lt;/li&gt;
&lt;li&gt;pages/&lt;/li&gt;
&lt;li&gt;constants.ts&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's set up our constants file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;AppConfig&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;    
    &lt;span class="nl"&gt;API_ENDPOINT&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;

  &lt;span class="p"&gt;}&lt;/span&gt;  

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;CONFIG&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AppConfig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;API_ENDPOINT&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://conduit.productionready.io/api/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the &lt;code&gt;App.tsx&lt;/code&gt; file, we need to import the Ionic CSS files.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@ionic/core/css/core.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@ionic/core/css/ionic.bundle.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Developing the App
&lt;/h2&gt;

&lt;p&gt;An offline user has access to the Home, Article, Profile and Login pages. An online user has access to the Home, Article, Profile, Settings and Login Pages.&lt;/p&gt;

&lt;p&gt;There are 70+ Ionic components we can use to speed up our development. First, let's set up routing.&lt;/p&gt;

&lt;h3&gt;
  
  
  Routing
&lt;/h3&gt;

&lt;p&gt;We are using React Router to manage Routing. We will be using &lt;code&gt;IonRouterOutlet&lt;/code&gt; to manage routes. The key difference with the website is that users can't navigate with urls. We are also creating a custom component &lt;code&gt;SideMenu&lt;/code&gt; for side menu navigation. &lt;code&gt;IonMenuToggle&lt;/code&gt; is used to toggle the menu in components.&lt;/p&gt;

&lt;p&gt;A loggedIn key and an Event Listener are used to manage user state. The token obtained from authentication will be saved in localstorage.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;Component&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Router&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;App&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;        
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IonApp&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IonSplitPane&lt;/span&gt; &lt;span class="nx"&gt;contentId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;main&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;SideMenu&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/SideMenu&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IonPage&lt;/span&gt; &lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;main&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;        
                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IonRouterOutlet&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Route&lt;/span&gt; &lt;span class="nx"&gt;exact&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;HomePage&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;                    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Route&lt;/span&gt; &lt;span class="nx"&gt;exact&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/login&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;LoginPage&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&amp;gt; &lt;/span&gt;&lt;span class="err"&gt; 
&lt;/span&gt;                    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Route&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/article/:slug&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;ArticlePage&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;                    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Route&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/profile/:authorname&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;ProfilePage&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;                    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Route&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/settings&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;SettingsPage&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;                    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Route&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/newarticle&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;component&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;NewArticlePage&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&amp;gt;                            &lt;/span&gt;&lt;span class="err"&gt; 
&lt;/span&gt;                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/IonRouterOutlet&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/IonPage&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/IonSplitPane&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/IonApp&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Router&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://blog.jscrambler.com/protecting-hybrid-mobile-apps-with-ionic-and-jscrambler/?utm_source=dev.to&amp;amp;utm_medium=referral"&gt;&lt;img alt="Protect your Code with Jscrambler" src="https://res.cloudinary.com/practicaldev/image/fetch/s--yycJbIiL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://media.jscrambler.com/blog/V1-Ionic.jpg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Side menu Component:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;SideMenu&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Component&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;props&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;      
      &lt;span class="na"&gt;isLoggedIn&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;isLogin&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;isLogin&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;false&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;   
      &lt;span class="na"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;appPages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
          &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Home&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;icon&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;home&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;         
        &lt;span class="p"&gt;],&lt;/span&gt;        
        &lt;span class="na"&gt;loggedOutPages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
          &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Login&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/login&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;icon&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;log-in&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;]&lt;/span&gt;  &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;loggedIn&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;            
      &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;isLoggedIn&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;detail&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="na"&gt;routes&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;appPages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Home&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;icon&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;home&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;         
          &lt;span class="p"&gt;],&lt;/span&gt;
          &lt;span class="na"&gt;loggedInPages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;My Profile&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/profile/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;username&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="na"&gt;icon&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;person&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;        
            &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;New Article&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/newarticle&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;icon&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;create&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Settings&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/settings&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;icon&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;settings&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Logout&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/login&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;icon&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;log-out&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
          &lt;span class="p"&gt;],&lt;/span&gt;
          &lt;span class="na"&gt;loggedOutPages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Login&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/login&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;icon&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;log-in&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
          &lt;span class="p"&gt;]&lt;/span&gt;  &lt;span class="p"&gt;}&lt;/span&gt;        
      &lt;span class="p"&gt;})&lt;/span&gt;      

    &lt;span class="p"&gt;});&lt;/span&gt;  
  &lt;span class="p"&gt;}&lt;/span&gt;    

   &lt;span class="nx"&gt;renderMenuItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;menu&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
         &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IonMenuToggle&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;menu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;auto&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;hide&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;false&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                   &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IonItem&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                     &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IonIcon&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;menu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;icon&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/IonIcon&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;                     &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Link&lt;/span&gt; &lt;span class="nx"&gt;replace&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;sidemenu-link&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;menu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;menu&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Link&amp;gt;&lt;/span&gt;&lt;span class="err"&gt; 
&lt;/span&gt;                   &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/IonItem&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;                   &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/IonMenuToggle&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;  
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IonMenu&lt;/span&gt; &lt;span class="nx"&gt;side&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;start&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;menuId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;first&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;contentId&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;main&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IonHeader&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IonToolbar&lt;/span&gt; &lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;success&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IonTitle&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Start&lt;/span&gt; &lt;span class="nx"&gt;Menu&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/IonTitle&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/IonToolbar&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/IonHeader&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IonContent&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IonList&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;appPages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="na"&gt;art&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;renderMenuItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;art&lt;/span&gt;&lt;span class="p"&gt;))}&lt;/span&gt;
              &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;isLoggedIn&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;true&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;loggedInPages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="na"&gt;art&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
                &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;renderMenuItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;art&lt;/span&gt;&lt;span class="p"&gt;))}&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/&amp;gt; :&amp;lt;&amp;gt; {this.state.routes.loggedOutPages.map&lt;/span&gt;&lt;span class="se"&gt;((&lt;/span&gt;&lt;span class="sr"&gt;art: any&lt;/span&gt;&lt;span class="se"&gt;)&lt;/span&gt;&lt;span class="sr"&gt; =&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;                &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;renderMenuItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;art&lt;/span&gt;&lt;span class="p"&gt;))}&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/&amp;gt; &lt;/span&gt;&lt;span class="err"&gt;}
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/IonList&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/IonContent&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/IonMenu&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;SideMenu&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Home Page
&lt;/h3&gt;

&lt;p&gt;As mentioned above, the Home Page has a list of articles. The &lt;code&gt;/articles&lt;/code&gt; endpoint provides us an array of 20 articles. &lt;/p&gt;

&lt;p&gt;A normal user can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;View a list of articles&lt;/li&gt;
&lt;li&gt;Navigate to a full article&lt;/li&gt;
&lt;li&gt;Navigate to author profile&lt;/li&gt;
&lt;li&gt;Filter articles by tags&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;An authenticated user can additionally:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;View his/her article feed&lt;/li&gt;
&lt;li&gt;Favorite an article&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We will create the &lt;code&gt;ArticleCard&lt;/code&gt; and &lt;code&gt;TagsCloud&lt;/code&gt; components to make our tasks simpler. &lt;/p&gt;

&lt;p&gt;Additionally, &lt;code&gt;Header&lt;/code&gt; is a wrapper around Ionic Header with &lt;code&gt;title&lt;/code&gt; as props.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;   &lt;span class="nt"&gt;&amp;lt;IonHeader&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;IonToolbar&lt;/span&gt; &lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;IonTitle&lt;/span&gt;  &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"header"&lt;/span&gt;  &lt;span class="na"&gt;color=&lt;/span&gt;&lt;span class="s"&gt;"success"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;{this.props.title}&lt;span class="nt"&gt;&amp;lt;/IonTitle&amp;gt;&lt;/span&gt;           
            &lt;span class="nt"&gt;&amp;lt;IonMenuButton&lt;/span&gt; &lt;span class="na"&gt;slot=&lt;/span&gt;&lt;span class="s"&gt;"start"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/IonMenuButton&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;/IonToolbar&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/IonHeader&amp;gt;&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;TagsCloud&lt;/code&gt; is a component to retrieve popular tags. We receive an array of tags at the endpoint &lt;code&gt;/tags&lt;/code&gt;. We will be passing a function &lt;code&gt;onTagClick&lt;/code&gt; in props. So, we will be able to filter the articles using the clicked tag. We are using &lt;code&gt;IonChip&lt;/code&gt; to render the tag chips.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;handleClick&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;onTagClick&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;componentDidMount&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;    
    &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;CONFIG&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;API_ENDPOINT&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tags&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;          
            &lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tags&lt;/span&gt;
          &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;      
        &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;      
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;tagcloud&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IonLabel&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;center&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nx"&gt;Popular&lt;/span&gt; &lt;span class="nx"&gt;Tags&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/IonLabel&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;        
         &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="na"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;index&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;number&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; 
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IonChip&lt;/span&gt; &lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;success&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;index&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IonLabel&lt;/span&gt;  &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handleClick&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;tag&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/IonLabel&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/IonChip&amp;gt;          &lt;/span&gt;&lt;span class="err"&gt; 
&lt;/span&gt;             &lt;span class="p"&gt;)}&lt;/span&gt;         
         &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&amp;gt;&lt;/span&gt;&lt;span class="err"&gt; 
&lt;/span&gt;    &lt;span class="p"&gt;);&lt;/span&gt;       
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;  
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;ArticleCard&lt;/code&gt; component returns an &lt;code&gt;IonItem&lt;/code&gt; and &lt;code&gt;IonItemSliding&lt;/code&gt; for logged in users. A user can swipe and favorite an article if he/she chooses to.&lt;/p&gt;

&lt;p&gt;Let's create a function &lt;code&gt;loggedOutCard&lt;/code&gt; to return an &lt;code&gt;IonItem&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;loggedOutCard&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;                 
           &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IonItem&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IonAvatar&lt;/span&gt; &lt;span class="nx"&gt;slot&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;start&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&amp;gt;             &lt;/span&gt;&lt;span class="err"&gt; 
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/IonAvatar&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IonLabel&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;p&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;title&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/p&amp;gt;             &lt;/span&gt;&lt;span class="err"&gt; 
&lt;/span&gt;              &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IonGrid&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IonRow&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IonCol&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;author&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;6&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Link&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;link&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;profileLink&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                  &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;author&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Link&amp;gt;                    &lt;/span&gt;&lt;span class="err"&gt; 
&lt;/span&gt;                 &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/IonCol&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;                  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IonCol&lt;/span&gt;  &lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;6&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;right&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;                  
                  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Link&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;link&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;routeLink&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Read&lt;/span&gt; &lt;span class="nx"&gt;More&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Link&amp;gt;       &lt;/span&gt;&lt;span class="err"&gt; 
&lt;/span&gt;                  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/IonCol&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;                &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/IonRow&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;              &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/IonGrid&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/IonLabel&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/IonItem&amp;gt;     &lt;/span&gt;&lt;span class="err"&gt; 
&lt;/span&gt;  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We create a function &lt;code&gt;loggedInCard&lt;/code&gt; to return an &lt;code&gt;IonSlidingItem&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;loggedInCard&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;        
           &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IonItemSliding&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;loggedOutCard&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IonItemOptions&lt;/span&gt; &lt;span class="nx"&gt;side&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;end&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IonItemOption&lt;/span&gt;  &lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;favorited&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;success&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;light&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;favoriteArticle&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IonIcon&lt;/span&gt; &lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;favorited&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;light&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;success&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;icon-blog-card&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;heart&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;favoritesCount&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/IonItemOption&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/IonItemOptions&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/IonItemSliding&amp;gt;          &lt;/span&gt;&lt;span class="err"&gt; 
&lt;/span&gt;  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Authenticated users can favorite an article. We will create a function &lt;code&gt;favoriteArticle&lt;/code&gt; to achieve this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;favoriteArticle&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;CONFIG&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;API_ENDPOINT&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;articles/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/favorite&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;favorited&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;method&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;method&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;DELETE&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;method&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Authorization&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Token &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;token&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;       
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
          &lt;span class="na"&gt;favorited&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;article&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;favorited&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="na"&gt;favoritesCount&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;article&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;favoritesCount&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, let’s return the component based on user state.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;  &lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;   
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;isLogin&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;true&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;loggedInCard&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;loggedOutCard&lt;/span&gt;&lt;span class="p"&gt;()}&lt;/span&gt; 
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/&amp;gt;              &lt;/span&gt;&lt;span class="err"&gt; 
&lt;/span&gt;      &lt;span class="p"&gt;);&lt;/span&gt;    
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After fetching the articles from the &lt;code&gt;/articles&lt;/code&gt; endpoint, we will iterate the &lt;code&gt;ArticleCard&lt;/code&gt; component in our Home Page.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;      
      &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;   
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Header&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Home&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Header&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IonContent&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; 
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IonSegment&lt;/span&gt; &lt;span class="nx"&gt;onIonChange&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toggle&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;success&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IonSegmentButton&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Global&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;success&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;checked&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;segment&lt;/span&gt;&lt;span class="o"&gt;===&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Global&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IonLabel&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Global&lt;/span&gt; &lt;span class="nx"&gt;Feed&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/IonLabel&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;              &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/IonSegmentButton&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;              &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;isLogin&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;true&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IonSegmentButton&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;myfeed&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;color&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;success&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
                  &lt;span class="nx"&gt;checked&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;segment&lt;/span&gt;&lt;span class="o"&gt;===&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;myfeed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
                  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IonLabel&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;Your&lt;/span&gt; &lt;span class="nx"&gt;Feed&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/IonLabel&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;              &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/IonSegmentButton&amp;gt; : '' &lt;/span&gt;&lt;span class="err"&gt;}
&lt;/span&gt;          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/IonSegment&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IonList&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;articles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="na"&gt;article&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; 
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ArticleCard&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;article&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;article&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;article&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;author&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;article&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;favorited&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;article&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;favorited&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;favoritesCount&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;article&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;favoritesCount&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;article&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slug&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;author&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;article&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;author&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/ArticleCard&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="p"&gt;)}&lt;/span&gt;      
        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/IonList&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;TagCloud&lt;/span&gt; &lt;span class="nx"&gt;onTagClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{(&lt;/span&gt;&lt;span class="na"&gt;e&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;handleTagClick&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/TagCloud&amp;gt;  &lt;/span&gt;&lt;span class="err"&gt; 
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/IonContent&amp;gt;   &lt;/span&gt;&lt;span class="err"&gt; 
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;toggle&lt;/code&gt; and &lt;code&gt;handleTagClick&lt;/code&gt; functions are in the source code. &lt;/p&gt;

&lt;h3&gt;
  
  
  Article Page
&lt;/h3&gt;

&lt;p&gt;We are fetching an individual article by &lt;code&gt;slug&lt;/code&gt; in the article page. The body of the article is in Markdown format. To display the article, we will be using showdown to convert it. Additionally, comments for the article are fetched from the &lt;code&gt;/articles/slug/comments&lt;/code&gt; endpoint and logged in users can post a comment. We will be creating a separate &lt;code&gt;Comment&lt;/code&gt; component to iterate over the list. To post comments, logged in users can use &lt;code&gt;IonTextArea&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i showdown @types/showdown 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will initialize showdown using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;  this.converter = new Showdown.Converter({
          tables: true,
          simplifiedAutoLink: true,
          strikethrough: true,
          tasklists: true,
          requireSpaceBeforeHeadingText: true
        });  

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And we will display markdown display using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;   &amp;lt;div dangerouslySetInnerHTML={{ __html: this.converter.makeHtml(article.body)}}&amp;gt;&amp;lt;/div&amp;gt;

            &amp;lt;/div&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The rest of the source can be viewed &lt;a href="https://github.com/JscramblerBlog/conduit-ionic-react"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blog.jscrambler.com/protecting-your-react-js-source-code-with-jscrambler/?utm_source=dev.to&amp;amp;utm_medium=referral"&gt;&lt;img alt="Protect your React App with Jscrambler" src="https://res.cloudinary.com/practicaldev/image/fetch/s--Hi7hvKYx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://media.jscrambler.com/blog/V6-React.jpg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Login Page
&lt;/h3&gt;

&lt;p&gt;Login Page is a basic form Page. We will be accepting email and password. The &lt;code&gt;/users/login&lt;/code&gt; endpoint accepts the POST request and returns a JWT token. We will save the JWT token in localstorage to manage our auth. In order to toggle the side menu, we will be using standard JS events. Also, we will be signing up users using the &lt;code&gt;/users&lt;/code&gt; endpoint. Additionally, we are using the &lt;code&gt;IonToast&lt;/code&gt; component to display error messages. The code used for the Login Page is below. &lt;code&gt;IonInput&lt;/code&gt; uses &lt;code&gt;CustomEvent&lt;/code&gt; and we can use the &lt;code&gt;onIonChange&lt;/code&gt; event to bind the input to the state.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="nx"&gt;updateUserName&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;any&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;detail&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;  
  &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="nx"&gt;login&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;credentials&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;     
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;  &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Login&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
      &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;CONFIG&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;API_ENDPOINT&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/users/login&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;credentials&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;password&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;CONFIG&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;API_ENDPOINT&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/users&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="nx"&gt;credentials&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;password&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
          &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;username&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;application/json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;              
            &lt;span class="p"&gt;},&lt;/span&gt;
            &lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;credentials&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;  
            &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SignUp&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Error creating user&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Error Logging in&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  
            &lt;span class="p"&gt;}&lt;/span&gt;                
          &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
          &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;    
              &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;token&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;token&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;       
              &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;username&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
              &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;isLogin&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;true&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
              &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;email&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

              &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;CustomEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;loggedIn&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;detail&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
              &lt;span class="p"&gt;});&lt;/span&gt;
              &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dispatchEvent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
              &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;history&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/blog&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
          &lt;span class="p"&gt;},&lt;/span&gt;

          &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
           &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;           
           &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;toastMessage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="na"&gt;toastState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
          &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(){&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Header&lt;/span&gt; &lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Login&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/Header&amp;gt;   &lt;/span&gt;&lt;span class="err"&gt; 
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IonContent&lt;/span&gt; &lt;span class="nx"&gt;padding&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ion-text-center&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;img&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;image&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;alt&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;logo&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;width&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;25%&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt; 
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/div&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;h1&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;ion-text-center conduit-title&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="nx"&gt;conduit&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/h1&amp;gt;     &lt;/span&gt;&lt;span class="err"&gt; 
&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IonToast&lt;/span&gt;
        &lt;span class="nx"&gt;isOpen&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toastState&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nx"&gt;onDidDismiss&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setState&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;toastState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt; &lt;span class="p"&gt;}))}&lt;/span&gt;
        &lt;span class="nx"&gt;message&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toastMessage&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="nx"&gt;duration&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;400&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
      &lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/IonToast&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;form&lt;/span&gt; &lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IonItem&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;

      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IonInput&lt;/span&gt;  &lt;span class="nx"&gt;onIonChange&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;updateEmail&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;email&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;placeholder&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Email&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/IonInput&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/IonItem&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SignUp&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt;    
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IonItem&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;

        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IonInput&lt;/span&gt; &lt;span class="nx"&gt;onIonChange&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;updateUserName&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;text&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;placeholder&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Username&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/IonInput&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/IonItem&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/&amp;gt; &lt;/span&gt;&lt;span class="err"&gt;}
&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IonItem&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IonInput&lt;/span&gt; &lt;span class="nx"&gt;onIonChange&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;updatePassword&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;password&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="nx"&gt;placeholder&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Password&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/IonInput&amp;gt;     &lt;/span&gt;&lt;span class="err"&gt; 
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/IonItem&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/form&amp;gt;     &lt;/span&gt;&lt;span class="err"&gt; 
&lt;/span&gt;
            &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IonButton&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;login&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/IonButton&amp;gt;        &lt;/span&gt;&lt;span class="err"&gt; 
&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/IonContent&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IonFooter&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;IonToolbar&lt;/span&gt; &lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;center&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="nx"&gt;Click&lt;/span&gt; &lt;span class="nx"&gt;here&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;a&lt;/span&gt; &lt;span class="nx"&gt;onClick&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toggleAction&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;action&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Login&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SignUp&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Login&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/a&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/IonToolbar&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/IonFooter&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  New Article Page
&lt;/h3&gt;

&lt;p&gt;This page is a form page like the login page. However, for the article body, we will be using a Markdown editor instead of a text area. For this tutorial, we are going to use &lt;a href="https://github.com/andrerpena/react-mde"&gt;react-mde&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install --save react-mde
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The form code is as below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;form&lt;/span&gt; &lt;span class="na"&gt;onSubmit=&lt;/span&gt;&lt;span class="s"&gt;{this.submitArticle}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;IonInput&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Title"&lt;/span&gt; &lt;span class="na"&gt;onIonChange=&lt;/span&gt;&lt;span class="s"&gt;{this.titleChange}&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"border-input"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/IonInput&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;IonInput&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt; &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"What's this article about"&lt;/span&gt;  &lt;span class="na"&gt;onIonChange=&lt;/span&gt;&lt;span class="s"&gt;{this.descriptionChange}&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"border-input"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/IonInput&amp;gt;&lt;/span&gt;

          &lt;span class="nt"&gt;&amp;lt;ReactMde&lt;/span&gt;
          &lt;span class="na"&gt;onChange=&lt;/span&gt;&lt;span class="s"&gt;{this.handleBodyChange}&lt;/span&gt;
          &lt;span class="na"&gt;onTabChange=&lt;/span&gt;&lt;span class="s"&gt;{this.handleTabChange}&lt;/span&gt;
          &lt;span class="na"&gt;value=&lt;/span&gt;&lt;span class="s"&gt;{this.state.articleBody}&lt;/span&gt;
          &lt;span class="na"&gt;selectedTab=&lt;/span&gt;&lt;span class="s"&gt;{this.state.tab}&lt;/span&gt;
          &lt;span class="na"&gt;generateMarkdownPreview=&lt;/span&gt;&lt;span class="s"&gt;{markdown&lt;/span&gt; &lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            Promise.resolve(this.converter.makeHtml(markdown))
          }
        /&amp;gt;
         &lt;span class="nt"&gt;&amp;lt;IonInput&lt;/span&gt; &lt;span class="na"&gt;type=&lt;/span&gt;&lt;span class="s"&gt;"text"&lt;/span&gt;  &lt;span class="na"&gt;placeholder=&lt;/span&gt;&lt;span class="s"&gt;"Enter Tags"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"border-input"&lt;/span&gt;  &lt;span class="na"&gt;onIonChange=&lt;/span&gt;&lt;span class="s"&gt;{this.tagsChange}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&amp;lt;/IonInput&amp;gt;&lt;/span&gt;
         &lt;span class="nt"&gt;&amp;lt;IonButton&lt;/span&gt; &lt;span class="na"&gt;expand=&lt;/span&gt;&lt;span class="s"&gt;"block"&lt;/span&gt; &lt;span class="na"&gt;onClick=&lt;/span&gt;&lt;span class="s"&gt;{this.submitArticle}&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Submit Article&lt;span class="nt"&gt;&amp;lt;/IonButton&amp;gt;&lt;/span&gt;        
      &lt;span class="nt"&gt;&amp;lt;/form&amp;gt;&lt;/span&gt;    
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Creating a Build Using Capacitor
&lt;/h3&gt;

&lt;p&gt;We will use &lt;code&gt;run build&lt;/code&gt; to build our React project:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm run build
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will then use Capacitor to copy the files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx capacitor copy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, we will need to compile the project natively:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx capacitor open android|ios
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Final Thoughts
&lt;/h2&gt;

&lt;p&gt;My mileage while developing Conduit varied a lot. Conduit doesn't have a spec for mobile, so it took a while to figure out the best workflow.&lt;/p&gt;

&lt;p&gt;We can improve the app by using middleware like &lt;a href="https://blog.jscrambler.com/becoming-familiar-with-redux/"&gt;Redux&lt;/a&gt;, using skeletons loaders at places, integrating infinite scroll and handling errors better. To complete the app experience, we will have to modify the backend so it can handle push notifications. A notification system makes sense if you receive a new follower or if a person you are following publishes a new post.&lt;/p&gt;

&lt;p&gt;As far as Ionic React is concerned, it felt like I was developing a React web application using a set of predefined components. Components like &lt;code&gt;IonInfiniteScroll&lt;/code&gt; are still WIP and we can hope to get them soon. Personally, I missed the tight integration of the framework and the side menu template. We can expect full Ionic CLI and Cordova support in the future.&lt;/p&gt;

&lt;p&gt;Android users can check the app &lt;a href="https://play.google.com/store/apps/details?id=me.karandpr.conduit"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Lastly, if you're building an application with sensitive logic, be sure to protect it against code theft and reverse-engineering by following our guides for &lt;a href="https://blog.jscrambler.com/protecting-your-react-js-source-code-with-jscrambler/?utm_source=dev.to&amp;amp;utm_medium=referral"&gt;React&lt;/a&gt; and for &lt;a href="https://blog.jscrambler.com/protecting-hybrid-mobile-apps-with-ionic-and-jscrambler/?utm_source=dev.to&amp;amp;utm_medium=referral"&gt;Ionic&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Originally published by Karan Gandhi in the &lt;a href="https://blog.jscrambler.com/"&gt;Jscrambler Blog&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>react</category>
      <category>ionic</category>
      <category>javascript</category>
      <category>mobile</category>
    </item>
    <item>
      <title>Create a File Storage Mobile App with NativeScript 5</title>
      <dc:creator>Karan Gandhi</dc:creator>
      <pubDate>Mon, 04 Mar 2019 17:34:24 +0000</pubDate>
      <link>https://dev.to/jscrambler/create-a-file-storage-mobile-app-with-nativescript-5-18n8</link>
      <guid>https://dev.to/jscrambler/create-a-file-storage-mobile-app-with-nativescript-5-18n8</guid>
      <description>&lt;p&gt;In this article, let's create a small demo project with NativeScript 5. To start with, let’s set up a scenario for the demo.&lt;/p&gt;

&lt;p&gt;SimpleFileTransfer is a virtual file locker. Users can sign up for the service and get 100 MB of free virtual storage space. Users can then download and upload files on a server. Users will be able to increase their storage space by filling a form.&lt;/p&gt;

&lt;p&gt;Let’s jot down the App functionalities before moving ahead:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;   Signup: User can signup for the app.&lt;/li&gt;
&lt;li&gt;   Login: Authenticates user.&lt;/li&gt;
&lt;li&gt;   Details Page: Provides user details like current quota and total space. Also, we can display a list of files.&lt;/li&gt;
&lt;li&gt;   Download file: Download file from the server to a device.&lt;/li&gt;
&lt;li&gt;   Upload file: Upload files from a device to the server.&lt;/li&gt;
&lt;li&gt;   Increase Quota: Increases storage quota of a user by a specified amount.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can find the whole code on &lt;a href="https://github.com/JscramblerBlog/SimpleFileTransfer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Structuring the Backend
&lt;/h2&gt;

&lt;p&gt;The backend must provide the functionalities of managing routes, providing basic authentication and storage, and facilitating file transfers.&lt;/p&gt;

&lt;p&gt;Based on the requirements above, we will be using the following stack:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Node: Server&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://expressjs.com"&gt;Express&lt;/a&gt;:  Middleware&lt;/li&gt;
&lt;li&gt;
&lt;a href="http://docs.sequelizejs.com/"&gt;Sequelize&lt;/a&gt;: ORM Middleware&lt;/li&gt;
&lt;li&gt;SQLite: Database&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We will also be using libraries like &lt;a href="https://github.com/expressjs/multer"&gt;multer&lt;/a&gt; and &lt;a href="https://github.com/kelektiv/node.bcrypt.js/"&gt;bcrypt&lt;/a&gt; for specific functionalities that will be explained later on.&lt;/p&gt;

&lt;h2&gt;
  
  
  Initializing the Backend Project
&lt;/h2&gt;

&lt;p&gt;We will be using express-generator to set up the project. Install &lt;code&gt;express-generator&lt;/code&gt; globally using:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;express-generator &lt;span class="nt"&gt;-g&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Start a new project using the command:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;express file-server
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Navigate to the &lt;code&gt;file-server&lt;/code&gt; directory and install the dependencies using &lt;code&gt;npm install&lt;/code&gt;. Also, install the following dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;multer async sequelize sqlite3 body-parser bcrypt &lt;span class="nt"&gt;--save&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Additionally, we will be creating some extra folders for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Database: Storing SQLite DB &amp;amp; DB script.&lt;/li&gt;
&lt;li&gt;Model: Storing Models.&lt;/li&gt;
&lt;li&gt;Upload: Temporarily storing uploaded files.&lt;/li&gt;
&lt;li&gt;Storage: storing file for specific users.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Starting with Sequelize
&lt;/h3&gt;

&lt;p&gt;&lt;a href="http://docs.sequelizejs.com/"&gt;Sequelize&lt;/a&gt; is an ORM middleware for SQLite, MySQL, PostgreSQL and MSSQL. For small projects, it’s convenient to use the Sequelize + SQLite combo.&lt;/p&gt;

&lt;p&gt;In our current scenario, we require only one Model. We will define our model user as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;User&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;sequelize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="na"&gt;uid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Sequelize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;INTEGER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;primaryKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;autoIncrement&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
       &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Sequelize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;STRING&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;unique&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
       &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Sequelize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;STRING&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="na"&gt;quota&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Sequelize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;INTEGER&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;defaultValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;104857600&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
       &lt;span class="na"&gt;createdAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Sequelize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DATE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
       &lt;span class="na"&gt;updatedAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Sequelize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DATE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We can use Sequelize's  &lt;code&gt;Model.sync&lt;/code&gt; to initialize Models Table in a database. To initialize users table, we will be using the code below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;     &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;sync&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;force&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Table created&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will store the user model in the &lt;code&gt;user.js&lt;/code&gt; file in the model folder.&lt;/p&gt;

&lt;h3&gt;
  
  
  Signup &amp;amp; Login
&lt;/h3&gt;

&lt;p&gt;This part is pretty straightforward. For signup, the server accepts a username and password and stores it in the database. We will be using the bcrypt library to salt the passwords. As shown below, we are salting the password 10 times before storing it in the database. We are using Sequelize's &lt;code&gt;Model.create&lt;/code&gt; to store the value. Once a user is created, we will create a directory on our server for his uploads.&lt;/p&gt;

&lt;p&gt;The code is as below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;     &lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
       &lt;span class="nx"&gt;bcrypt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="nx"&gt;User&lt;/span&gt;
         &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;password&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;hash&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
         &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;    
         &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;existsSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;storage/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;uid&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))){&lt;/span&gt;
         &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;mkdirSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;storage/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;uid&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
         &lt;span class="p"&gt;}&lt;/span&gt; 
           &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;send&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;User created&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;uid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;user&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;uid&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)});&lt;/span&gt;
         &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
           &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;send&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
         &lt;span class="p"&gt;})&lt;/span&gt;
       &lt;span class="p"&gt;});&lt;/span&gt;
     &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For login, the server accepts a username and password and validates it against the database. We are using &lt;code&gt;Model.findAll&lt;/code&gt; to get the database record. We use &lt;code&gt;bcrypt.compare&lt;/code&gt; to compare passwords.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;   &lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
     &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;findAll&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
       &lt;span class="na"&gt;attributes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;username&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;password&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
       &lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;username&lt;/span&gt;
       &lt;span class="p"&gt;}&lt;/span&gt;
     &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dbQ&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;    
         &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dbQ&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
           &lt;span class="nx"&gt;bcrypt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;compare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;dbQ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;dataValues&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;password&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
             &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
               &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;send&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Login Success&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
             &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
               &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;send&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Incorrect Password&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
             &lt;span class="p"&gt;}&lt;/span&gt;            
         &lt;span class="p"&gt;});&lt;/span&gt;
       &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;send&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;User not found&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
       &lt;span class="p"&gt;}&lt;/span&gt;         
     &lt;span class="p"&gt;});&lt;/span&gt;
   &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Defining the Users Route
&lt;/h3&gt;

&lt;p&gt;An authenticated user is allowed to perform the following functions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Upload file&lt;/li&gt;
&lt;li&gt;Download file&lt;/li&gt;
&lt;li&gt;Get Details&lt;/li&gt;
&lt;li&gt;Increase quota&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's define the routes for those functions:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Upload: &lt;code&gt;POST /users/:id/upload&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Download: &lt;code&gt;GET /users/:id/download/:filename&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Details: &lt;code&gt;GET /users/:id/details&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Increase Quota: &lt;code&gt;POST /users/:id/increasequota&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Uploading a File to the Server
&lt;/h3&gt;

&lt;p&gt;We will be using &lt;a href="https://www.npmjs.com/package/multer"&gt;multer&lt;/a&gt; to handle uploads.&lt;/p&gt;

&lt;p&gt;The multer library is useful to handle multi-part form data. Initially, we will be uploading the file to the uploads folder. Then, the file will be moved to &lt;code&gt;/storage/uid&lt;/code&gt; folder where uid is user id.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;   &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;storage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;multer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;diskStorage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
     &lt;span class="na"&gt;destination&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nx"&gt;cb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;uploads/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
     &lt;span class="p"&gt;},&lt;/span&gt;
     &lt;span class="na"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;cb&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nx"&gt;cb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;originalname&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="p"&gt;});&lt;/span&gt;

   &lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/:id/upload&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;upload&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;single&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fileparam&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;No file received&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
       &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;send&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
         &lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
         &lt;span class="na"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Error Uploading files&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
       &lt;span class="p"&gt;});&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;file received&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
       &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rename&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;uploads/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;originalname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;storage/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;originalname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
           &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
               &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
           &lt;span class="p"&gt;}&lt;/span&gt;  
           &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;send&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
             &lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
             &lt;span class="na"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;File Uploaded&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
           &lt;span class="p"&gt;})&lt;/span&gt;   
       &lt;span class="p"&gt;});&lt;/span&gt;   
     &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;upload.single&lt;/code&gt; method is used for handling uploads. This route is expecting a file with name &lt;code&gt;fileparam&lt;/code&gt; in the URL call. This is quickly done by adding a name attribute an HTML form. We will need the name attribute app side.&lt;/p&gt;

&lt;h3&gt;
  
  
  Download Route
&lt;/h3&gt;

&lt;p&gt;ExpressJS provides us with a function to set the download route, conveniently called download.&lt;/p&gt;

&lt;p&gt;This is the logic we are following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A user logs into the app.&lt;/li&gt;
&lt;li&gt;He selects a file and initiates the download.&lt;/li&gt;
&lt;li&gt;The server receives a request with userid and filename.&lt;/li&gt;
&lt;li&gt;The server sends the file back to the user.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The code for the route is below&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;    &lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/:id/download/:filename&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;storage/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
         &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;download&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Increase User Quota Route
&lt;/h3&gt;

&lt;p&gt;We will be invoking &lt;code&gt;Model.update&lt;/code&gt; to adjust the quota. By default, we have 104857600 bytes — which is equivalent to 100 MB — assigned to each user. You can find the query below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;   &lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/:id/increasequota&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;update&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
       &lt;span class="na"&gt;quota&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;body&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;quota&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="na"&gt;uid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;        
       &lt;span class="p"&gt;}&lt;/span&gt;
     &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;send&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Quota Increased&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
     &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;send&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;status&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
     &lt;span class="p"&gt;});&lt;/span&gt; 
   &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  User Details Route
&lt;/h3&gt;

&lt;p&gt;This is a route which we will be using for fetching multiple data, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Storage Limit of user: from the DB,&lt;/li&gt;
&lt;li&gt;Current File Space occupied: from the &lt;code&gt;/storage/userid&lt;/code&gt; directory,&lt;/li&gt;
&lt;li&gt;Space Remaining: it's just Point 1 - Point 2,&lt;/li&gt;
&lt;li&gt;File List: list of Files,&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We can fetch the storage limit of a user using &lt;code&gt;Model.findAll&lt;/code&gt;. For fetching file names and storage space, we are using &lt;code&gt;fs .readdir&lt;/code&gt;, &lt;code&gt;fs.stat&lt;/code&gt; and &lt;code&gt;async&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;   &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getStorageSpace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;relpath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;space&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
     &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;fileNames&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
     &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;promise&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;readdir&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;relpath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
           &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
         &lt;span class="p"&gt;}&lt;/span&gt;
         &lt;span class="nx"&gt;fileNames&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
         &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;filesArr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
           &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;relpath&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;val&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
         &lt;span class="p"&gt;});&lt;/span&gt;
         &lt;span class="k"&gt;async&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;filesArr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stat&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

           &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
             &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
               &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
             &lt;span class="p"&gt;}&lt;/span&gt;
             &lt;span class="nx"&gt;space&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;space&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;results&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
           &lt;span class="p"&gt;}&lt;/span&gt;
           &lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;fileNames&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;fileNames&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;space&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;space&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
         &lt;span class="p"&gt;});&lt;/span&gt;
       &lt;span class="p"&gt;});&lt;/span&gt;
     &lt;span class="p"&gt;});&lt;/span&gt;
     &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;promise&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;

   &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;getStorageLimit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;uid&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
     &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;promise&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nx"&gt;User&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;findAll&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
         &lt;span class="na"&gt;attributes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;quota&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
         &lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
           &lt;span class="na"&gt;uid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;uid&lt;/span&gt;
         &lt;span class="p"&gt;}&lt;/span&gt;
       &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dbQ&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

         &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dbQ&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
           &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Quota Not Found&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
         &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
           &lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dbQ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;dataValues&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;quota&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
         &lt;span class="p"&gt;}&lt;/span&gt;     
       &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
       &lt;span class="p"&gt;});&lt;/span&gt;
     &lt;span class="p"&gt;});&lt;/span&gt;
     &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;promise&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
   &lt;span class="p"&gt;}&lt;/span&gt;

   &lt;span class="nx"&gt;router&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/:id/details&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
     &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;relpath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;storage/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
     &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;all&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;getStorageSpace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;relpath&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;getStorageLimit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)]).&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

       &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;send&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;storageLimit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="na"&gt;occupiedSpace&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;space&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;fileNames&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;fileNames&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;remainingSpace&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;space&lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
     &lt;span class="p"&gt;})&lt;/span&gt;
   &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;N.B.:&lt;/strong&gt; The code works on assumption that user is not allowed to create a subdirectory in his folder.&lt;/p&gt;

&lt;p&gt;The code for enforcing storage limit will be discussed later in the article.&lt;/p&gt;

&lt;h2&gt;
  
  
  NativeScript App
&lt;/h2&gt;

&lt;p&gt;For the app side, we will be taking an alternative approach.  A demo project based on Angular-Blank template will be shared with users. A significant part of this article will cover details about plugins concerning the plugin functionalities.&lt;/p&gt;

&lt;h3&gt;
  
  
  Consuming Web Services
&lt;/h3&gt;

&lt;p&gt;We are consuming data from simple web services for Login / Signup / User Details Page.&lt;/p&gt;

&lt;p&gt;As mentioned in the &lt;a href="https://blog.jscrambler.com/introduction-to-nativescript/"&gt;previous article&lt;/a&gt;, we can access these webservices using the &lt;a href="https://docs.nativescript.org/angular/ng-framework-modules/http"&gt;HttpClient Module&lt;/a&gt;. The basic steps are as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Import &lt;code&gt;NativeScriptHttpClientModule&lt;/code&gt; in the PageModule.&lt;/li&gt;
&lt;li&gt;Import &lt;code&gt;HttpClient&lt;/code&gt; and &lt;code&gt;HttpHeaders&lt;/code&gt; in Component or Provider.&lt;/li&gt;
&lt;li&gt;Consume the URL as you will in an Angular application.&lt;/li&gt;
&lt;li&gt;We will set &lt;code&gt;Content-Type&lt;/code&gt; header to &lt;code&gt;application/json&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For the JavaScript/TypeScript templates, we can use the NativeScript Core &lt;a href="https://docs.nativescript.org/angular/ng-framework-modules/http#http"&gt;http&lt;/a&gt; module. The &lt;code&gt;http. getJson&lt;/code&gt; function provides the required framework to consume webservices. Alternatively, we can also use the &lt;a href="https://docs.nativescript.org/ns-framework-modules/fetch"&gt;fetch&lt;/a&gt; module.&lt;/p&gt;

&lt;p&gt;As a response from the server, we will be receiving the &lt;code&gt;uid&lt;/code&gt; of a user. After authentication, we need to store the &lt;code&gt;uid&lt;/code&gt; so we can allow a mobile user to access &lt;code&gt;/users/uid route&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Storing Data
&lt;/h3&gt;

&lt;p&gt;The NativeScript framework doesn't have any method to store data persistently. We can add that functionality using plugins. We are going to look at two of these plugins.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.npmjs.com/package/nativescript-sqlite"&gt;nativescript-sqlite&lt;/a&gt;: This plugin provides an interface for the SQLite library. This works well if your app needs to store a large volume of records. Install it with:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;tns plugin add nativescript-sqlite
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.npmjs.com/package/nativescript-localstorage"&gt;nativescipt-localstorage&lt;/a&gt;: This plugins provides a key value API for string data, similar to &lt;code&gt;window.localstorage&lt;/code&gt;. This works well if your app doesn't have lot of records. Install it with:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;tns plugin add nativescript-localstorage
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The demo app will be using &lt;code&gt;nativescript-localstorage&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://blog.jscrambler.com/protecting-your-nativescript-source-code-with-jscrambler/"&gt;&lt;img alt="Protect your NativeScript App with Jscrambler" src="https://res.cloudinary.com/practicaldev/image/fetch/s--ddMcNtqh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://media.jscrambler.com/blog/nativescript-ad.jpg"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Uploading Files from a Device to a Server
&lt;/h3&gt;

&lt;p&gt;Let's break this functionality into subtasks:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Choose Files from the device.&lt;/li&gt;
&lt;li&gt;Get File Path.&lt;/li&gt;
&lt;li&gt;Upload File over uploads WebService.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To choose a file and get a file path, we will be using the &lt;code&gt;nativescript-mediapicker&lt;/code&gt; plugin.  The plugin has multiple modes and we can customize it for specific use cases. You can check the plugin documentation &lt;a href="https://github.com/jibon57/nativescript-mediafilepicker"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To select a file, first, we need to define extensions. This is different for both OSes.&lt;/p&gt;

&lt;p&gt;For Android devices, we have to use file extensions based on mime types like &lt;code&gt;let extensions = ["xlsx", "xls", "doc", "docx", "ppt", "pptx", "pdf", "txt", "png"]&lt;/code&gt;&lt;br&gt;
For iOS devices, we have to define extensions from list for Unified Type identifiers: &lt;code&gt;let extensions = [kUTTypePDF, kUTTypeText];&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;You can read more about UTIs &lt;a href="https://developer.apple.com/documentation/mobilecoreservices/uttype"&gt;here&lt;/a&gt; and &lt;a href="https://developer.apple.com/library/archive/documentation/Miscellaneous/Reference/UTIRef/Articles/System-DeclaredUniformTypeIdentifiers.html"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The code for invoking &lt;code&gt;filepicker&lt;/code&gt; is as below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;   &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;FilePickerOptions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="na"&gt;android&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
           &lt;span class="na"&gt;extensions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;extensions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="na"&gt;maxNumberFiles&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
       &lt;span class="p"&gt;},&lt;/span&gt;
       &lt;span class="na"&gt;ios&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
           &lt;span class="na"&gt;extensions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;extensions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="na"&gt;multipleSelection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
       &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="p"&gt;};&lt;/span&gt;

   &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;mediafilepicker&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;Mediafilepicker&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
   &lt;span class="nx"&gt;mediafilepicker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;openFilePicker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

   &lt;span class="s2"&gt;`mediafilepicker.on("getFiles", function (res) {
       let results = res.object.get('results');
       console.dir(results);
   });

   mediafilepicker.on("error", function (res) {
       let msg = res.object.get('msg');
       console.log(msg);
   });

   mediafilepicker.on("cancel", function (res) {
       let msg = res.object.get('msg');
       console.log(msg);
   });`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As above, we will receive the filepath of a file in the &lt;code&gt;getFiles&lt;/code&gt; event.&lt;/p&gt;

&lt;p&gt;We will send the file to the server using the &lt;code&gt;nativescript-background-http&lt;/code&gt; plugin. You can read about the plugin &lt;a href="https://github.com/NativeScript/nativescript-background-http"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Earlier, we defined the &lt;code&gt;/users/:id/upload&lt;/code&gt; route. As mentioned earlier, our server is expecting the file in the attribute named &lt;code&gt;fileparam&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The background &lt;code&gt;http&lt;/code&gt; provides us with two functions: &lt;code&gt;uploadFile&lt;/code&gt; and &lt;code&gt;multipartUpload&lt;/code&gt;. Since we need to set the name attribute, we will be using the &lt;code&gt;multiPartUpload&lt;/code&gt; function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;bgHttp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;image-upload&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;bgHttp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Request&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;url&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;Config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;apiUrl&lt;/span&gt;  &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/users/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;localStorage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;uid&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/upload&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;   &lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;method&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;POST&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Content-Type&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;multipart/form-data&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;FileName&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;
        &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;file&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;
    &lt;span class="p"&gt;}];&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;bgHttp&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Task&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;multipartUpload&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;request&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;error&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="nx"&gt;task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;on&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;complete&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt; 


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Downloading a File to the Device
&lt;/h3&gt;

&lt;p&gt;We will be using the core &lt;a href="https://docs.nativescript.org/ns-framework-modules/file-system"&gt;file-system&lt;/a&gt;, &lt;a href="https://docs.nativescript.org/ns-framework-modules/platform"&gt;platform&lt;/a&gt; and &lt;a href="https://docs.nativescript.org/core-concepts/utils"&gt;utils&lt;/a&gt; modules to achieve the result. Both Android and iOS handle downloads differently.  We will be using &lt;code&gt;isAndroid&lt;/code&gt; and &lt;code&gt;isIOS&lt;/code&gt; variables from platform module to segregate the code.&lt;/p&gt;

&lt;p&gt;The file-system module provides us with a &lt;code&gt;knownFolders&lt;/code&gt; sub-module. Three predefined folders for both Android and iOS are available:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;knownFolders.currentApp()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;knownFolders.documents()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;knownFolders.temp()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Additionally, an &lt;a href="https://docs.nativescript.org/api-reference/modules/_file_system_.knownfolders.ios"&gt;iOS sub-module&lt;/a&gt; provides us with some other predefined folders. E.g:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;knownFolders.ios.download&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;knownFolders.ios.sharedPublic&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  iOS Code
&lt;/h4&gt;

&lt;p&gt;On an iOS scenario, this is straightforward:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Show a list of server files.&lt;/li&gt;
&lt;li&gt;Download the files to the documents folder.&lt;/li&gt;
&lt;li&gt;List downloaded files in a separate view&lt;/li&gt;
&lt;li&gt;Use the &lt;code&gt;utils.openFile&lt;/code&gt; function to open the file.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To download the files, we will be using the &lt;a href="https://docs.nativescript.org/ns-framework-modules/http"&gt;http&lt;/a&gt; module of the NativeScript framework. The &lt;code&gt;getFile&lt;/code&gt; function can be used to fetch files from the server and save them to a specific file location. The snippet for iOS is below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;      &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;knownFolders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;documents&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fileName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
           &lt;span class="nx"&gt;getFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;download_url&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;fileName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resultFile&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                   &lt;span class="c1"&gt;// The returned result will be File object&lt;/span&gt;
   &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the file has been downloaded, we can use the &lt;code&gt;openFile&lt;/code&gt; function from the &lt;code&gt;utils&lt;/code&gt; module to open a file on iOS.&lt;/p&gt;

&lt;h4&gt;
  
  
  Android Code
&lt;/h4&gt;

&lt;p&gt;The Android side of coding is a bit trickier. The locations of the &lt;code&gt;knownFolders&lt;/code&gt; module are as below.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;currentFolder:  &lt;code&gt;/data/data/:appid/files/app&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;documents: &lt;code&gt;/data/user/:androiduser/:appid/files&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;temp:  &lt;code&gt;/data/user/:androiduser/:appid/cache&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As you can see, all the folders are located in &lt;code&gt;/data&lt;/code&gt;. &lt;code&gt;/data&lt;/code&gt; is inaccessible to normal users. Furthermore, external apps won't be able to access the files in those folders. Also, there is no &lt;code&gt;openFile&lt;/code&gt; function for Android.&lt;/p&gt;

&lt;p&gt;As of now, the best we can do is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Show a list of server files.&lt;/li&gt;
&lt;li&gt;Download a file to a user accessible location.&lt;/li&gt;
&lt;li&gt;List the files present in the location.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To implement the functionality, we will be using a bit of native code.&lt;br&gt;
Before moving ahead, we will have to install &lt;code&gt;tns-platform-declarations&lt;/code&gt; with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm i tns-platform-declarations &lt;span class="nt"&gt;--save&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create a &lt;code&gt;reference.d.ts&lt;/code&gt; file in the root folder and add the following lines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="s2"&gt;`/// &amp;lt;reference path="./node_modules/tns-platform-declarations/ios.d.ts" /&amp;gt;`&lt;/span&gt;
&lt;span class="s2"&gt;`/// &amp;lt;reference path="./node_modules/tns-platform-declarations/android.d.ts" /&amp;gt;`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can check the &lt;a href="https://github.com/NativeScript/NativeScript/tree/master/tns-platform-declarations"&gt;readme&lt;/a&gt; for more details.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developer.android.com/reference/android/os/Environment"&gt;Android OS&lt;/a&gt; provides us with a function to access the external storage.&lt;/p&gt;

&lt;p&gt;We will be using the constant &lt;code&gt;DIRECTORY_DOWNLOADS&lt;/code&gt; and the function &lt;code&gt;getExternalStoragePublicDirectory&lt;/code&gt; to create a publicly accessible download location.&lt;/p&gt;

&lt;p&gt;We will append a path “SimpleFileTransfer” to create a custom &lt;code&gt;folderPath&lt;/code&gt; and &lt;code&gt;filePath&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;androidDownloadsPath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;android&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getExternalStoragePublicDirectory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;android&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DIRECTORY_DOWNLOADS&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;androidFolderPath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;androidDownloadsPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;SimpleFileTransfer&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;androidFolderPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;fileName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="nx"&gt;getFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;download_url&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;fileName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;resultFile&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                   &lt;span class="c1"&gt;// The returned result will be File object&lt;/span&gt;
   &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you check your file explorer, a new directory will be created in the Downloads folder called SimpleFileTransfer. You will find all the files downloaded there.&lt;/p&gt;

&lt;h3&gt;
  
  
  Listing Downloaded Files
&lt;/h3&gt;

&lt;p&gt;We will be using the &lt;code&gt;file-system&lt;/code&gt; module. The Folder class of the &lt;code&gt;file-system&lt;/code&gt; module has a &lt;a href="https://docs.nativescript.org/ns-framework-modules/file-system#read"&gt;getEntities&lt;/a&gt; function which allows us to list files in a folder. As with &lt;code&gt;fs.readdir&lt;/code&gt; in Node.js, we can only list the files.&lt;/p&gt;

&lt;p&gt;For iOS, the path is&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt;  &lt;span class="nx"&gt;folderPath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="nx"&gt;string&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt;  &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;knownFolders&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;documents&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For Android, the path is&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;androidDownloadsPath&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt;  &lt;span class="nx"&gt;android&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getExternalStoragePublicDirectory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;android&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DIRECTORY_DOWNLOADS&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="s2"&gt;`const  folderPath=  fs.path.join(androidDownloadsPath, "SimpleFileTransfer");`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To access the Folder functions, we define a folder using&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;let&lt;/span&gt;  &lt;span class="nx"&gt;internalFolder&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt;  &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Folder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fromPath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;folderPath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, we use &lt;code&gt;getEntities&lt;/code&gt; to get a list of files:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;   &lt;span class="nx"&gt;internalFolder&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getEntities&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
               &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;entities&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                   &lt;span class="c1"&gt;// entities is array with the document's files and folders.&lt;/span&gt;

                   &lt;span class="nx"&gt;entities&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                   &lt;span class="kd"&gt;let&lt;/span&gt;  &lt;span class="nx"&gt;fileSize&lt;/span&gt;  &lt;span class="o"&gt;=&lt;/span&gt;  &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;fromPath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                       &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;listArray&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
                           &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                           &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                           &lt;span class="na"&gt;lastModified&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;entity&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;lastModified&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
                           &lt;span class="na"&gt;size&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;fileSize&lt;/span&gt;
                       &lt;span class="p"&gt;});&lt;/span&gt;
                   &lt;span class="p"&gt;});&lt;/span&gt;                  
               &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="k"&gt;catch&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                   &lt;span class="c1"&gt;// Failed to obtain folder's contents.&lt;/span&gt;
                   &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stack&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
               &lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Additionally, we have used the size property of File class to get file size.&lt;/p&gt;

&lt;h3&gt;
  
  
  Enforcing Storage Limit
&lt;/h3&gt;

&lt;p&gt;The storage limit can be enforced in two ways:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Upload file to the server --&amp;gt; Checking remaining space --&amp;gt; Reject the upload on the server side.&lt;/li&gt;
&lt;li&gt;Check remaining space using webservice --&amp;gt;  Check file size --&amp;gt; Cancel the upload on the app side.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To enforce the former, we can modify the upload route as below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;   &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;all&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="nx"&gt;getStorageSpace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;relpath&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="nx"&gt;getStorageLimit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)]).&lt;/span&gt;&lt;span class="nx"&gt;then&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;space&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;size&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
       &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rename&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;uploads/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;originalname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;storage/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nx"&gt;req&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;originalname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
           &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;send&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
             &lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
             &lt;span class="na"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Error Uploading files&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
           &lt;span class="p"&gt;});&lt;/span&gt;
         &lt;span class="p"&gt;}&lt;/span&gt;  
         &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;send&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
           &lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="na"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;File Uploaded&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
         &lt;span class="p"&gt;})&lt;/span&gt;   
     &lt;span class="p"&gt;});&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;send&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
         &lt;span class="na"&gt;success&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
         &lt;span class="na"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Storage Limit Exceeded&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
       &lt;span class="p"&gt;});&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt; 
     &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To enforce the latter, we get the file size of the file selected by the &lt;code&gt;mediafilepicker&lt;/code&gt; plugin and check it against the space remaining using the details webservice.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="s2"&gt;`let  fileSize  =  fs.File.fromPath(results[0].file).size;`&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;fileSize&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;remainingSpace&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
    &lt;span class="c1"&gt;// Send To server&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`else {
   // alert user about lack of space
   }
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Closing Thoughts
&lt;/h2&gt;

&lt;p&gt;This demo covers quite a few different concepts.&lt;/p&gt;

&lt;p&gt;We divided the solution into a series of functionalities. We used core NativeScript for UX, interacting with the backend, file system management, and Routing. We extended the framework by installing plugins for functionalities like picking files. Going further, we used a bit of native code for solving a specific problem.&lt;/p&gt;

&lt;p&gt;Using NativeScript allowed us to develop the app faster for both platforms as against individually.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you want to learn how you can secure your NativeScript source code against theft and reverse-engineering, be sure to check &lt;a href="https://blog.jscrambler.com/protecting-your-nativescript-source-code-with-jscrambler/?utm_source=dev.to&amp;amp;utm_medium=referral"&gt;our tutorial&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This article was originally published on the &lt;a href="https://blog.jscrambler.com/create-a-file-storage-mobile-app-with-nativescript-5/?utm_source=dev.to&amp;amp;utm_medium=referral"&gt;Jscrambler Blog&lt;/a&gt; by Karan Gandhi&lt;/strong&gt;.&lt;/p&gt;

</description>
      <category>nativescript</category>
      <category>javascript</category>
      <category>node</category>
      <category>express</category>
    </item>
  </channel>
</rss>
