{"componentChunkName":"component---src-templates-blog-list-template-js","path":"/engineering/6","result":{"data":{"allMarkdownRemark":{"edges":[{"node":{"excerpt":"Securing communications between a client and a server often requires credentials to identify both parties. That is where the different…","fields":{"slug":"/engineering/cookie-based-vs-cookieless-authentication/"},"html":"<p>Securing communications between a client and a server often requires credentials to identify both parties. That is where the different authentication techniques comes in. Two popular authentication methods are cookie-based and cookieless authentication. However, choosing any one of them depends on the organization's requirements. Both come with their benefits and challenges. This article will give a quick walkthrough of cookie-based and cookieless authentication along with their advantages and disadvantages.</p>\n<h2 id=\"what-is-cookie-based-authentication\" style=\"position:relative;\"><a href=\"#what-is-cookie-based-authentication\" aria-label=\"what is cookie based authentication permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>What is Cookie-based Authentication?</h2>\n<p>Cookies are pieces of data used to identify the user and their preferences. The browser returns the cookie to the server every time the page is requested. Specific cookies like HTTP cookies are used to perform cookie-based authentication to maintain the session for each user.</p>\n<p>The entire cookie-based authentication works in the following manner:</p>\n<ol>\n<li>The user gives a username and password at the time of login. Once the user fills in the login form, the browser (client) sends a login request to the server.</li>\n<li>\n<p>The server verifies the user by querying the user data. If the authentication request is valid, the server generates the following:</p>\n<ul>\n<li>A session by utilizing the user information</li>\n<li>A unique ID, known as the session ID</li>\n</ul>\n<p>The server then passes the session ID to the browser that keeps it. The server also keeps track of the active sessions.</p>\n</li>\n<li>The browser has to submit this generated session ID while sending a subsequent request. Every time the server validates the session ID. The session ID helps the authentication process identify the user and provides access accordingly.</li>\n<li>When the user logs out of the application, the session gets destroyed from both client (browser) and the server. It discontinues the authentication process from happening again through the respective session ID.</li>\n</ol>\n<h3 id=\"benefits-of-cookie-based-authentication\" style=\"position:relative;\"><a href=\"#benefits-of-cookie-based-authentication\" aria-label=\"benefits of cookie based authentication permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Benefits of Cookie-based Authentication</h3>\n<ul>\n<li><strong>Availability:</strong> In cookies-based authentication, cookies can be made available for an extended period, maintaining a session for a long time.</li>\n<li><strong>Easy Configuration:</strong> Websites can deliver cookies by configuring them as per requirement. For example, a website can send cookies that will expire as the users close the browser tab. It is also possible to configure cookies for a specified length of time on the client-side.</li>\n<li><strong>User-friendly:</strong> Cookie-based authentications are simple, and the cookies used in this method are user-friendly. Users can choose what to do with cookie files that have kept user credentials. All modern browsers come with settings to clear the cookies. Users can find cookies in the hard drive and delete them manually.</li>\n</ul>\n<h3 id=\"challenges-of-cookie-based-authentication\" style=\"position:relative;\"><a href=\"#challenges-of-cookie-based-authentication\" aria-label=\"challenges of cookie based authentication permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Challenges of Cookie-based Authentication</h3>\n<ul>\n<li><strong>Vulnerable to CSRF:</strong> Cookie-based authentications are prone to <a href=\"https://www.loginradius.com/blog/engineering/introduction-to-cross-site-request-forgery-csrf/\">Cross-site Request Forgery (CSRF) attacks</a>. Hence, they often require additional security postures for protection.</li>\n<li><strong>Less Mobile-friendly:</strong> Cookie-based authentication does not work well with all native applications.</li>\n<li><strong>Limitations:</strong> There are certain limitations and concerns such as size limit (not more than 4KB of information per cookie), browser limitations on cookies, user privacy, etc., come with cookies and cookie-based authentication.</li>\n<li><strong>Less Scalable:</strong> Cookie-based authentication is less scalable, and the overhead rises when the user count increases on a particular site.</li>\n</ul>\n<h2 id=\"what-is-cookieless-authentication\" style=\"position:relative;\"><a href=\"#what-is-cookieless-authentication\" aria-label=\"what is cookieless authentication permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>What is Cookieless Authentication?</h2>\n<p>Cookieless authentication, also known as token-based authentication, is a technique that leverages JSON web tokens (JWT) instead of cookies to authenticate a user. It uses a protocol that creates encrypted security tokens. These tokens allow the user to verify their identity. In return, the users receive a unique access token to perform the authentication. The token contains information about user identities and transmits it securely between the server and client.\nThe entire cookieless authentication works in the following manner:</p>\n<ol>\n<li>The user logs into the service by providing their login credentials. It issues an access request from the client-side by sending the credential and API key (public key) to the application server.</li>\n<li>The server verifies the login credentials that checks the password entered against the username. Once approved, the server will generate a unique session token that will help authorize subsequent actions.</li>\n<li>This access token is sent back to the client via URL query strings, post request body, or other means. The server-generated signed authentication token gets assigned with an expiration time.</li>\n<li>The token gets transmitted back to the user's browser. On every subsequent request to the application server or future website visits, the access token gets added to the authorization header along with the public key. If there is a match from the application server against the private key, the user can proceed. If a given token expires, a new token gets generated as an authentication request.</li>\n</ol>\n<h3 id=\"benefits-of-cookieless-authentication\" style=\"position:relative;\"><a href=\"#benefits-of-cookieless-authentication\" aria-label=\"benefits of cookieless authentication permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Benefits of Cookieless Authentication</h3>\n<ul>\n<li><strong>Scalable and Efficient:</strong> In cookieless authentication, the tokens remain stored on the user's end. The server only needs to sign the authentication token once on successful login. That makes the entire technique scalable and allows maintaining more users on an application at once without any hassle.</li>\n<li><strong>Better Performance:</strong> Cookie-based authentication requires the server to perform an authentication lookup every time the user requests a page. You can eliminate the round-trips with tokens through the cookieless authentication technique. In cookieless authentication, the access token and the public key are added to the authorization header on every page request.</li>\n<li><strong>Robust Security:</strong> Since cookieless authentication leverages tokens like JWT (stateless), only a private key (used to create the authentication token) can validate it when received at the server-side.</li>\n<li><strong>Seamless Across Devices:</strong> Cookieless authentication works well with all native applications. Tokens are much easier to implement on iOS, Android, IoT devices, and distributed systems, making the authentication system seamless.</li>\n<li><strong>Expiration Time:</strong> Usually, tokens get generated with an expiration time, after which they become invalid. Then a new token needs to be obtained for reauthentication. If a token gets leaked, the potential damage becomes much smaller due to its short lifespan.</li>\n</ul>\n<h3 id=\"challenges-with-cookieless-authentication\" style=\"position:relative;\"><a href=\"#challenges-with-cookieless-authentication\" aria-label=\"challenges with cookieless authentication permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Challenges with Cookieless Authentication</h3>\n<ul>\n<li><strong>Single-key Token:</strong> One of the significant challenges with cookieless authentication is that these access tokens rely on just one key. Tokens that use JWT leverages a single key for authentication. If the developers/administrators handle the key poorly, it can lead to severe consequences that can compromise sensitive information.</li>\n<li><strong>Data Overhead:</strong> Storing a lot of data increases the overall size of the token. It slows down the request impacting the overall loading speed. This slowing down ultimately hampers the user experience. Thus proper development practices need to be followed, regulating minimum but essential data into the token.</li>\n<li><strong>Vulnerable to XSS and CSRF:</strong> Cookieless authentications are susceptible to <a href=\"https://www.loginradius.com/blog/engineering/http-security-headers/\">XSS</a> and CSRF attacks. So, the best practice is to have a short expiration time for access tokens. Keeping a longer expiration time might allow the attackers to hijack the access token and use it to gain unauthorized authentication.</li>\n</ul>\n<h2 id=\"how-does-loginradius-have-native-support-for-cookieless-authentication\" style=\"position:relative;\"><a href=\"#how-does-loginradius-have-native-support-for-cookieless-authentication\" aria-label=\"how does loginradius have native support for cookieless authentication permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>How does LoginRadius have Native Support for Cookieless Authentication?</h2>\n<p>LoginRadius provides multiple methods to implement a cookieless login workflow leveraging industry and security best practices. As a consumer-centric Identity platform, LoginRadius ensures that modern implementation methodologies comply with the changing security landscape. The cookieless authentication workflows detailed below are systems that LoginRadius has developed support for even before the recent browser-based privacy policies and are a core part of the LoginRadius platform.</p>\n<h3 id=\"loginradius-apis\" style=\"position:relative;\"><a href=\"#loginradius-apis\" aria-label=\"loginradius apis permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>LoginRadius APIs</h3>\n<p>The LoginRadius API has been architected and designed to function as a cookieless authentication system. Once authentication occurs, a session token gets returned to the requesting client in the form of an access token which can be leveraged to take further authorized actions against the Consumer account. It is a core part of the LoginRadius authentication workflows, and APIs developed based on Oauth 2.0 protocols.</p>\n<p>These APIs provide flexibility in generating access tokens based on consumer authentication requests and are automatically validated and signed leveraging the LoginRadius API Key and Secret. <a href=\"https://www.loginradius.com/developers/\">Detailed API documentation is available here</a>.</p>\n<h3 id=\"json-web-tokens\" style=\"position:relative;\"><a href=\"#json-web-tokens\" aria-label=\"json web tokens permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>JSON Web Tokens</h3>\n<p>In addition to the LoginRadius APIs, JWTs are a standard method to handle cookieless login. Once authentication is completed and verified, a signed token can be generated(leveraging LoginRadius APIs) to pass the consumer session to the client.</p>\n<p>JWTs are a standard industry mechanism leveraged by various service providers and tools, making them ideal for interoperability with multiple applications. Find additional details on <a href=\"https://www.loginradius.com/developers/\">how to use JWT as part of your authentication workflows here</a>.</p>\n<h3 id=\"additional-options\" style=\"position:relative;\"><a href=\"#additional-options\" aria-label=\"additional options permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Additional Options</h3>\n<p>In addition to the above two options, LoginRadius provides flexibility and support for various authentication and authorization standards that support a cookieless authentication approach. Outbound authentication workflows such as OIDC and Oauth 2.0 allow for a modern standardized approach to authentication.</p>\n<p>These are industry-recognized and recommended authentication and authorization protocols that comply with security and privacy best practices, including supporting a cookieless authentication approach. Check out <a href=\"https://www.loginradius.com/developers/\">our dedicated documentation on outbound workflows</a>.</p>\n<h2 id=\"conclusion\" style=\"position:relative;\"><a href=\"#conclusion\" aria-label=\"conclusion permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Conclusion</h2>\n<p>Cookieless authentication can facilitate more secure and scalable authentication. You should decide how to authenticate consumers considering your requirements and the benefits and challenges of cookie-based and cookieless authentication.</p>\n<style class=\"grvsc-styles\">\n  .grvsc-container {\n    overflow: auto;\n    -webkit-overflow-scrolling: touch;\n    padding-top: 1rem;\n    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));\n    padding-bottom: 1rem;\n    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));\n    border-radius: 8px;\n    border-radius: var(--grvsc-border-radius, 8px);\n    font-feature-settings: normal;\n  }\n  \n  .grvsc-code {\n    display: inline-block;\n    min-width: 100%;\n  }\n  \n  .grvsc-line {\n    display: inline-block;\n    box-sizing: border-box;\n    width: 100%;\n    padding-left: 1.5rem;\n    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));\n    padding-right: 1.5rem;\n    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));\n  }\n  \n  .grvsc-line-highlighted {\n    background-color: var(--grvsc-line-highlighted-background-color, transparent);\n    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, transparent);\n  }\n  \n</style>","frontmatter":{"date":"December 14, 2021","updated_date":null,"description":"Understand how cookie-based and cookieless authentication methods work. And learn their major differences, advantages, and disadvantages.","title":"Cookie-based vs. Cookieless Authentication: What’s the Future?","tags":["Authentication","JWT","Cookie"],"pinned":null,"coverImage":{"childImageSharp":{"fluid":{"aspectRatio":1.5037593984962405,"src":"/static/581ff70fe87fda67a0bad33af670f950/ee604/coverImage.png","srcSet":"/static/581ff70fe87fda67a0bad33af670f950/69585/coverImage.png 200w,\n/static/581ff70fe87fda67a0bad33af670f950/497c6/coverImage.png 400w,\n/static/581ff70fe87fda67a0bad33af670f950/ee604/coverImage.png 800w,\n/static/581ff70fe87fda67a0bad33af670f950/f3583/coverImage.png 1200w","sizes":"(max-width: 800px) 100vw, 800px"}}},"author":{"id":"Kundan Singh","github":null,"avatar":null}}}},{"node":{"excerpt":"Authentication is an essential part of any web application. But unfortunately, it is not always easy to implement. What is Authentication…","fields":{"slug":"/engineering/guest-post/securing-flask-api-with-jwt/"},"html":"<p>Authentication is an essential part of any web application. But unfortunately, it is not always easy to implement.</p>\n<h2 id=\"what-is-authentication\" style=\"position:relative;\"><a href=\"#what-is-authentication\" aria-label=\"what is authentication permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>What is Authentication?</h2>\n<p>Authentication is a process of verifying that an entity is who they claim to be. For example, a user might authenticate by providing a username and password. If the username and password are valid, the system will check if the user can access the resource. After the system checks the user's details against its database and if the details are valid, the user is thus authenticated and can access available resources.</p>\n<h2 id=\"authentication-factors\" style=\"position:relative;\"><a href=\"#authentication-factors\" aria-label=\"authentication factors permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Authentication Factors</h2>\n<p>The following factors are used to authenticate a user.</p>\n<h3 id=\"single-factor-authentication\" style=\"position:relative;\"><a href=\"#single-factor-authentication\" aria-label=\"single factor authentication permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Single-factor Authentication</h3>\n<p>This authentication is used when a user provides a username/email/phone number and a password. This is the most common and weakest authentication factor. The user simply inputs the email and password, and the system checks if the data is valid; if valid, the user gets authenticated and can access the resource. What happens if another person who is not a legitimate user tries to access the resource? The system denies access to the resource.</p>\n<h3 id=\"multi-factor-authentication\" style=\"position:relative;\"><a href=\"#multi-factor-authentication\" aria-label=\"multi factor authentication permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a><a href=\"https://www.loginradius.com/multi-factor-authentication/\">Multi-factor Authentication</a></h3>\n<p>This authentication uses more than one factor to authenticate a user. For example, the user tries to log in with, say, email and password; if the data is correct, a code is sent to the user's phone number, and the user is asked to input the code. If the user enters the code, the user gets logged in; otherwise, the user is not authenticated. Some applications even go a step further by not using two factors but using three factors.</p>\n<h2 id=\"types-of-authentication\" style=\"position:relative;\"><a href=\"#types-of-authentication\" aria-label=\"types of authentication permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Types of Authentication</h2>\n<p>There are three types of authentication, as follows:</p>\n<ol>\n<li><strong>Knowledge Authentication</strong>: The user is asked something that only they can provide or know -- e.g., password. This is the most common type and also the easiest.</li>\n<li><strong>Property Authentication</strong>: The user is asked for something they own or possess. For example, they can use a hardware authentication device like YubiKey or an authenticator app on their phone. The idea is that users will be asked to set an authentication factor that verifies the identity more securely. This isn’t always used alone; it’s used alongside another authentication type, say, <code>Knowledge authentication</code>.</li>\n<li><strong>Biological Authentication</strong>: The user is asked to verify their identity using something biologically unique to them -- e.g., a fingerprint or iris scan.</li>\n</ol>\n<p>In most applications, knowledge and property authentication are used as an extra layer of authentication.</p>\n<h2 id=\"authentication-vs-authorization\" style=\"position:relative;\"><a href=\"#authentication-vs-authorization\" aria-label=\"authentication vs authorization permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Authentication vs. Authorization</h2>\n<p>The following are the differences between authentication and authorization:</p>\n<ol>\n<li>Authentication verifies identity (usually through credential validation)) while authorization grants or denies permissions to a user.</li>\n<li>Authentication is used to verify that users are who they say they are. Authorization is used to verify that a user has permission to do something.</li>\n</ol>\n<h2 id=\"starter-application\" style=\"position:relative;\"><a href=\"#starter-application\" aria-label=\"starter application permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Starter Application</h2>\n<p>In this tutorial, you'll work on authentication in flask middleware for an existing API built with <a href=\"https://flask.palletsprojects.com/en/2.0.x/\">Flask</a> and <a href=\"https://pymongo.readthedocs.io/en/stable/\">PyMongo</a>. The API is a book library API using which users can create books and upload cover images for the books and relevant data. PyMongo is used to connect to the mongo database. You'll use the PyJWT library to generate and verify JWT tokens for auth in flask.  </p>\n<blockquote>\n<p>You can learn <a href=\"https://www.loginradius.com/blog/engineering/guest-post/jwt-authentication-best-practices-and-when-to-use/\">more about JSON Web Tokens (JWT) here</a>.</p>\n</blockquote>\n<p>To get started, clone the repository and set up the application by running the following commands:</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"bash\" data-index=\"0\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">git clone https://github.com/LoginRadius/engineering-blog-samples.git </span><span class=\"mtk3\"># Clone the repository</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk11\">cd</span><span class=\"mtk1\"> /Flask/loginRadius-flask-auth </span><span class=\"mtk3\"># change directory</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">python3 -m venv env </span><span class=\"mtk3\"># create virtual environment; if you&#39;re using Windows, `py -m venv env`</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk11\">source</span><span class=\"mtk1\"> env/bin/activate </span><span class=\"mtk3\"># activate virtual environment, if you&#39;re using windows, env/Scripts/activate</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">pip install -r requirements.txt </span><span class=\"mtk3\"># install dependencies</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk3\"># https://packaging.python.org/en/latest/guides/installing-using-pip-and-virtual-environments/</span></span></code></pre>\n<p>The application is now set up and ready to run. You can run the app using the command <code>flask run</code> in the project directory. You can test that all the endpoints are working by testing the app in an API testing tool, like Postman.</p>\n<h2 id=\"authentication-middleware\" style=\"position:relative;\"><a href=\"#authentication-middleware\" aria-label=\"authentication middleware permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Authentication Middleware</h2>\n<p>As you've noticed, anybody can access the API; you need to restrict access to the API. Create new book data if they have the correct data, then add, delete, and update book data, but you don't want that. To do this, you need to implement an authentication middleware.</p>\n<p>When we talk about authentication with flask, middlewares are created in Flask by creating a decorator; a function can have multiple middlewares, and the order matters a lot. </p>\n<p>To create your auth middleware, you need to install PyJWT -- the library you'll use to generate tokens. You’ll also use Pillow to alter image data before saving them to disk. Run the following command to install the packages:</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"bash\" data-index=\"1\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">pip install pyjwt pillow</span></span></code></pre>\n<p>You need to add a secret key to your application; this is what you should pass to JWT.</p>\n<p>Add the following to your <code>app.py</code> file below the app declaration.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"python\" data-index=\"2\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk3\"># app = Flask(__name__)</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">SECRET_KEY = os.environ.get(</span><span class=\"mtk8\">&#39;SECRET_KEY&#39;</span><span class=\"mtk1\">) </span><span class=\"mtk4\">or</span><span class=\"mtk1\"> </span><span class=\"mtk8\">&#39;this is a secret&#39;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk11\">print</span><span class=\"mtk1\">(SECRET_KEY)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">app.config[</span><span class=\"mtk8\">&#39;SECRET_KEY&#39;</span><span class=\"mtk1\">] = SECRET_KEY</span></span></code></pre>\n<p>Let's create a file called <code>auth_middleware.py</code> in the root of your application and place the following inside this file:</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"python\" data-index=\"3\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk15\">from</span><span class=\"mtk1\"> functools </span><span class=\"mtk15\">import</span><span class=\"mtk1\"> wraps</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk15\">import</span><span class=\"mtk1\"> jwt</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk15\">from</span><span class=\"mtk1\"> flask </span><span class=\"mtk15\">import</span><span class=\"mtk1\"> request, abort</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk15\">from</span><span class=\"mtk1\"> flask </span><span class=\"mtk15\">import</span><span class=\"mtk1\"> current_app</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk15\">import</span><span class=\"mtk1\"> models</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">def</span><span class=\"mtk1\"> </span><span class=\"mtk11\">token_required</span><span class=\"mtk1\">(</span><span class=\"mtk12\">f</span><span class=\"mtk1\">):</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk11\">@wraps</span><span class=\"mtk1\">(f)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk4\">def</span><span class=\"mtk1\"> </span><span class=\"mtk11\">decorated</span><span class=\"mtk1\">(*</span><span class=\"mtk12\">args</span><span class=\"mtk1\">, **</span><span class=\"mtk12\">kwargs</span><span class=\"mtk1\">):</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        token = </span><span class=\"mtk4\">None</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">if</span><span class=\"mtk1\"> </span><span class=\"mtk8\">&quot;Authorization&quot;</span><span class=\"mtk1\"> </span><span class=\"mtk4\">in</span><span class=\"mtk1\"> request.headers:</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            token = request.headers[</span><span class=\"mtk8\">&quot;Authorization&quot;</span><span class=\"mtk1\">].split(</span><span class=\"mtk8\">&quot; &quot;</span><span class=\"mtk1\">)[</span><span class=\"mtk7\">1</span><span class=\"mtk1\">]</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">if</span><span class=\"mtk1\"> </span><span class=\"mtk4\">not</span><span class=\"mtk1\"> token:</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                </span><span class=\"mtk8\">&quot;message&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;Authentication Token is missing!&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                </span><span class=\"mtk8\">&quot;data&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk4\">None</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                </span><span class=\"mtk8\">&quot;error&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;Unauthorized&quot;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            }, </span><span class=\"mtk7\">401</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">try</span><span class=\"mtk1\">:</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            data=jwt.decode(token, current_app.config[</span><span class=\"mtk8\">&quot;SECRET_KEY&quot;</span><span class=\"mtk1\">], </span><span class=\"mtk12\">algorithms</span><span class=\"mtk1\">=[</span><span class=\"mtk8\">&quot;HS256&quot;</span><span class=\"mtk1\">])</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            current_user=models.User().get_by_id(data[</span><span class=\"mtk8\">&quot;user_id&quot;</span><span class=\"mtk1\">])</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk15\">if</span><span class=\"mtk1\"> current_user </span><span class=\"mtk4\">is</span><span class=\"mtk1\"> </span><span class=\"mtk4\">None</span><span class=\"mtk1\">:</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                </span><span class=\"mtk8\">&quot;message&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;Invalid Authentication token!&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                </span><span class=\"mtk8\">&quot;data&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk4\">None</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                </span><span class=\"mtk8\">&quot;error&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;Unauthorized&quot;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            }, </span><span class=\"mtk7\">401</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk15\">if</span><span class=\"mtk1\"> </span><span class=\"mtk4\">not</span><span class=\"mtk1\"> current_user[</span><span class=\"mtk8\">&quot;active&quot;</span><span class=\"mtk1\">]:</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                abort(</span><span class=\"mtk7\">403</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">except</span><span class=\"mtk1\"> </span><span class=\"mtk10\">Exception</span><span class=\"mtk1\"> </span><span class=\"mtk15\">as</span><span class=\"mtk1\"> e:</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                </span><span class=\"mtk8\">&quot;message&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;Something went wrong&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                </span><span class=\"mtk8\">&quot;data&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk4\">None</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                </span><span class=\"mtk8\">&quot;error&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk10\">str</span><span class=\"mtk1\">(e)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            }, </span><span class=\"mtk7\">500</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> f(current_user, *args, **kwargs)</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> decorated</span></span></code></pre>\n<p>The function above is simply a decorator function. Inside this function, you check if there is an <code>Authorization</code> field in the headers part of the request; if this is missing, you return an authorization error.</p>\n<p>Next, you check if it exists but is not valid; if it is not valid, you also return an authorization error.</p>\n<p>If everything goes fine, then the view function is called. As you can see, you return <code>f(current_user, *args, **kwargs)</code>, where <code>f</code> is the next decorator or function that's being called after this decorator -- in your case, the view function, which means that the first argument of any view function that uses this decorator must be <code>current_user</code>.</p>\n<h2 id=\"auth-routes\" style=\"position:relative;\"><a href=\"#auth-routes\" aria-label=\"auth routes permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Auth Routes</h2>\n<p>You currently have a route to creating a new user, but you don't have one to log in. From what you have above, you're checking if the token passed as the header is valid, but now the question is -- how do you get to know the token. Basically, the login route fetches the token and sends it to the client.</p>\n<p>Add the following function below the <code>add_user</code> function:</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"python\" data-index=\"4\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk11\">@app.route</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;/users/login&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk12\">methods</span><span class=\"mtk1\">=[</span><span class=\"mtk8\">&quot;POST&quot;</span><span class=\"mtk1\">])</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">def</span><span class=\"mtk1\"> </span><span class=\"mtk11\">login</span><span class=\"mtk1\">():</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk15\">try</span><span class=\"mtk1\">:</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        data = request.json</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">if</span><span class=\"mtk1\"> </span><span class=\"mtk4\">not</span><span class=\"mtk1\"> data:</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                </span><span class=\"mtk8\">&quot;message&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;Please provide user details&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                </span><span class=\"mtk8\">&quot;data&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk4\">None</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                </span><span class=\"mtk8\">&quot;error&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;Bad request&quot;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            }, </span><span class=\"mtk7\">400</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk3\"># validate input</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        is_validated = validate_email_and_password(data.get(</span><span class=\"mtk8\">&#39;email&#39;</span><span class=\"mtk1\">), data.get(</span><span class=\"mtk8\">&#39;password&#39;</span><span class=\"mtk1\">))</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">if</span><span class=\"mtk1\"> is_validated </span><span class=\"mtk4\">is</span><span class=\"mtk1\"> </span><span class=\"mtk4\">not</span><span class=\"mtk1\"> </span><span class=\"mtk4\">True</span><span class=\"mtk1\">:</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> </span><span class=\"mtk10\">dict</span><span class=\"mtk1\">(</span><span class=\"mtk12\">message</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&#39;Invalid data&#39;</span><span class=\"mtk1\">, </span><span class=\"mtk12\">data</span><span class=\"mtk1\">=</span><span class=\"mtk4\">None</span><span class=\"mtk1\">, </span><span class=\"mtk12\">error</span><span class=\"mtk1\">=is_validated), </span><span class=\"mtk7\">400</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        user = User().login(</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            data[</span><span class=\"mtk8\">&quot;email&quot;</span><span class=\"mtk1\">],</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            data[</span><span class=\"mtk8\">&quot;password&quot;</span><span class=\"mtk1\">]</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        )</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">if</span><span class=\"mtk1\"> user:</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk15\">try</span><span class=\"mtk1\">:</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                </span><span class=\"mtk3\"># token should expire after 24 hrs</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                user[</span><span class=\"mtk8\">&quot;token&quot;</span><span class=\"mtk1\">] = jwt.encode(</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                    {</span><span class=\"mtk8\">&quot;user_id&quot;</span><span class=\"mtk1\">: user[</span><span class=\"mtk8\">&quot;_id&quot;</span><span class=\"mtk1\">]},</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                    app.config[</span><span class=\"mtk8\">&quot;SECRET_KEY&quot;</span><span class=\"mtk1\">],</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                    </span><span class=\"mtk12\">algorithm</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;HS256&quot;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                )</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                    </span><span class=\"mtk8\">&quot;message&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;Successfully fetched auth token&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                    </span><span class=\"mtk8\">&quot;data&quot;</span><span class=\"mtk1\">: user</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                }</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk15\">except</span><span class=\"mtk1\"> </span><span class=\"mtk10\">Exception</span><span class=\"mtk1\"> </span><span class=\"mtk15\">as</span><span class=\"mtk1\"> e:</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                    </span><span class=\"mtk8\">&quot;error&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;Something went wrong&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                    </span><span class=\"mtk8\">&quot;message&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk10\">str</span><span class=\"mtk1\">(e)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                }, </span><span class=\"mtk7\">500</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk8\">&quot;message&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;Error fetching auth token!, invalid email or password&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk8\">&quot;data&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk4\">None</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk8\">&quot;error&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;Unauthorized&quot;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        }, </span><span class=\"mtk7\">404</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk15\">except</span><span class=\"mtk1\"> </span><span class=\"mtk10\">Exception</span><span class=\"mtk1\"> </span><span class=\"mtk15\">as</span><span class=\"mtk1\"> e:</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                </span><span class=\"mtk8\">&quot;message&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;Something went wrong!&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                </span><span class=\"mtk8\">&quot;error&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk10\">str</span><span class=\"mtk1\">(e),</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                </span><span class=\"mtk8\">&quot;data&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk4\">None</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        }, </span><span class=\"mtk7\">500</span></span></code></pre>\n<h2 id=\"protecting-api-routes-in-flask\" style=\"position:relative;\"><a href=\"#protecting-api-routes-in-flask\" aria-label=\"protecting api routes in flask permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Protecting API Routes in Flask</h2>\n<p>So far, you've been able to create your auth middleware, but you need to use this middleware to protect routes. All you need to do is to pass this middleware immediately after the <code>app.route</code> middleware, then make <code>current_user</code> the first argument of the view function, as follows:</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"python\" data-index=\"5\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk11\">@app.route</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&#39;/&#39;</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk11\">@token_required</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">def</span><span class=\"mtk1\"> </span><span class=\"mtk11\">user</span><span class=\"mtk1\">(</span><span class=\"mtk12\">current_user</span><span class=\"mtk1\">):</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> jsonify(current_user)</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk11\">@app.route</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&#39;/&lt;pdt_id&gt;&#39;</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk11\">@token_required</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">def</span><span class=\"mtk1\"> </span><span class=\"mtk11\">product</span><span class=\"mtk1\">(</span><span class=\"mtk12\">current_user</span><span class=\"mtk1\">, </span><span class=\"mtk12\">pdt_id</span><span class=\"mtk1\">):</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">  </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> jsonify(Product.find({</span><span class=\"mtk8\">&#39;user_id&#39;</span><span class=\"mtk1\">: pdt_id}))</span></span></code></pre>\n<p>Add this middleware (<code>@token_required</code>) to every function you only want authenticated users to access. In the end, your whole <code>app.py</code> file should look as follows.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"python\" data-index=\"6\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk15\">import</span><span class=\"mtk1\"> jwt, os</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk15\">from</span><span class=\"mtk1\"> dotenv </span><span class=\"mtk15\">import</span><span class=\"mtk1\"> load_dotenv</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk15\">from</span><span class=\"mtk1\"> flask </span><span class=\"mtk15\">import</span><span class=\"mtk1\"> Flask, request, jsonify</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk15\">from</span><span class=\"mtk1\"> save_image </span><span class=\"mtk15\">import</span><span class=\"mtk1\"> save_pic</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk15\">from</span><span class=\"mtk1\"> validate </span><span class=\"mtk15\">import</span><span class=\"mtk1\"> validate_book, validate_email_and_password, validate_user</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">load_dotenv()</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">app = Flask(</span><span class=\"mtk12\">__name__</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">SECRET_KEY = os.environ.get(</span><span class=\"mtk8\">&#39;SECRET_KEY&#39;</span><span class=\"mtk1\">) </span><span class=\"mtk4\">or</span><span class=\"mtk1\"> </span><span class=\"mtk8\">&#39;this is a secret&#39;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk11\">print</span><span class=\"mtk1\">(SECRET_KEY)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">app.config[</span><span class=\"mtk8\">&#39;SECRET_KEY&#39;</span><span class=\"mtk1\">] = SECRET_KEY</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk15\">from</span><span class=\"mtk1\"> models </span><span class=\"mtk15\">import</span><span class=\"mtk1\"> Books, User</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk15\">from</span><span class=\"mtk1\"> auth_middleware </span><span class=\"mtk15\">import</span><span class=\"mtk1\"> token_required</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk11\">@app.route</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;/&quot;</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">def</span><span class=\"mtk1\"> </span><span class=\"mtk11\">hello</span><span class=\"mtk1\">():</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> </span><span class=\"mtk8\">&quot;Hello World!&quot;</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk11\">@app.route</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;/users/&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk12\">methods</span><span class=\"mtk1\">=[</span><span class=\"mtk8\">&quot;POST&quot;</span><span class=\"mtk1\">])</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">def</span><span class=\"mtk1\"> </span><span class=\"mtk11\">add_user</span><span class=\"mtk1\">():</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk15\">try</span><span class=\"mtk1\">:</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        user = request.json</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">if</span><span class=\"mtk1\"> </span><span class=\"mtk4\">not</span><span class=\"mtk1\"> user:</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                </span><span class=\"mtk8\">&quot;message&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;Please provide user details&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                </span><span class=\"mtk8\">&quot;data&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk4\">None</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                </span><span class=\"mtk8\">&quot;error&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;Bad request&quot;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            }, </span><span class=\"mtk7\">400</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        is_validated = validate_user(**user)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">if</span><span class=\"mtk1\"> is_validated </span><span class=\"mtk4\">is</span><span class=\"mtk1\"> </span><span class=\"mtk4\">not</span><span class=\"mtk1\"> </span><span class=\"mtk4\">True</span><span class=\"mtk1\">:</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> </span><span class=\"mtk10\">dict</span><span class=\"mtk1\">(</span><span class=\"mtk12\">message</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&#39;Invalid data&#39;</span><span class=\"mtk1\">, </span><span class=\"mtk12\">data</span><span class=\"mtk1\">=</span><span class=\"mtk4\">None</span><span class=\"mtk1\">, </span><span class=\"mtk12\">error</span><span class=\"mtk1\">=is_validated), </span><span class=\"mtk7\">400</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        user = User().create(**user)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">if</span><span class=\"mtk1\"> </span><span class=\"mtk4\">not</span><span class=\"mtk1\"> user:</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                </span><span class=\"mtk8\">&quot;message&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;User already exists&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                </span><span class=\"mtk8\">&quot;error&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;Conflict&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                </span><span class=\"mtk8\">&quot;data&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk4\">None</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            }, </span><span class=\"mtk7\">409</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk8\">&quot;message&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;Successfully created new user&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk8\">&quot;data&quot;</span><span class=\"mtk1\">: user</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        }, </span><span class=\"mtk7\">201</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk15\">except</span><span class=\"mtk1\"> </span><span class=\"mtk10\">Exception</span><span class=\"mtk1\"> </span><span class=\"mtk15\">as</span><span class=\"mtk1\"> e:</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk8\">&quot;message&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;Something went wrong&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk8\">&quot;error&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk10\">str</span><span class=\"mtk1\">(e),</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk8\">&quot;data&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk4\">None</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        }, </span><span class=\"mtk7\">500</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk11\">@app.route</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;/users/login&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk12\">methods</span><span class=\"mtk1\">=[</span><span class=\"mtk8\">&quot;POST&quot;</span><span class=\"mtk1\">])</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">def</span><span class=\"mtk1\"> </span><span class=\"mtk11\">login</span><span class=\"mtk1\">():</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk15\">try</span><span class=\"mtk1\">:</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        data = request.json</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">if</span><span class=\"mtk1\"> </span><span class=\"mtk4\">not</span><span class=\"mtk1\"> data:</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                </span><span class=\"mtk8\">&quot;message&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;Please provide user details&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                </span><span class=\"mtk8\">&quot;data&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk4\">None</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                </span><span class=\"mtk8\">&quot;error&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;Bad request&quot;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            }, </span><span class=\"mtk7\">400</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk3\"># validate input</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        is_validated = validate_email_and_password(data.get(</span><span class=\"mtk8\">&#39;email&#39;</span><span class=\"mtk1\">), data.get(</span><span class=\"mtk8\">&#39;password&#39;</span><span class=\"mtk1\">))</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">if</span><span class=\"mtk1\"> is_validated </span><span class=\"mtk4\">is</span><span class=\"mtk1\"> </span><span class=\"mtk4\">not</span><span class=\"mtk1\"> </span><span class=\"mtk4\">True</span><span class=\"mtk1\">:</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> </span><span class=\"mtk10\">dict</span><span class=\"mtk1\">(</span><span class=\"mtk12\">message</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&#39;Invalid data&#39;</span><span class=\"mtk1\">, </span><span class=\"mtk12\">data</span><span class=\"mtk1\">=</span><span class=\"mtk4\">None</span><span class=\"mtk1\">, </span><span class=\"mtk12\">error</span><span class=\"mtk1\">=is_validated), </span><span class=\"mtk7\">400</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        user = User().login(</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            data[</span><span class=\"mtk8\">&quot;email&quot;</span><span class=\"mtk1\">],</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            data[</span><span class=\"mtk8\">&quot;password&quot;</span><span class=\"mtk1\">]</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        )</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">if</span><span class=\"mtk1\"> user:</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk15\">try</span><span class=\"mtk1\">:</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                </span><span class=\"mtk3\"># token should expire after 24 hrs</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                user[</span><span class=\"mtk8\">&quot;token&quot;</span><span class=\"mtk1\">] = jwt.encode(</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                    {</span><span class=\"mtk8\">&quot;user_id&quot;</span><span class=\"mtk1\">: user[</span><span class=\"mtk8\">&quot;_id&quot;</span><span class=\"mtk1\">]},</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                    app.config[</span><span class=\"mtk8\">&quot;SECRET_KEY&quot;</span><span class=\"mtk1\">],</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                    </span><span class=\"mtk12\">algorithm</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;HS256&quot;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                )</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                    </span><span class=\"mtk8\">&quot;message&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;Successfully fetched auth token&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                    </span><span class=\"mtk8\">&quot;data&quot;</span><span class=\"mtk1\">: user</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                }</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk15\">except</span><span class=\"mtk1\"> </span><span class=\"mtk10\">Exception</span><span class=\"mtk1\"> </span><span class=\"mtk15\">as</span><span class=\"mtk1\"> e:</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                    </span><span class=\"mtk8\">&quot;error&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;Something went wrong&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                    </span><span class=\"mtk8\">&quot;message&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk10\">str</span><span class=\"mtk1\">(e)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                }, </span><span class=\"mtk7\">500</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk8\">&quot;message&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;Error fetching auth token!, invalid email or password&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk8\">&quot;data&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk4\">None</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk8\">&quot;error&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;Unauthorized&quot;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        }, </span><span class=\"mtk7\">404</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk15\">except</span><span class=\"mtk1\"> </span><span class=\"mtk10\">Exception</span><span class=\"mtk1\"> </span><span class=\"mtk15\">as</span><span class=\"mtk1\"> e:</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                </span><span class=\"mtk8\">&quot;message&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;Something went wrong!&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                </span><span class=\"mtk8\">&quot;error&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk10\">str</span><span class=\"mtk1\">(e),</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                </span><span class=\"mtk8\">&quot;data&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk4\">None</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        }, </span><span class=\"mtk7\">500</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk11\">@app.route</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;/users/&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk12\">methods</span><span class=\"mtk1\">=[</span><span class=\"mtk8\">&quot;GET&quot;</span><span class=\"mtk1\">])</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk11\">@token_required</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">def</span><span class=\"mtk1\"> </span><span class=\"mtk11\">get_current_user</span><span class=\"mtk1\">(</span><span class=\"mtk12\">current_user</span><span class=\"mtk1\">):</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> jsonify({</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk8\">&quot;message&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;successfully retrieved user profile&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk8\">&quot;data&quot;</span><span class=\"mtk1\">: current_user</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    })</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk11\">@app.route</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;/users/&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk12\">methods</span><span class=\"mtk1\">=[</span><span class=\"mtk8\">&quot;PUT&quot;</span><span class=\"mtk1\">])</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk11\">@token_required</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">def</span><span class=\"mtk1\"> </span><span class=\"mtk11\">update_user</span><span class=\"mtk1\">(</span><span class=\"mtk12\">current_user</span><span class=\"mtk1\">):</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk15\">try</span><span class=\"mtk1\">:</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        user = request.json</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">if</span><span class=\"mtk1\"> user.get(</span><span class=\"mtk8\">&quot;name&quot;</span><span class=\"mtk1\">):</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            user = User().update(current_user[</span><span class=\"mtk8\">&quot;_id&quot;</span><span class=\"mtk1\">], user[</span><span class=\"mtk8\">&quot;name&quot;</span><span class=\"mtk1\">])</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> jsonify({</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                </span><span class=\"mtk8\">&quot;message&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;successfully updated account&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                </span><span class=\"mtk8\">&quot;data&quot;</span><span class=\"mtk1\">: user</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            }), </span><span class=\"mtk7\">201</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk8\">&quot;message&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;Invalid data, you can only update your account name!&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk8\">&quot;data&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk4\">None</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk8\">&quot;error&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;Bad Request&quot;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        }, </span><span class=\"mtk7\">400</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk15\">except</span><span class=\"mtk1\"> </span><span class=\"mtk10\">Exception</span><span class=\"mtk1\"> </span><span class=\"mtk15\">as</span><span class=\"mtk1\"> e:</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> jsonify({</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk8\">&quot;message&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;failed to update account&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk8\">&quot;error&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk10\">str</span><span class=\"mtk1\">(e),</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk8\">&quot;data&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk4\">None</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        }), </span><span class=\"mtk7\">400</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk11\">@app.route</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;/users/&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk12\">methods</span><span class=\"mtk1\">=[</span><span class=\"mtk8\">&quot;DELETE&quot;</span><span class=\"mtk1\">])</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk11\">@token_required</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">def</span><span class=\"mtk1\"> </span><span class=\"mtk11\">disable_user</span><span class=\"mtk1\">(</span><span class=\"mtk12\">current_user</span><span class=\"mtk1\">):</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk15\">try</span><span class=\"mtk1\">:</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        User().disable_account(current_user[</span><span class=\"mtk8\">&quot;_id&quot;</span><span class=\"mtk1\">])</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> jsonify({</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk8\">&quot;message&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;successfully disabled acount&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk8\">&quot;data&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk4\">None</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        }), </span><span class=\"mtk7\">204</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk15\">except</span><span class=\"mtk1\"> </span><span class=\"mtk10\">Exception</span><span class=\"mtk1\"> </span><span class=\"mtk15\">as</span><span class=\"mtk1\"> e:</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> jsonify({</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk8\">&quot;message&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;failed to disable account&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk8\">&quot;error&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk10\">str</span><span class=\"mtk1\">(e),</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk8\">&quot;data&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk4\">None</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        }), </span><span class=\"mtk7\">400</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk11\">@app.route</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;/books/&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk12\">methods</span><span class=\"mtk1\">=[</span><span class=\"mtk8\">&quot;POST&quot;</span><span class=\"mtk1\">])</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk11\">@token_required</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">def</span><span class=\"mtk1\"> </span><span class=\"mtk11\">add_book</span><span class=\"mtk1\">(</span><span class=\"mtk12\">current_user</span><span class=\"mtk1\">):</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk15\">try</span><span class=\"mtk1\">:</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        book = </span><span class=\"mtk10\">dict</span><span class=\"mtk1\">(request.form)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">if</span><span class=\"mtk1\"> </span><span class=\"mtk4\">not</span><span class=\"mtk1\"> book:</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                </span><span class=\"mtk8\">&quot;message&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;Invalid data, you need to give the book title, cover image, author id,&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                </span><span class=\"mtk8\">&quot;data&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk4\">None</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                </span><span class=\"mtk8\">&quot;error&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;Bad Request&quot;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            }, </span><span class=\"mtk7\">400</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">if</span><span class=\"mtk1\"> </span><span class=\"mtk4\">not</span><span class=\"mtk1\"> request.files[</span><span class=\"mtk8\">&quot;cover_image&quot;</span><span class=\"mtk1\">]:</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                </span><span class=\"mtk8\">&quot;message&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;cover image is required&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                </span><span class=\"mtk8\">&quot;data&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk4\">None</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            }, </span><span class=\"mtk7\">400</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        book[</span><span class=\"mtk8\">&quot;image_url&quot;</span><span class=\"mtk1\">] = request.host_url+</span><span class=\"mtk8\">&quot;static/books/&quot;</span><span class=\"mtk1\">+save_pic(request.files[</span><span class=\"mtk8\">&quot;cover_image&quot;</span><span class=\"mtk1\">])</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        book[</span><span class=\"mtk8\">&quot;user_id&quot;</span><span class=\"mtk1\">] = current_user[</span><span class=\"mtk8\">&quot;_id&quot;</span><span class=\"mtk1\">]</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        is_validated = validate_book(**book)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">if</span><span class=\"mtk1\"> is_validated </span><span class=\"mtk4\">is</span><span class=\"mtk1\"> </span><span class=\"mtk4\">not</span><span class=\"mtk1\"> </span><span class=\"mtk4\">True</span><span class=\"mtk1\">:</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                </span><span class=\"mtk8\">&quot;message&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;Invalid data&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                </span><span class=\"mtk8\">&quot;data&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk4\">None</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                </span><span class=\"mtk8\">&quot;error&quot;</span><span class=\"mtk1\">: is_validated</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            }, </span><span class=\"mtk7\">400</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        book = Books().create(**book)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">if</span><span class=\"mtk1\"> </span><span class=\"mtk4\">not</span><span class=\"mtk1\"> book:</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                </span><span class=\"mtk8\">&quot;message&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;The book has been created by user&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                </span><span class=\"mtk8\">&quot;data&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk4\">None</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                </span><span class=\"mtk8\">&quot;error&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;Conflict&quot;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            }, </span><span class=\"mtk7\">400</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> jsonify({</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk8\">&quot;message&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;successfully created a new book&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk8\">&quot;data&quot;</span><span class=\"mtk1\">: book</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        }), </span><span class=\"mtk7\">201</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk15\">except</span><span class=\"mtk1\"> </span><span class=\"mtk10\">Exception</span><span class=\"mtk1\"> </span><span class=\"mtk15\">as</span><span class=\"mtk1\"> e:</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> jsonify({</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk8\">&quot;message&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;failed to create a new book&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk8\">&quot;error&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk10\">str</span><span class=\"mtk1\">(e),</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk8\">&quot;data&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk4\">None</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        }), </span><span class=\"mtk7\">500</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk11\">@app.route</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;/books/&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk12\">methods</span><span class=\"mtk1\">=[</span><span class=\"mtk8\">&quot;GET&quot;</span><span class=\"mtk1\">])</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk11\">@token_required</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">def</span><span class=\"mtk1\"> </span><span class=\"mtk11\">get_books</span><span class=\"mtk1\">(</span><span class=\"mtk12\">current_user</span><span class=\"mtk1\">):</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk15\">try</span><span class=\"mtk1\">:</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        books = Books().get_by_user_id(current_user[</span><span class=\"mtk8\">&quot;_id&quot;</span><span class=\"mtk1\">])</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> jsonify({</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk8\">&quot;message&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;successfully retrieved all books&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk8\">&quot;data&quot;</span><span class=\"mtk1\">: books</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        })</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk15\">except</span><span class=\"mtk1\"> </span><span class=\"mtk10\">Exception</span><span class=\"mtk1\"> </span><span class=\"mtk15\">as</span><span class=\"mtk1\"> e:</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> jsonify({</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk8\">&quot;message&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;failed to retrieve all books&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk8\">&quot;error&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk10\">str</span><span class=\"mtk1\">(e),</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk8\">&quot;data&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk4\">None</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        }), </span><span class=\"mtk7\">500</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk11\">@app.route</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;/books/&lt;book_id&gt;&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk12\">methods</span><span class=\"mtk1\">=[</span><span class=\"mtk8\">&quot;GET&quot;</span><span class=\"mtk1\">])</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk11\">@token_required</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">def</span><span class=\"mtk1\"> </span><span class=\"mtk11\">get_book</span><span class=\"mtk1\">(</span><span class=\"mtk12\">current_user</span><span class=\"mtk1\">, </span><span class=\"mtk12\">book_id</span><span class=\"mtk1\">):</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk15\">try</span><span class=\"mtk1\">:</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        book = Books().get_by_id(book_id)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">if</span><span class=\"mtk1\"> </span><span class=\"mtk4\">not</span><span class=\"mtk1\"> book:</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                </span><span class=\"mtk8\">&quot;message&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;Book not found&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                </span><span class=\"mtk8\">&quot;data&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk4\">None</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                </span><span class=\"mtk8\">&quot;error&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;Not Found&quot;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            }, </span><span class=\"mtk7\">404</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> jsonify({</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk8\">&quot;message&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;successfully retrieved a book&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk8\">&quot;data&quot;</span><span class=\"mtk1\">: book</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        })</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk15\">except</span><span class=\"mtk1\"> </span><span class=\"mtk10\">Exception</span><span class=\"mtk1\"> </span><span class=\"mtk15\">as</span><span class=\"mtk1\"> e:</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> jsonify({</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk8\">&quot;message&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;Something went wrong&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk8\">&quot;error&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk10\">str</span><span class=\"mtk1\">(e),</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk8\">&quot;data&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk4\">None</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        }), </span><span class=\"mtk7\">500</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk11\">@app.route</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;/books/&lt;book_id&gt;&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk12\">methods</span><span class=\"mtk1\">=[</span><span class=\"mtk8\">&quot;PUT&quot;</span><span class=\"mtk1\">])</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk11\">@token_required</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">def</span><span class=\"mtk1\"> </span><span class=\"mtk11\">update_book</span><span class=\"mtk1\">(</span><span class=\"mtk12\">current_user</span><span class=\"mtk1\">, </span><span class=\"mtk12\">book_id</span><span class=\"mtk1\">):</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk15\">try</span><span class=\"mtk1\">:</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        book = Books().get_by_id(book_id)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">if</span><span class=\"mtk1\"> </span><span class=\"mtk4\">not</span><span class=\"mtk1\"> book </span><span class=\"mtk4\">or</span><span class=\"mtk1\"> book[</span><span class=\"mtk8\">&quot;user_id&quot;</span><span class=\"mtk1\">] != current_user[</span><span class=\"mtk8\">&quot;_id&quot;</span><span class=\"mtk1\">]:</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                </span><span class=\"mtk8\">&quot;message&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;Book not found for user&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                </span><span class=\"mtk8\">&quot;data&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk4\">None</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                </span><span class=\"mtk8\">&quot;error&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;Not found&quot;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            }, </span><span class=\"mtk7\">404</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        book = request.form</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">if</span><span class=\"mtk1\"> book.get(</span><span class=\"mtk8\">&#39;cover_image&#39;</span><span class=\"mtk1\">):</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            book[</span><span class=\"mtk8\">&quot;image_url&quot;</span><span class=\"mtk1\">] = request.host_url+</span><span class=\"mtk8\">&quot;static/books/&quot;</span><span class=\"mtk1\">+save_pic(request.files[</span><span class=\"mtk8\">&quot;cover_image&quot;</span><span class=\"mtk1\">])</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        book = Books().update(book_id, **book)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> jsonify({</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk8\">&quot;message&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;successfully updated a book&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk8\">&quot;data&quot;</span><span class=\"mtk1\">: book</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        }), </span><span class=\"mtk7\">201</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk15\">except</span><span class=\"mtk1\"> </span><span class=\"mtk10\">Exception</span><span class=\"mtk1\"> </span><span class=\"mtk15\">as</span><span class=\"mtk1\"> e:</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> jsonify({</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk8\">&quot;message&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;failed to update a book&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk8\">&quot;error&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk10\">str</span><span class=\"mtk1\">(e),</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk8\">&quot;data&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk4\">None</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        }), </span><span class=\"mtk7\">400</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk11\">@app.route</span><span class=\"mtk1\">(</span><span class=\"mtk8\">&quot;/books/&lt;book_id&gt;&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk12\">methods</span><span class=\"mtk1\">=[</span><span class=\"mtk8\">&quot;DELETE&quot;</span><span class=\"mtk1\">])</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk11\">@token_required</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">def</span><span class=\"mtk1\"> </span><span class=\"mtk11\">delete_book</span><span class=\"mtk1\">(</span><span class=\"mtk12\">current_user</span><span class=\"mtk1\">, </span><span class=\"mtk12\">book_id</span><span class=\"mtk1\">):</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk15\">try</span><span class=\"mtk1\">:</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        book = Books().get_by_id(book_id)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">if</span><span class=\"mtk1\"> </span><span class=\"mtk4\">not</span><span class=\"mtk1\"> book </span><span class=\"mtk4\">or</span><span class=\"mtk1\"> book[</span><span class=\"mtk8\">&quot;user_id&quot;</span><span class=\"mtk1\">] != current_user[</span><span class=\"mtk8\">&quot;_id&quot;</span><span class=\"mtk1\">]:</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                </span><span class=\"mtk8\">&quot;message&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;Book not found for user&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                </span><span class=\"mtk8\">&quot;data&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk4\">None</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                </span><span class=\"mtk8\">&quot;error&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;Not found&quot;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            }, </span><span class=\"mtk7\">404</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        Books().delete(book_id)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> jsonify({</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk8\">&quot;message&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;successfully deleted a book&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk8\">&quot;data&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk4\">None</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        }), </span><span class=\"mtk7\">204</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk15\">except</span><span class=\"mtk1\"> </span><span class=\"mtk10\">Exception</span><span class=\"mtk1\"> </span><span class=\"mtk15\">as</span><span class=\"mtk1\"> e:</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> jsonify({</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk8\">&quot;message&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;failed to delete a book&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk8\">&quot;error&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk10\">str</span><span class=\"mtk1\">(e),</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk8\">&quot;data&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk4\">None</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        }), </span><span class=\"mtk7\">400</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk11\">@app.errorhandler</span><span class=\"mtk1\">(</span><span class=\"mtk7\">403</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">def</span><span class=\"mtk1\"> </span><span class=\"mtk11\">forbidden</span><span class=\"mtk1\">(</span><span class=\"mtk12\">e</span><span class=\"mtk1\">):</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> jsonify({</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk8\">&quot;message&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;Forbidden&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk8\">&quot;error&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk10\">str</span><span class=\"mtk1\">(e),</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk8\">&quot;data&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk4\">None</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    }), </span><span class=\"mtk7\">403</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk11\">@app.errorhandler</span><span class=\"mtk1\">(</span><span class=\"mtk7\">404</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">def</span><span class=\"mtk1\"> </span><span class=\"mtk11\">forbidden</span><span class=\"mtk1\">(</span><span class=\"mtk12\">e</span><span class=\"mtk1\">):</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> jsonify({</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk8\">&quot;message&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk8\">&quot;Endpoint Not Found&quot;</span><span class=\"mtk1\">,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk8\">&quot;error&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk10\">str</span><span class=\"mtk1\">(e),</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk8\">&quot;data&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk4\">None</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    }), </span><span class=\"mtk7\">404</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk15\">if</span><span class=\"mtk1\"> </span><span class=\"mtk12\">__name__</span><span class=\"mtk1\"> == </span><span class=\"mtk8\">&quot;__main__&quot;</span><span class=\"mtk1\">:</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    app.run(</span><span class=\"mtk12\">debug</span><span class=\"mtk1\">=</span><span class=\"mtk4\">True</span><span class=\"mtk1\">)</span></span></code></pre>\n<p>Before running the application, let's look at the <code>save_pic</code> function inside the <code>save_image.py</code> file. This is the function responsible for saving uploaded pictures.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"python\" data-index=\"7\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk15\">from</span><span class=\"mtk1\"> PIL </span><span class=\"mtk15\">import</span><span class=\"mtk1\"> Image</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk15\">import</span><span class=\"mtk1\"> secrets, os</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk15\">from</span><span class=\"mtk1\"> flask </span><span class=\"mtk15\">import</span><span class=\"mtk1\"> current_app </span><span class=\"mtk15\">as</span><span class=\"mtk1\"> app</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">def</span><span class=\"mtk1\"> </span><span class=\"mtk11\">save_pic</span><span class=\"mtk1\">(</span><span class=\"mtk12\">picture</span><span class=\"mtk1\">):</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    file_name = secrets.token_hex(</span><span class=\"mtk7\">8</span><span class=\"mtk1\">) +os.path.splitext(picture.filename)[</span><span class=\"mtk7\">1</span><span class=\"mtk1\">]</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk15\">if</span><span class=\"mtk1\"> </span><span class=\"mtk4\">not</span><span class=\"mtk1\"> os.path.isdir(os.path.join(app.root_path, </span><span class=\"mtk8\">&#39;static&#39;</span><span class=\"mtk1\">)):</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        os.mkdir(os.path.join(app.root_path,</span><span class=\"mtk8\">&quot;static&quot;</span><span class=\"mtk1\">))</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        os.mkdir(os.path.join(app.root_path,</span><span class=\"mtk8\">&quot;static/images&quot;</span><span class=\"mtk1\">))</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        os.mkdir(os.path.join(app.root_path,</span><span class=\"mtk8\">&quot;static/images/books&quot;</span><span class=\"mtk1\">))</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk15\">if</span><span class=\"mtk1\"> </span><span class=\"mtk4\">not</span><span class=\"mtk1\"> os.path.isdir(os.path.join(app.root_path, </span><span class=\"mtk8\">&#39;static/images&#39;</span><span class=\"mtk1\">)):</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        os.mkdir(os.path.join(app.root_path,</span><span class=\"mtk8\">&quot;static/images&quot;</span><span class=\"mtk1\">))</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        os.mkdir(os.path.join(app.root_path,</span><span class=\"mtk8\">&quot;static/images/books&quot;</span><span class=\"mtk1\">))</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk15\">if</span><span class=\"mtk1\"> </span><span class=\"mtk4\">not</span><span class=\"mtk1\"> os.path.isdir(os.path.join(app.root_path, </span><span class=\"mtk8\">&#39;static/images/books&#39;</span><span class=\"mtk1\">)):</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        os.mkdir(os.path.join(app.root_path,</span><span class=\"mtk8\">&quot;static/images/books&quot;</span><span class=\"mtk1\">))</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    file_path = os.path.join(app.root_path, </span><span class=\"mtk8\">&quot;static/images/books&quot;</span><span class=\"mtk1\">, file_name)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    picture = Image.open(picture)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    picture.thumbnail((</span><span class=\"mtk7\">150</span><span class=\"mtk1\">, </span><span class=\"mtk7\">150</span><span class=\"mtk1\">))</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    picture.save(file_path)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> file_name</span></span></code></pre>\n<p>You should also add the following functions as helper methods of the <code>User</code> model class.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"python\" data-index=\"8\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk4\">def</span><span class=\"mtk1\"> </span><span class=\"mtk11\">disable_account</span><span class=\"mtk1\">(</span><span class=\"mtk12\">self</span><span class=\"mtk1\">, </span><span class=\"mtk12\">user_id</span><span class=\"mtk1\">):</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    user = db.users.update_one(</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        {</span><span class=\"mtk8\">&quot;_id&quot;</span><span class=\"mtk1\">: bson.ObjectId(user_id)},</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        {</span><span class=\"mtk8\">&quot;$set&quot;</span><span class=\"mtk1\">: {</span><span class=\"mtk8\">&quot;active&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk4\">False</span><span class=\"mtk1\">}}</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    )</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    user = </span><span class=\"mtk4\">self</span><span class=\"mtk1\">.get_by_id(user_id)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> user</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">def</span><span class=\"mtk1\"> </span><span class=\"mtk11\">encrypt_password</span><span class=\"mtk1\">(</span><span class=\"mtk12\">self</span><span class=\"mtk1\">, </span><span class=\"mtk12\">password</span><span class=\"mtk1\">):</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> generate_password_hash(password)</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">def</span><span class=\"mtk1\"> </span><span class=\"mtk11\">login</span><span class=\"mtk1\">(</span><span class=\"mtk12\">self</span><span class=\"mtk1\">, </span><span class=\"mtk12\">email</span><span class=\"mtk1\">, </span><span class=\"mtk12\">password</span><span class=\"mtk1\">):</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk8\">&quot;&quot;&quot;Login a user&quot;&quot;&quot;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    user = </span><span class=\"mtk4\">self</span><span class=\"mtk1\">.get_by_email(email)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk15\">if</span><span class=\"mtk1\"> </span><span class=\"mtk4\">not</span><span class=\"mtk1\"> user </span><span class=\"mtk4\">or</span><span class=\"mtk1\"> </span><span class=\"mtk4\">not</span><span class=\"mtk1\"> check_password_hash(user[</span><span class=\"mtk8\">&quot;password&quot;</span><span class=\"mtk1\">], password):</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">return</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    user.pop(</span><span class=\"mtk8\">&quot;password&quot;</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> user</span></span></code></pre>\n<p>Your <code>models.py</code> file should look as follows:</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"python\" data-index=\"9\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk8\">&quot;&quot;&quot;Application Models&quot;&quot;&quot;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk15\">import</span><span class=\"mtk1\"> bson, os</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk15\">from</span><span class=\"mtk1\"> dotenv </span><span class=\"mtk15\">import</span><span class=\"mtk1\"> load_dotenv</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk15\">from</span><span class=\"mtk1\"> pymongo </span><span class=\"mtk15\">import</span><span class=\"mtk1\"> MongoClient</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk15\">from</span><span class=\"mtk1\"> werkzeug.security </span><span class=\"mtk15\">import</span><span class=\"mtk1\"> generate_password_hash, check_password_hash</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">load_dotenv()</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">DATABASE_URL=os.environ.get(</span><span class=\"mtk8\">&#39;DATABASE_URL&#39;</span><span class=\"mtk1\">) </span><span class=\"mtk4\">or</span><span class=\"mtk1\"> </span><span class=\"mtk8\">&#39;mongodb://localhost:27017/myDatabase&#39;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk11\">print</span><span class=\"mtk1\">(DATABASE_URL)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">client = MongoClient(DATABASE_URL)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">db = client.myDatabase</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">class</span><span class=\"mtk1\"> </span><span class=\"mtk10\">Books</span><span class=\"mtk1\">:</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk8\">&quot;&quot;&quot;Books Model&quot;&quot;&quot;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk4\">def</span><span class=\"mtk1\"> </span><span class=\"mtk11\">__init__</span><span class=\"mtk1\">(</span><span class=\"mtk12\">self</span><span class=\"mtk1\">):</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">return</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk4\">def</span><span class=\"mtk1\"> </span><span class=\"mtk11\">create</span><span class=\"mtk1\">(</span><span class=\"mtk12\">self</span><span class=\"mtk1\">, </span><span class=\"mtk12\">title</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk12\">description</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk12\">image_url</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk12\">category</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk12\">user_id</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;&quot;</span><span class=\"mtk1\">):</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk8\">&quot;&quot;&quot;Create a new book&quot;&quot;&quot;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        book = </span><span class=\"mtk4\">self</span><span class=\"mtk1\">.get_by_user_id_and_title(user_id, title)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">if</span><span class=\"mtk1\"> book:</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk15\">return</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        new_book = db.books.insert_one(</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                </span><span class=\"mtk8\">&quot;title&quot;</span><span class=\"mtk1\">: title,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                </span><span class=\"mtk8\">&quot;description&quot;</span><span class=\"mtk1\">: description,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                </span><span class=\"mtk8\">&quot;image_url&quot;</span><span class=\"mtk1\">: image_url,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                </span><span class=\"mtk8\">&quot;category&quot;</span><span class=\"mtk1\">: category,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                </span><span class=\"mtk8\">&quot;user_id&quot;</span><span class=\"mtk1\">: user_id</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            }</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        )</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> </span><span class=\"mtk4\">self</span><span class=\"mtk1\">.get_by_id(new_book.inserted_id)</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk4\">def</span><span class=\"mtk1\"> </span><span class=\"mtk11\">get_all</span><span class=\"mtk1\">(</span><span class=\"mtk12\">self</span><span class=\"mtk1\">):</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk8\">&quot;&quot;&quot;Get all books&quot;&quot;&quot;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        books = db.books.find()</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> [{**book, </span><span class=\"mtk8\">&quot;_id&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk10\">str</span><span class=\"mtk1\">(book[</span><span class=\"mtk8\">&quot;_id&quot;</span><span class=\"mtk1\">])} </span><span class=\"mtk15\">for</span><span class=\"mtk1\"> book </span><span class=\"mtk4\">in</span><span class=\"mtk1\"> books]</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk4\">def</span><span class=\"mtk1\"> </span><span class=\"mtk11\">get_by_id</span><span class=\"mtk1\">(</span><span class=\"mtk12\">self</span><span class=\"mtk1\">, </span><span class=\"mtk12\">book_id</span><span class=\"mtk1\">):</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk8\">&quot;&quot;&quot;Get a book by id&quot;&quot;&quot;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        book = db.books.find_one({</span><span class=\"mtk8\">&quot;_id&quot;</span><span class=\"mtk1\">: bson.ObjectId(book_id)})</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">if</span><span class=\"mtk1\"> </span><span class=\"mtk4\">not</span><span class=\"mtk1\"> book:</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk15\">return</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        book[</span><span class=\"mtk8\">&quot;_id&quot;</span><span class=\"mtk1\">] = </span><span class=\"mtk10\">str</span><span class=\"mtk1\">(book[</span><span class=\"mtk8\">&quot;_id&quot;</span><span class=\"mtk1\">])</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> book</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk4\">def</span><span class=\"mtk1\"> </span><span class=\"mtk11\">get_by_user_id</span><span class=\"mtk1\">(</span><span class=\"mtk12\">self</span><span class=\"mtk1\">, </span><span class=\"mtk12\">user_id</span><span class=\"mtk1\">):</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk8\">&quot;&quot;&quot;Get all books created by a user&quot;&quot;&quot;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        books = db.books.find({</span><span class=\"mtk8\">&quot;user_id&quot;</span><span class=\"mtk1\">: user_id})</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> [{**book, </span><span class=\"mtk8\">&quot;_id&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk10\">str</span><span class=\"mtk1\">(book[</span><span class=\"mtk8\">&quot;_id&quot;</span><span class=\"mtk1\">])} </span><span class=\"mtk15\">for</span><span class=\"mtk1\"> book </span><span class=\"mtk4\">in</span><span class=\"mtk1\"> books]</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk4\">def</span><span class=\"mtk1\"> </span><span class=\"mtk11\">get_by_category</span><span class=\"mtk1\">(</span><span class=\"mtk12\">self</span><span class=\"mtk1\">, </span><span class=\"mtk12\">category</span><span class=\"mtk1\">):</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk8\">&quot;&quot;&quot;Get all books by category&quot;&quot;&quot;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        books = db.books.find({</span><span class=\"mtk8\">&quot;category&quot;</span><span class=\"mtk1\">: category})</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> [book </span><span class=\"mtk15\">for</span><span class=\"mtk1\"> book </span><span class=\"mtk4\">in</span><span class=\"mtk1\"> books]</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk4\">def</span><span class=\"mtk1\"> </span><span class=\"mtk11\">get_by_user_id_and_category</span><span class=\"mtk1\">(</span><span class=\"mtk12\">self</span><span class=\"mtk1\">, </span><span class=\"mtk12\">user_id</span><span class=\"mtk1\">, </span><span class=\"mtk12\">category</span><span class=\"mtk1\">):</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk8\">&quot;&quot;&quot;Get all books by category for a particular user&quot;&quot;&quot;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        books = db.books.find({</span><span class=\"mtk8\">&quot;user_id&quot;</span><span class=\"mtk1\">: user_id, </span><span class=\"mtk8\">&quot;category&quot;</span><span class=\"mtk1\">: category})</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> [{**book, </span><span class=\"mtk8\">&quot;_id&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk10\">str</span><span class=\"mtk1\">(book[</span><span class=\"mtk8\">&quot;_id&quot;</span><span class=\"mtk1\">])} </span><span class=\"mtk15\">for</span><span class=\"mtk1\"> book </span><span class=\"mtk4\">in</span><span class=\"mtk1\"> books]</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk4\">def</span><span class=\"mtk1\"> </span><span class=\"mtk11\">get_by_user_id_and_title</span><span class=\"mtk1\">(</span><span class=\"mtk12\">self</span><span class=\"mtk1\">, </span><span class=\"mtk12\">user_id</span><span class=\"mtk1\">, </span><span class=\"mtk12\">title</span><span class=\"mtk1\">):</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk8\">&quot;&quot;&quot;Get a book given its title and author&quot;&quot;&quot;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        book = db.books.find_one({</span><span class=\"mtk8\">&quot;user_id&quot;</span><span class=\"mtk1\">: user_id, </span><span class=\"mtk8\">&quot;title&quot;</span><span class=\"mtk1\">: title})</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">if</span><span class=\"mtk1\"> </span><span class=\"mtk4\">not</span><span class=\"mtk1\"> book:</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk15\">return</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        book[</span><span class=\"mtk8\">&quot;_id&quot;</span><span class=\"mtk1\">] = </span><span class=\"mtk10\">str</span><span class=\"mtk1\">(book[</span><span class=\"mtk8\">&quot;_id&quot;</span><span class=\"mtk1\">])</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> book</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk4\">def</span><span class=\"mtk1\"> </span><span class=\"mtk11\">update</span><span class=\"mtk1\">(</span><span class=\"mtk12\">self</span><span class=\"mtk1\">, </span><span class=\"mtk12\">book_id</span><span class=\"mtk1\">, </span><span class=\"mtk12\">title</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk12\">description</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk12\">image_url</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk12\">category</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk12\">user_id</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;&quot;</span><span class=\"mtk1\">):</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk8\">&quot;&quot;&quot;Update a book&quot;&quot;&quot;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        data={}</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">if</span><span class=\"mtk1\"> title: data[</span><span class=\"mtk8\">&quot;title&quot;</span><span class=\"mtk1\">]=title</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">if</span><span class=\"mtk1\"> description: data[</span><span class=\"mtk8\">&quot;description&quot;</span><span class=\"mtk1\">]=description</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">if</span><span class=\"mtk1\"> image_url: data[</span><span class=\"mtk8\">&quot;image_url&quot;</span><span class=\"mtk1\">]=image_url</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">if</span><span class=\"mtk1\"> category: data[</span><span class=\"mtk8\">&quot;category&quot;</span><span class=\"mtk1\">]=category</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        book = db.books.update_one(</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            {</span><span class=\"mtk8\">&quot;_id&quot;</span><span class=\"mtk1\">: bson.ObjectId(book_id)},</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                </span><span class=\"mtk8\">&quot;$set&quot;</span><span class=\"mtk1\">: data</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            }</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        )</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        book = </span><span class=\"mtk4\">self</span><span class=\"mtk1\">.get_by_id(book_id)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> book</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk4\">def</span><span class=\"mtk1\"> </span><span class=\"mtk11\">delete</span><span class=\"mtk1\">(</span><span class=\"mtk12\">self</span><span class=\"mtk1\">, </span><span class=\"mtk12\">book_id</span><span class=\"mtk1\">):</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk8\">&quot;&quot;&quot;Delete a book&quot;&quot;&quot;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        book = db.books.delete_one({</span><span class=\"mtk8\">&quot;_id&quot;</span><span class=\"mtk1\">: bson.ObjectId(book_id)})</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> book</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk4\">def</span><span class=\"mtk1\"> </span><span class=\"mtk11\">delete_by_user_id</span><span class=\"mtk1\">(</span><span class=\"mtk12\">self</span><span class=\"mtk1\">, </span><span class=\"mtk12\">user_id</span><span class=\"mtk1\">):</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk8\">&quot;&quot;&quot;Delete all books created by a user&quot;&quot;&quot;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        book = db.books.delete_many({</span><span class=\"mtk8\">&quot;user_id&quot;</span><span class=\"mtk1\">: bson.ObjectId(user_id)})</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> book</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">class</span><span class=\"mtk1\"> </span><span class=\"mtk10\">User</span><span class=\"mtk1\">:</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk8\">&quot;&quot;&quot;User Model&quot;&quot;&quot;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk4\">def</span><span class=\"mtk1\"> </span><span class=\"mtk11\">__init__</span><span class=\"mtk1\">(</span><span class=\"mtk12\">self</span><span class=\"mtk1\">):</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">return</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk4\">def</span><span class=\"mtk1\"> </span><span class=\"mtk11\">create</span><span class=\"mtk1\">(</span><span class=\"mtk12\">self</span><span class=\"mtk1\">, </span><span class=\"mtk12\">name</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk12\">email</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk12\">password</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;&quot;</span><span class=\"mtk1\">):</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk8\">&quot;&quot;&quot;Create a new user&quot;&quot;&quot;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        user = </span><span class=\"mtk4\">self</span><span class=\"mtk1\">.get_by_email(email)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">if</span><span class=\"mtk1\"> user:</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk15\">return</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        new_user = db.users.insert_one(</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                </span><span class=\"mtk8\">&quot;name&quot;</span><span class=\"mtk1\">: name,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                </span><span class=\"mtk8\">&quot;email&quot;</span><span class=\"mtk1\">: email,</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                </span><span class=\"mtk8\">&quot;password&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk4\">self</span><span class=\"mtk1\">.encrypt_password(password),</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                </span><span class=\"mtk8\">&quot;active&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk4\">True</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            }</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        )</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> </span><span class=\"mtk4\">self</span><span class=\"mtk1\">.get_by_id(new_user.inserted_id)</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk4\">def</span><span class=\"mtk1\"> </span><span class=\"mtk11\">get_all</span><span class=\"mtk1\">(</span><span class=\"mtk12\">self</span><span class=\"mtk1\">):</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk8\">&quot;&quot;&quot;Get all users&quot;&quot;&quot;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        users = db.users.find({</span><span class=\"mtk8\">&quot;active&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk4\">True</span><span class=\"mtk1\">})</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> [{**user, </span><span class=\"mtk8\">&quot;_id&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk10\">str</span><span class=\"mtk1\">(user[</span><span class=\"mtk8\">&quot;_id&quot;</span><span class=\"mtk1\">])} </span><span class=\"mtk15\">for</span><span class=\"mtk1\"> user </span><span class=\"mtk4\">in</span><span class=\"mtk1\"> users]</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk4\">def</span><span class=\"mtk1\"> </span><span class=\"mtk11\">get_by_id</span><span class=\"mtk1\">(</span><span class=\"mtk12\">self</span><span class=\"mtk1\">, </span><span class=\"mtk12\">user_id</span><span class=\"mtk1\">):</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk8\">&quot;&quot;&quot;Get a user by id&quot;&quot;&quot;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        user = db.users.find_one({</span><span class=\"mtk8\">&quot;_id&quot;</span><span class=\"mtk1\">: bson.ObjectId(user_id), </span><span class=\"mtk8\">&quot;active&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk4\">True</span><span class=\"mtk1\">})</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">if</span><span class=\"mtk1\"> </span><span class=\"mtk4\">not</span><span class=\"mtk1\"> user:</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk15\">return</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        user[</span><span class=\"mtk8\">&quot;_id&quot;</span><span class=\"mtk1\">] = </span><span class=\"mtk10\">str</span><span class=\"mtk1\">(user[</span><span class=\"mtk8\">&quot;_id&quot;</span><span class=\"mtk1\">])</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        user.pop(</span><span class=\"mtk8\">&quot;password&quot;</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> user</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk4\">def</span><span class=\"mtk1\"> </span><span class=\"mtk11\">get_by_email</span><span class=\"mtk1\">(</span><span class=\"mtk12\">self</span><span class=\"mtk1\">, </span><span class=\"mtk12\">email</span><span class=\"mtk1\">):</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk8\">&quot;&quot;&quot;Get a user by email&quot;&quot;&quot;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        user = db.users.find_one({</span><span class=\"mtk8\">&quot;email&quot;</span><span class=\"mtk1\">: email, </span><span class=\"mtk8\">&quot;active&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk4\">True</span><span class=\"mtk1\">})</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">if</span><span class=\"mtk1\"> </span><span class=\"mtk4\">not</span><span class=\"mtk1\"> user:</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk15\">return</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        user[</span><span class=\"mtk8\">&quot;_id&quot;</span><span class=\"mtk1\">] = </span><span class=\"mtk10\">str</span><span class=\"mtk1\">(user[</span><span class=\"mtk8\">&quot;_id&quot;</span><span class=\"mtk1\">])</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> user</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk4\">def</span><span class=\"mtk1\"> </span><span class=\"mtk11\">update</span><span class=\"mtk1\">(</span><span class=\"mtk12\">self</span><span class=\"mtk1\">, </span><span class=\"mtk12\">user_id</span><span class=\"mtk1\">, </span><span class=\"mtk12\">name</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&quot;&quot;</span><span class=\"mtk1\">):</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk8\">&quot;&quot;&quot;Update a user&quot;&quot;&quot;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        data = {}</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">if</span><span class=\"mtk1\"> name:</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            data[</span><span class=\"mtk8\">&quot;name&quot;</span><span class=\"mtk1\">] = name</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        user = db.users.update_one(</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            {</span><span class=\"mtk8\">&quot;_id&quot;</span><span class=\"mtk1\">: bson.ObjectId(user_id)},</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">                </span><span class=\"mtk8\">&quot;$set&quot;</span><span class=\"mtk1\">: data</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            }</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        )</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        user = </span><span class=\"mtk4\">self</span><span class=\"mtk1\">.get_by_id(user_id)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> user</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk4\">def</span><span class=\"mtk1\"> </span><span class=\"mtk11\">delete</span><span class=\"mtk1\">(</span><span class=\"mtk12\">self</span><span class=\"mtk1\">, </span><span class=\"mtk12\">user_id</span><span class=\"mtk1\">):</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk8\">&quot;&quot;&quot;Delete a user&quot;&quot;&quot;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        Books().delete_by_user_id(user_id)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        user = db.users.delete_one({</span><span class=\"mtk8\">&quot;_id&quot;</span><span class=\"mtk1\">: bson.ObjectId(user_id)})</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        user = </span><span class=\"mtk4\">self</span><span class=\"mtk1\">.get_by_id(user_id)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> user</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk4\">def</span><span class=\"mtk1\"> </span><span class=\"mtk11\">disable_account</span><span class=\"mtk1\">(</span><span class=\"mtk12\">self</span><span class=\"mtk1\">, </span><span class=\"mtk12\">user_id</span><span class=\"mtk1\">):</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk8\">&quot;&quot;&quot;Disable a user account&quot;&quot;&quot;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        user = db.users.update_one(</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            {</span><span class=\"mtk8\">&quot;_id&quot;</span><span class=\"mtk1\">: bson.ObjectId(user_id)},</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            {</span><span class=\"mtk8\">&quot;$set&quot;</span><span class=\"mtk1\">: {</span><span class=\"mtk8\">&quot;active&quot;</span><span class=\"mtk1\">: </span><span class=\"mtk4\">False</span><span class=\"mtk1\">}}</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        )</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        user = </span><span class=\"mtk4\">self</span><span class=\"mtk1\">.get_by_id(user_id)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> user</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk4\">def</span><span class=\"mtk1\"> </span><span class=\"mtk11\">encrypt_password</span><span class=\"mtk1\">(</span><span class=\"mtk12\">self</span><span class=\"mtk1\">, </span><span class=\"mtk12\">password</span><span class=\"mtk1\">):</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk8\">&quot;&quot;&quot;Encrypt password&quot;&quot;&quot;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> generate_password_hash(password)</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk4\">def</span><span class=\"mtk1\"> </span><span class=\"mtk11\">login</span><span class=\"mtk1\">(</span><span class=\"mtk12\">self</span><span class=\"mtk1\">, </span><span class=\"mtk12\">email</span><span class=\"mtk1\">, </span><span class=\"mtk12\">password</span><span class=\"mtk1\">):</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk8\">&quot;&quot;&quot;Login a user&quot;&quot;&quot;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        user = </span><span class=\"mtk4\">self</span><span class=\"mtk1\">.get_by_email(email)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">if</span><span class=\"mtk1\"> </span><span class=\"mtk4\">not</span><span class=\"mtk1\"> user </span><span class=\"mtk4\">or</span><span class=\"mtk1\"> </span><span class=\"mtk4\">not</span><span class=\"mtk1\"> check_password_hash(user[</span><span class=\"mtk8\">&quot;password&quot;</span><span class=\"mtk1\">], password):</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">            </span><span class=\"mtk15\">return</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        user.pop(</span><span class=\"mtk8\">&quot;password&quot;</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> user</span></span></code></pre>\n<p>Here's an example of the user request:</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"\" data-index=\"10\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">{</span>\n<span class=\"grvsc-line\">     &quot;name&quot; : &quot;abc xyz&quot;,</span>\n<span class=\"grvsc-line\">     &quot;email&quot; : &quot;xyz@gmail.com&quot;,</span>\n<span class=\"grvsc-line\">     &quot;password&quot; : &quot;Abc@123&quot;</span>\n<span class=\"grvsc-line\">}</span></code></pre>\n<p>Here, the name should have two words, and the password should have at least an uppercase later, a lower case letter, a digit, and a special character.</p>\n<p>And an example of the book request:</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"\" data-index=\"11\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">{</span>\n<span class=\"grvsc-line\">    &quot;title&quot;:&quot;name of book&quot;,</span>\n<span class=\"grvsc-line\">    &quot;cover_image&quot;: &quot;path to image file locally&quot;,</span>\n<span class=\"grvsc-line\">    &quot;category&quot;: &quot;[&#39;romance&#39;, &#39;peotry&#39;, &#39;politics&#39;, &#39;picture book&#39;, &#39;science&#39;, &#39;fantasy&#39;, &#39;horror&#39;, &#39;thriller&#39;],</span>\n<span class=\"grvsc-line\">    &quot;description&quot;:&quot;description&quot;,</span>\n<span class=\"grvsc-line\">    &quot;user_id&quot;:&quot;user_id&quot;</span>\n<span class=\"grvsc-line\">}</span></code></pre>\n<p>While passing a book request, pass it via the <code>form-data</code> tab in Postman.</p>\n<h2 id=\"conclusion\" style=\"position:relative;\"><a href=\"#conclusion\" aria-label=\"conclusion permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Conclusion</h2>\n<p>This article has explained flask JWT authentication .</p>\n<p>In some cases, handling flask authentication yourself may not be good enough or efficient -- to overcome this, you can simply use third-party authentication providers like LoginRadius. You can check out this tutorial to learn how to add LoginRadius to your Flask application.</p>\n<p>You can find the complete code for this article on <a href=\"https://github.com/LoginRadius/engineering-blog-samples/tree/master/Flask/loginRadius-flask-auth\">Github</a>. You can reach out to me on <a href=\"https://twitter.com/bkoiki950\">Twitter</a> if you've any questions.</p>\n<style class=\"grvsc-styles\">\n  .grvsc-container {\n    overflow: auto;\n    -webkit-overflow-scrolling: touch;\n    padding-top: 1rem;\n    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));\n    padding-bottom: 1rem;\n    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));\n    border-radius: 8px;\n    border-radius: var(--grvsc-border-radius, 8px);\n    font-feature-settings: normal;\n  }\n  \n  .grvsc-code {\n    display: inline-block;\n    min-width: 100%;\n  }\n  \n  .grvsc-line {\n    display: inline-block;\n    box-sizing: border-box;\n    width: 100%;\n    padding-left: 1.5rem;\n    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));\n    padding-right: 1.5rem;\n    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));\n  }\n  \n  .grvsc-line-highlighted {\n    background-color: var(--grvsc-line-highlighted-background-color, transparent);\n    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, transparent);\n  }\n  \n  .dark-default-dark {\n    background-color: #1E1E1E;\n    color: #D4D4D4;\n  }\n  .dark-default-dark .mtk1 { color: #D4D4D4; }\n  .dark-default-dark .mtk3 { color: #6A9955; }\n  .dark-default-dark .mtk11 { color: #DCDCAA; }\n  .dark-default-dark .mtk8 { color: #CE9178; }\n  .dark-default-dark .mtk4 { color: #569CD6; }\n  .dark-default-dark .mtk15 { color: #C586C0; }\n  .dark-default-dark .mtk12 { color: #9CDCFE; }\n  .dark-default-dark .mtk7 { color: #B5CEA8; }\n  .dark-default-dark .mtk10 { color: #4EC9B0; }\n</style>","frontmatter":{"date":"December 09, 2021","updated_date":null,"description":"This tutorial helps you build a simple Flask API and demonstrates how to secure it using JWT. In the end, you can test your API authentication using a sample schema.","title":"Using JWT Flask JWT Authentication- A Quick Guide","tags":["Flask","JWT","API"],"pinned":null,"coverImage":{"childImageSharp":{"fluid":{"aspectRatio":1.5037593984962405,"src":"/static/707e66d1cd3ca14a40e66ac10ad13cea/ee604/coverImage.png","srcSet":"/static/707e66d1cd3ca14a40e66ac10ad13cea/69585/coverImage.png 200w,\n/static/707e66d1cd3ca14a40e66ac10ad13cea/497c6/coverImage.png 400w,\n/static/707e66d1cd3ca14a40e66ac10ad13cea/ee604/coverImage.png 800w,\n/static/707e66d1cd3ca14a40e66ac10ad13cea/f3583/coverImage.png 1200w","sizes":"(max-width: 800px) 100vw, 800px"}}},"author":{"id":"Babatunde Koiki","github":"Babatunde13","avatar":null}}}},{"node":{"excerpt":"Single-tenant and multi-tenant cloud architectures represent two core approaches to managing SaaS environments, each with unique benefits…","fields":{"slug":"/engineering/saas-single-tenancy-vs-multi-tenancy/"},"html":"<p>Single-tenant and multi-tenant cloud architectures represent two core approaches to managing SaaS environments, each with unique benefits depending on how resources and infrastructure are utilized. In a single-tenant cloud, each customer has their own dedicated environment, offering greater control, data security, and customization. Meanwhile, multi-tenant cloud architecture allows multiple customers to share the same infrastructure, driving down costs and enabling faster, more frequent updates.\nHence, choosing the right cloud architecture is crucial for your business. </p>\n<p>This article comprehensively compares SaaS-based multi-tenant and single-tenant cloud architectures along with their benefits and drawbacks. The comprehension also points out which one to choose based on the organization’s requirements and scenario.</p>\n<h2 id=\"single-tenant-cloud-architecture\" style=\"position:relative;\"><a href=\"#single-tenant-cloud-architecture\" aria-label=\"single tenant cloud architecture permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Single-Tenant Cloud Architecture</h2>\n<p><a href=\"https://www.loginradius.com/private-cloud/\">A single-tenant architecture</a>  dedicates a single instance of the software, infrastructure, or database to a single customer. The single-tenant system encapsulates all customer data and interactions distinctly from other customers. Moreover, customer information is not shared in any way.</p>\n<p>In a single-tenant architecture, the provider helps manage the software instance and dedicated infrastructure while giving a single-tenant nearly complete flexibility over software and infrastructure modification. Single-tenancy models provide control, reliability, security, and backup capability. In addition, each tenant has its independent database and software instance, keeping them separate from one another. Each tenant's data also has a remote backup, allowing tenants to restore their data in case of data loss quickly. In most cases, tenants can choose when they want to install any available updates themselves rather than waiting for the service provider to do so.</p>\n<p>Ultimately, potential customers who desire more control and flexibility to meet specific needs in their environment would likely prefer a single-tenant infrastructure over other solutions.</p>\n<h3 id=\"benefits-of-single-tenancy\" style=\"position:relative;\"><a href=\"#benefits-of-single-tenancy\" aria-label=\"benefits of single tenancy permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Benefits of Single-Tenancy</h3>\n<p>Although single-tenancy architecture is uncommon, it caters to easy auditing and maintenance. Here is the list of some other benefits a single-tenant cloud provides:</p>\n<ul>\n<li><strong>Excellent Reliability:</strong> Single-tenant architectures are typically more reliable because one software instance serves one customer. So the entire system remains unaffected by other cloud traffic and peak load performance. Also, it becomes easier to scale as compared to the multi-tenant. Moreover, one can configure In-transit Network Routing in single-tenancy.</li>\n<li><strong>Enhanced Data Security:</strong> Single-tenant cloud architecture separates application instances and supporting components like database and infrastructure for each customer within the same provider. So, there is no way for others outside of your organization to access your data in case of vulnerability. As a result, even if a customer with the same service provider experiences a data breach, other tenants remain protected.</li>\n<li><strong>Simplified Migration:</strong> It is easier to migrate data from a single-tenant architecture since the data store contains data from a single customer. One does not need to think about mixing customer data or using complicated migration scripts.</li>\n<li><strong>Easy Customizations:</strong> In the case of SaaS, mainly the services are thoroughly managed by the service provider’s team. However, the service provider can give dedicated server access to customers in the case of single-tenant—for example; server logs access to customers. The same level of ownership or customization cannot be provided for multi-tenant customers.</li>\n</ul>\n<h3 id=\"drawbacks-of-single-tenancy\" style=\"position:relative;\"><a href=\"#drawbacks-of-single-tenancy\" aria-label=\"drawbacks of single tenancy permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Drawbacks of Single-Tenancy</h3>\n<p>Despite all of the potential benefits of single-tenancy, it is still the least popular architecture among competing options, which you could attribute to some of its drawbacks. The following are some of the disadvantages of single-tenancy:</p>\n<ul>\n<li><strong>Higher Costs:</strong> Hosting one SaaS instance per customer increases the cost due to setup time, resources, customization, and maintenance.</li>\n<li><strong>Lesser Deployments:</strong> While releasing customer-specific updates and features, all customer benefits in case of multi-tenant. Such feature updates are not generally released for single-tenant customers because of their separate application instances and related components.</li>\n</ul>\n<p><strong><a href=\"https://www.loginradius.com/resource/ebook/single-tenant-vs-multi-tenant-business/\">Single-Tenant or Multi-Tenant SaaS: Which is Better for Your Business</a></strong></p>\n<h2 id=\"multi-tenant-cloud-architecture\" style=\"position:relative;\"><a href=\"#multi-tenant-cloud-architecture\" aria-label=\"multi tenant cloud architecture permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Multi-Tenant Cloud Architecture</h2>\n<p><a href=\"https://www.loginradius.com/multi-tenant-cloud/\">Multi-tenancy</a> is another cloud architecture wherein a single instance of a software program serves numerous customers. People usually refer to the real estate analogy to explain Single-tenant vs. Multi-tenant cloud architecture.</p>\n<p>Every user in a single-tenant cloud lives alone in a single building with its security system and amenities, entirely secluded from neighboring buildings. Tenants in multi-tenant cloud architecture, on the other hand, live in various apartments within a single apartment complex. They are both protected by the same security system and have access to the same communal facilities. However, each resident has a key to their apartment, ensuring that their privacy is protected. The actions of other tenants, however, are more likely to affect their comfort in the property.</p>\n<p>Most startups choose a multi-tenant architecture having a single massive database containing all customer information. Customer data is kept confidential with the necessary security systems in place. While customers cannot view each other's data, they are all stored in the same database, and all of the data gets processed by the same computer.</p>\n<h3 id=\"benefits-of-multi-tenancy\" style=\"position:relative;\"><a href=\"#benefits-of-multi-tenancy\" aria-label=\"benefits of multi tenancy permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Benefits of Multi-Tenancy</h3>\n<ul>\n<li><strong>Lower Costs:</strong> SaaS allows businesses of all sizes to share infrastructure and data center operations expenditures, resulting in lower prices. It also reduces infrastructure implications as compared to single-tenancy-hosted solutions.</li>\n<li><strong>Frequent Deployments:</strong> All customers get the feature updates when SaaS vendors release features in a multi-tenancy environment, even if a specific multi-tenancy customer initially requested the feature.</li>\n</ul>\n<p>In contrast, the single-tenancy customer does not benefit from such scenarios.</p>\n<h3 id=\"drawbacks-of-multi-tenancy\" style=\"position:relative;\"><a href=\"#drawbacks-of-multi-tenancy\" aria-label=\"drawbacks of multi tenancy permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Drawbacks of Multi-Tenancy</h3>\n<p>While multi-tenant cloud architecture is usually the best option for most SaaS customers, it can have <a href=\"https://web.archive.org/web/20150221181153/http://se2.informatik.uni-wuerzburg.de/pa/uploads/papers/paper-371.pdf\">some drawbacks</a>, including:</p>\n<ul>\n<li>\n<p><strong>Greater Security Risk:</strong> As different customers share resources, the risk factor in a multi-tenant setup increases. In contrast to a single-tenant cloud, where security events remain isolated to a single customer, it is more likely to harm other customers if one customer's data is compromised.</p>\n<p>In multi-tenancy, an organization's data is not visible to other tenants. However, multiple users without the organization's affiliation get access to the same database. This increases the security risks.</p>\n</li>\n<li><strong>Resource Availability:</strong> The increased load of one customer can impact other customers sharing the same resources in a multi-tenancy setup. While in a single-tenancy architecture of SaaS, this risk is not present as customers are provided with dedicated resources.</li>\n</ul>\n<h2 id=\"when-to-use-one-over-the-other\" style=\"position:relative;\"><a href=\"#when-to-use-one-over-the-other\" aria-label=\"when to use one over the other permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>When to Use One Over the Other</h2>\n<p>A single-tenant setup of SaaS may be appropriate for certain companies or sectors where customer data privacy and security are paramount. The healthcare and finance industries are excellent examples, leveraging single-tenant cloud systems.</p>\n<p>For example, when working with patient information, applications in the healthcare industry must comply with <a href=\"https://www.loginradius.com/industry-healthcare/\">HIPAA regulations</a>. To maintain compliance, each hospital may need to establish its own data center on-site. The same is true for certain forms of financial information.</p>\n<p>Most consumer-facing applications and start-ups that require comparatively less customizability tend to use a multi-tenant setup of SaaS. Also, multi-tenancy is preferred by organizations that want to opt for a cost-effective solution.</p>\n<p>To learn more about Single-Tenant vs Multi-Tenant Cloud, check out the <a href=\"https://www.loginradius.com/resource/infographic/single-tenant-vs-multi-tenant-cloud\">infographic by LoginRadius</a>.</p>\n<h2 id=\"conclusion\" style=\"position:relative;\"><a href=\"#conclusion\" aria-label=\"conclusion permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Conclusion</h2>\n<p>There are a lot of other factors an organization must keep in mind while deciding which SaaS architecture to choose. Some business factors are the purpose of cloud adoption, type of application, budget, scalability, customization, migration, visibility, backup, and recovery. Finally, organizations must brainstorm what they want to achieve and how their company operates to arrive at the best, ideal solution.</p>\n<h2 id=\"faqs\" style=\"position:relative;\"><a href=\"#faqs\" aria-label=\"faqs permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>FAQs</h2>\n<p><strong>1. What is the difference between single tenant vs multi tenant?</strong></p>\n<p>In single tenant architecture, a dedicated cloud infrastructure serves one client, while in a multi tenant cloud, multiple businesses share the same infrastructure, which optimizes resources.</p>\n<p><strong>2. Is AWS a single tenant?</strong></p>\n<p>AWS offers primarily multi tenant cloud environments, but single tenant architecture can be achieved through dedicated hosting options like Amazon EC2 Dedicated Instances.</p>\n<p><strong>3. What is a multi tenant cloud system?</strong></p>\n<p>A multi tenant cloud system allows multiple businesses to share the same infrastructure, with resources and applications managed centrally for efficiency.</p>\n<p><strong>4. What are some examples of single tenant and multi tenant systems?</strong></p>\n<p>Private clouds or custom SaaS deployments are examples of single tenant architecture, while platforms like Salesforce represent multi tenant cloud systems.</p>\n<p><strong>5. Which SaaS architecture is more secure: single tenant or multi tenant?</strong></p>\n<p>Single tenant architectures generally offer more security due to isolated data environments, while multi-tenant systems have more shared risks but are often well-protected by cloud providers.</p>\n<p><strong>6. What is tenancy in cloud computing?</strong></p>\n<p>Tenancy in cloud computing refers to how computing resources are shared—whether through single tenant or multi tenant systems that isolate or combine client resources.</p>\n<p><strong>7. What is a tenant in cloud computing?</strong></p>\n<p>A tenant in cloud computing is an entity, such as a business, that uses a specific cloud infrastructure, either in a single tenant or multi tenant setup.</p>\n<p><em>LoginRadius provides both <a href=\"https://www.loginradius.com/private-cloud/\">single-tenant</a> and <a href=\"https://www.loginradius.com/multi-tenant-cloud/\">multi-tenant</a> SaaS architecture for our CIAM solution.</em></p>\n<style class=\"grvsc-styles\">\n  .grvsc-container {\n    overflow: auto;\n    -webkit-overflow-scrolling: touch;\n    padding-top: 1rem;\n    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));\n    padding-bottom: 1rem;\n    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));\n    border-radius: 8px;\n    border-radius: var(--grvsc-border-radius, 8px);\n    font-feature-settings: normal;\n  }\n  \n  .grvsc-code {\n    display: inline-block;\n    min-width: 100%;\n  }\n  \n  .grvsc-line {\n    display: inline-block;\n    box-sizing: border-box;\n    width: 100%;\n    padding-left: 1.5rem;\n    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));\n    padding-right: 1.5rem;\n    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));\n  }\n  \n  .grvsc-line-highlighted {\n    background-color: var(--grvsc-line-highlighted-background-color, transparent);\n    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, transparent);\n  }\n  \n</style>","frontmatter":{"date":"December 01, 2021","updated_date":null,"description":"When choosing a SaaS architecture for your business, the decision between single-tenant and multi-tenant models can significantly impact performance, security, and cost. This blog explores the key differences, advantages, and potential drawbacks of each approach, helping you determine which solution best aligns with your business needs.","title":"Single-Tenant vs. Multi-Tenant: Which SaaS Architecture is better for Your Business? ","tags":["saas","Architecture"],"pinned":null,"coverImage":{"childImageSharp":{"fluid":{"aspectRatio":1.5037593984962405,"src":"/static/6e91625d67f997fc0d90b890f7111691/ee604/coverImage.png","srcSet":"/static/6e91625d67f997fc0d90b890f7111691/69585/coverImage.png 200w,\n/static/6e91625d67f997fc0d90b890f7111691/497c6/coverImage.png 400w,\n/static/6e91625d67f997fc0d90b890f7111691/ee604/coverImage.png 800w,\n/static/6e91625d67f997fc0d90b890f7111691/f3583/coverImage.png 1200w","sizes":"(max-width: 800px) 100vw, 800px"}}},"author":{"id":"Rakesh Soni","github":"oyesoni","avatar":"rakesh-soni.jpg"}}}},{"node":{"excerpt":"What is a Smart Contract? Smart Contracts 📝 are simple programs stored on a blockchain network. You can say it's like an agreement between…","fields":{"slug":"/engineering/guest-post/ethereum-smart-contract-tutorial/"},"html":"<h2 id=\"what-is-a-smart-contract\" style=\"position:relative;\"><a href=\"#what-is-a-smart-contract\" aria-label=\"what is a smart contract permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>What is a Smart Contract?</h2>\n<p><a href=\"https://en.wikipedia.org/wiki/Smart_contract\"><strong>Smart Contracts</strong></a> 📝 are simple programs stored on a blockchain network.</p>\n<p>You can say it's like an agreement between two people in the form of computer code. The transactions in a smart contract are processed by the blockchain and stored as a <strong>42 character hex address</strong> with the prefix <code>\"0x\"</code>). All of which means that they can be sent automatically without needing a third party.</p>\n<p><strong>🤔 Remember:</strong> They're stored in a public database. And once a smart contract is deployed, it cannot be changed.</p>\n<h2 id=\"what-is-solidity\" style=\"position:relative;\"><a href=\"#what-is-solidity\" aria-label=\"what is solidity permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>What is Solidity?</h2>\n<p>Solidity is one of the most popular languages used for building smart contracts on Ethereum Blockchain. It's also an object-oriented programming language.</p>\n<h2 id=\"build-your-first-smart-contract\" style=\"position:relative;\"><a href=\"#build-your-first-smart-contract\" aria-label=\"build your first smart contract permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Build Your First Smart Contract</h2>\n<ol>\n<li>Open <strong><code>Remix</code> IDE</strong> from <a href=\"https://remix.ethereum.org/\">here</a>.</li>\n<li>Click on <code>Sure</code> and then <code>Done</code>.</li>\n<li>Under <code>default_workshop</code>, click on <code>create new file</code>.</li>\n<li>Rename it as <code>Hostel.sol</code>.</li>\n</ol>\n<p>Now you're ready to write your first <strong>Smart Contract</strong>. 🤩</p>\n<h3 id=\"contract-code\" style=\"position:relative;\"><a href=\"#contract-code\" aria-label=\"contract code permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Contract Code</h3>\n<ol>\n<li>You have to provide the <code>solidity version</code> in the smart contract:</li>\n</ol>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"ruby\" data-index=\"0\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">pragma solidity ^</span><span class=\"mtk7\">0.5</span><span class=\"mtk1\">.</span><span class=\"mtk7\">16</span><span class=\"mtk1\">;</span></span></code></pre>\n<ol start=\"2\">\n<li>Now create the main contract named <code>Hostel</code>:</li>\n</ol>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"ruby\" data-index=\"1\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">contract </span><span class=\"mtk12\">Hostel</span><span class=\"mtk1\">{</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    ...</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">}</span></span></code></pre>\n<ol start=\"3\">\n<li>Now, inside the <code>contract Hostel{...}</code> follow the steps below.</li>\n<li>Create some variables where the smart contract will store the <a href=\"https://ethereum.stackexchange.com/questions/20874/payable-function-in-solidity\"><strong>payable</strong></a> <code>address</code> (42 char hex string with prefix : <code>\"0x\"</code>) of the <code>Landlord</code> &#x26; the <code>Tenant</code>.</li>\n</ol>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"ruby\" data-index=\"2\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">    address payable tenant;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    address payable landlord;</span></span></code></pre>\n<ol start=\"5\">\n<li>Create some <a href=\"https://ethereum.stackexchange.com/questions/19380/external-vs-public-best-practices\"><strong>public</strong></a> variables where the smart contract will store some integer values. For this, there's a data type called <code>uint</code> (256-bit unsigned integer)</li>\n</ol>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"ruby\" data-index=\"3\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">    uint </span><span class=\"mtk4\">public</span><span class=\"mtk1\"> no_of_rooms = </span><span class=\"mtk7\">0</span><span class=\"mtk1\">;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    uint </span><span class=\"mtk4\">public</span><span class=\"mtk1\"> no_of_agreement = </span><span class=\"mtk7\">0</span><span class=\"mtk1\">;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    uint </span><span class=\"mtk4\">public</span><span class=\"mtk1\"> no_of_rent = </span><span class=\"mtk7\">0</span><span class=\"mtk1\">;</span></span></code></pre>\n<ol start=\"6\">\n<li>Now, create a <code>structure</code> to store details of each Hostel room like <code>Hostel no.</code>, <code>Hostel name</code>, <code>Hostel address</code>, <code>No of total agreements</code>, <code>Monthly rent</code>, <code>One-time security deposit</code>, <code>Last agreement sign time</code>, <code>Vacancy</code>, <code>Landlord address</code>, and <code>Current Tenant Address</code>.</li>\n</ol>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"ruby\" data-index=\"4\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">    struct </span><span class=\"mtk12\">Room</span><span class=\"mtk1\">{</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        uint roomid;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        uint agreementid;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        string roomname;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        string roomaddress;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        uint rent_per_month;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        uint securityDeposit;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        uint timestamp;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        bool vacant;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        address payable landlord;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        address payable currentTenant;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    }</span></span></code></pre>\n<ol start=\"7\">\n<li><code>map</code> previous <code>structure</code> with a <code>uint</code>(named : <code>roomid</code>).</li>\n</ol>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"ruby\" data-index=\"5\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">mapping(uint =&gt; </span><span class=\"mtk12\">Room</span><span class=\"mtk1\">) </span><span class=\"mtk4\">public</span><span class=\"mtk1\"> </span><span class=\"mtk12\">Room_by_No</span><span class=\"mtk1\">;</span></span></code></pre>\n<ol start=\"8\">\n<li>Similar to the above, create a <code>structure</code> for each <code>Rental Agreement</code> and map that with a <code>uint</code>(named: <code>agreementid</code>). This will store details like: <code>Hostel no.</code>, <code>Agreement No</code>, <code>Hostel name</code>, <code>Hostel address</code>, <code>Monthly rent</code>, <code>One-time security deposit</code>,<code>Lockin Period</code>, <code>Agreement sign time</code>, <code>Landlord address</code>, and <code>Tenant Address</code>.</li>\n</ol>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"ruby\" data-index=\"6\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">    struct </span><span class=\"mtk12\">RoomAgreement</span><span class=\"mtk1\">{</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        uint roomid;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        uint agreementid;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        string </span><span class=\"mtk12\">Roomname</span><span class=\"mtk1\">;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        string </span><span class=\"mtk12\">RoomAddresss</span><span class=\"mtk1\">;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        uint rent_per_month;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        uint securityDeposit;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        uint lockInPeriod;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        uint timestamp;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        address payable tenantAddress;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        address payable landlordAddress;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    }</span></span></code></pre>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"ruby\" data-index=\"7\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">mapping(uint =&gt; </span><span class=\"mtk12\">RoomAgreement</span><span class=\"mtk1\">) </span><span class=\"mtk4\">public</span><span class=\"mtk1\"> </span><span class=\"mtk12\">RoomAgreement_by_No</span><span class=\"mtk1\">;</span></span></code></pre>\n<ol start=\"9\">\n<li>Now, create a <code>structure</code> for each <code>Rent</code> payment and map that with a <code>uint</code>. This will store details like: <code>Rent No.</code>, <code>Hostel no.</code>, <code>Agreement No</code>, <code>Hostel name</code>, <code>Hostel address</code>, <code>Monthly rent</code>, <code>Rent payment time</code>, <code>Landlord address</code>, and <code>Tenant Address</code>.</li>\n</ol>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"ruby\" data-index=\"8\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">    struct </span><span class=\"mtk12\">Rent</span><span class=\"mtk1\">{</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        uint rentno;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        uint roomid;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        uint agreementid;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        string </span><span class=\"mtk12\">Roomname</span><span class=\"mtk1\">;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        string </span><span class=\"mtk12\">RoomAddresss</span><span class=\"mtk1\">;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        uint rent_per_month;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        uint timestamp;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        address payable tenantAddress;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        address payable landlordAddress;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    }</span></span></code></pre>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"ruby\" data-index=\"9\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">   mapping(uint =&gt; </span><span class=\"mtk12\">Rent</span><span class=\"mtk1\">) </span><span class=\"mtk4\">public</span><span class=\"mtk1\"> </span><span class=\"mtk12\">Rent_by_No</span><span class=\"mtk1\">;</span></span></code></pre>\n<ol start=\"10\">\n<li>\n<p>Create some <a href=\"https://ethereum.stackexchange.com/questions/48971/what-are-function-modifiers\"><strong>modifiers</strong></a> that will help you verify a few things before running a function.</p>\n<p>Here <code>require(...);</code> means that if the given condition is not satisfied, the function won't execute, and the given string will appear as an error code.</p>\n</li>\n</ol>\n<p>The following will check if the message sender is the landlord.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"ruby\" data-index=\"10\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">    modifier onlyLandlord(uint </span><span class=\"mtk12\">_index</span><span class=\"mtk1\">) {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk4\">require</span><span class=\"mtk1\">(msg.sender == </span><span class=\"mtk10\">Room_by_No</span><span class=\"mtk1\">[</span><span class=\"mtk12\">_index</span><span class=\"mtk1\">].landlord, </span><span class=\"mtk8\">&quot;Only landlord can access this&quot;</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk12\">_</span><span class=\"mtk1\">;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    }</span></span></code></pre>\n<p>The following will check if the message sender is anyone except the landlord.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"ruby\" data-index=\"11\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">    modifier notLandLord(uint </span><span class=\"mtk12\">_index</span><span class=\"mtk1\">) {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk4\">require</span><span class=\"mtk1\">(msg.sender != </span><span class=\"mtk10\">Room_by_No</span><span class=\"mtk1\">[</span><span class=\"mtk12\">_index</span><span class=\"mtk1\">].landlord, </span><span class=\"mtk8\">&quot;Only Tenant can access this&quot;</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk12\">_</span><span class=\"mtk1\">;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    }</span></span></code></pre>\n<p>The following will check whether the room is vacant or not.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"ruby\" data-index=\"12\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">    modifier </span><span class=\"mtk12\">OnlyWhileVacant</span><span class=\"mtk1\">(uint </span><span class=\"mtk12\">_index</span><span class=\"mtk1\">){</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk4\">require</span><span class=\"mtk1\">(</span><span class=\"mtk10\">Room_by_No</span><span class=\"mtk1\">[</span><span class=\"mtk12\">_index</span><span class=\"mtk1\">].vacant == </span><span class=\"mtk4\">true</span><span class=\"mtk1\">, </span><span class=\"mtk8\">&quot;Room is currently Occupied.&quot;</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk12\">_</span><span class=\"mtk1\">;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    }</span></span></code></pre>\n<p>The following will check whether the tenant has enough <code>Ether</code> in his wallet to pay the rent.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"ruby\" data-index=\"13\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">    modifier enoughRent(uint </span><span class=\"mtk12\">_index</span><span class=\"mtk1\">) {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk4\">require</span><span class=\"mtk1\">(msg.value &gt;= uint(</span><span class=\"mtk10\">Room_by_No</span><span class=\"mtk1\">[</span><span class=\"mtk12\">_index</span><span class=\"mtk1\">].rent_per_month), </span><span class=\"mtk8\">&quot;Not enough Ether in your wallet&quot;</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk12\">_</span><span class=\"mtk1\">;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    }</span></span></code></pre>\n<p>The following will check whether the tenant has enough <code>Ether</code> in his wallet to pay a one-time security deposit and one month's rent in advance.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"ruby\" data-index=\"14\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">    modifier enoughAgreementfee(uint </span><span class=\"mtk12\">_index</span><span class=\"mtk1\">) {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk4\">require</span><span class=\"mtk1\">(msg.value &gt;= uint(uint(</span><span class=\"mtk10\">Room_by_No</span><span class=\"mtk1\">[</span><span class=\"mtk12\">_index</span><span class=\"mtk1\">].rent_per_month) + uint(</span><span class=\"mtk10\">Room_by_No</span><span class=\"mtk1\">[</span><span class=\"mtk12\">_index</span><span class=\"mtk1\">].securityDeposit)), </span><span class=\"mtk8\">&quot;Not enough Ether in your wallet&quot;</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk12\">_</span><span class=\"mtk1\">;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    }</span></span></code></pre>\n<p>The following will check whether the tenant's address is the same as who has signed the previous rental agreement.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"ruby\" data-index=\"15\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">    modifier sameTenant(uint </span><span class=\"mtk12\">_index</span><span class=\"mtk1\">) {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk4\">require</span><span class=\"mtk1\">(msg.sender == </span><span class=\"mtk10\">Room_by_No</span><span class=\"mtk1\">[</span><span class=\"mtk12\">_index</span><span class=\"mtk1\">].currentTenant, </span><span class=\"mtk8\">&quot;No previous agreement found with you & landlord&quot;</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk12\">_</span><span class=\"mtk1\">;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    }</span></span></code></pre>\n<p>The following will check whether any time is left for the agreement to end.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"ruby\" data-index=\"16\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">    modifier </span><span class=\"mtk12\">AgreementTimesLeft</span><span class=\"mtk1\">(uint </span><span class=\"mtk12\">_index</span><span class=\"mtk1\">) {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        uint </span><span class=\"mtk12\">_AgreementNo</span><span class=\"mtk1\"> = </span><span class=\"mtk10\">Room_by_No</span><span class=\"mtk1\">[</span><span class=\"mtk12\">_index</span><span class=\"mtk1\">].agreementid;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        uint time = </span><span class=\"mtk10\">RoomAgreement_by_No</span><span class=\"mtk1\">[</span><span class=\"mtk12\">_AgreementNo</span><span class=\"mtk1\">].timestamp + </span><span class=\"mtk10\">RoomAgreement_by_No</span><span class=\"mtk1\">[</span><span class=\"mtk12\">_AgreementNo</span><span class=\"mtk1\">].lockInPeriod;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk4\">require</span><span class=\"mtk1\">(now &lt; time, </span><span class=\"mtk8\">&quot;Agreement already Ended&quot;</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk12\">_</span><span class=\"mtk1\">;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    }</span></span></code></pre>\n<p>The following will check whether 365 days have passed after the last agreement has been created.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"ruby\" data-index=\"17\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">    modifier </span><span class=\"mtk12\">AgreementTimesUp</span><span class=\"mtk1\">(uint </span><span class=\"mtk12\">_index</span><span class=\"mtk1\">) {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        uint </span><span class=\"mtk12\">_AgreementNo</span><span class=\"mtk1\"> = </span><span class=\"mtk10\">Room_by_No</span><span class=\"mtk1\">[</span><span class=\"mtk12\">_index</span><span class=\"mtk1\">].agreementid;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        uint time = </span><span class=\"mtk10\">RoomAgreement_by_No</span><span class=\"mtk1\">[</span><span class=\"mtk12\">_AgreementNo</span><span class=\"mtk1\">].timestamp + </span><span class=\"mtk10\">RoomAgreement_by_No</span><span class=\"mtk1\">[</span><span class=\"mtk12\">_AgreementNo</span><span class=\"mtk1\">].lockInPeriod;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk4\">require</span><span class=\"mtk1\">(now &gt; time, </span><span class=\"mtk8\">&quot;Time is left for contract to end&quot;</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk12\">_</span><span class=\"mtk1\">;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    }</span></span></code></pre>\n<p>The following will check whether 30 days have passed after the last rent payment.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"ruby\" data-index=\"18\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">    modifier </span><span class=\"mtk12\">RentTimesUp</span><span class=\"mtk1\">(uint </span><span class=\"mtk12\">_index</span><span class=\"mtk1\">) {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        uint time = </span><span class=\"mtk10\">Room_by_No</span><span class=\"mtk1\">[</span><span class=\"mtk12\">_index</span><span class=\"mtk1\">].timestamp + </span><span class=\"mtk7\">30</span><span class=\"mtk1\"> days;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk4\">require</span><span class=\"mtk1\">(now &gt;= time, </span><span class=\"mtk8\">&quot;Time left to pay Rent&quot;</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk12\">_</span><span class=\"mtk1\">;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    }</span></span></code></pre>\n<ol start=\"11\">\n<li>Now, create some <a href=\"https://docs.soliditylang.org/en/v0.4.24/introduction-to-smart-contracts.html\"><strong>functions</strong></a></li>\n</ol>\n<p>The following function will be used to add Rooms.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"ruby\" data-index=\"19\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">    function addRoom(string memory </span><span class=\"mtk12\">_roomname</span><span class=\"mtk1\">, string memory </span><span class=\"mtk12\">_roomaddress</span><span class=\"mtk1\">, uint </span><span class=\"mtk12\">_rentcost</span><span class=\"mtk1\">, uint  </span><span class=\"mtk12\">_securitydeposit</span><span class=\"mtk1\">) </span><span class=\"mtk4\">public</span><span class=\"mtk1\"> {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk4\">require</span><span class=\"mtk1\">(msg.sender != address(</span><span class=\"mtk7\">0</span><span class=\"mtk1\">));</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        no_of_rooms ++;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        bool </span><span class=\"mtk12\">_vacancy</span><span class=\"mtk1\"> = </span><span class=\"mtk4\">true</span><span class=\"mtk1\">;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk10\">Room_by_No</span><span class=\"mtk1\">[no_of_rooms] = </span><span class=\"mtk12\">Room</span><span class=\"mtk1\">(no_of_rooms,</span><span class=\"mtk7\">0</span><span class=\"mtk1\">,</span><span class=\"mtk12\">_roomname</span><span class=\"mtk1\">,</span><span class=\"mtk12\">_roomaddress</span><span class=\"mtk1\">, </span><span class=\"mtk12\">_rentcost</span><span class=\"mtk1\">,</span><span class=\"mtk12\">_securitydeposit</span><span class=\"mtk1\">,</span><span class=\"mtk7\">0</span><span class=\"mtk1\">,</span><span class=\"mtk12\">_vacancy</span><span class=\"mtk1\">, msg.sender, address(</span><span class=\"mtk7\">0</span><span class=\"mtk1\">)); </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    }</span></span></code></pre>\n<p>Now, create a function to sign the rental agreement for a hostel room between the landlord and a tenant.</p>\n<p>Before creating the <code>signAgreement</code> function, remember the following:</p>\n<ul>\n<li>The function will only execute if the user is <code>Tenant</code>, meaning that the user's address and the landlord's address don't match.</li>\n<li>The function will only execute if the user has enough ether (payable 'ether') in their Ethereum wallet.(Enough ether means = one-time security deposit + 1st month's rent)</li>\n</ul>\n<p>Let's use those modifiers here, so that:</p>\n<ul>\n<li>The function <code>signAgreement</code> will only execute only if the said room is vacant and the tenant has enough ether in their wallet.</li>\n</ul>\n<p>Remember those modifiers in point no.10? Use those modifiers here to execute the following function.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"ruby\" data-index=\"20\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">    function signAgreement(uint </span><span class=\"mtk12\">_index</span><span class=\"mtk1\">) </span><span class=\"mtk4\">public</span><span class=\"mtk1\"> payable notLandLord(</span><span class=\"mtk12\">_index</span><span class=\"mtk1\">) enoughAgreementfee(</span><span class=\"mtk12\">_index</span><span class=\"mtk1\">) </span><span class=\"mtk12\">OnlyWhileVacant</span><span class=\"mtk1\">(</span><span class=\"mtk12\">_index</span><span class=\"mtk1\">) {</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk4\">require</span><span class=\"mtk1\">(msg.sender != address(</span><span class=\"mtk7\">0</span><span class=\"mtk1\">));</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        address payable </span><span class=\"mtk12\">_landlord</span><span class=\"mtk1\"> = </span><span class=\"mtk10\">Room_by_No</span><span class=\"mtk1\">[</span><span class=\"mtk12\">_index</span><span class=\"mtk1\">].landlord;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        uint totalfee = </span><span class=\"mtk10\">Room_by_No</span><span class=\"mtk1\">[</span><span class=\"mtk12\">_index</span><span class=\"mtk1\">].rent_per_month + </span><span class=\"mtk10\">Room_by_No</span><span class=\"mtk1\">[</span><span class=\"mtk12\">_index</span><span class=\"mtk1\">].securityDeposit;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk12\">_landlord</span><span class=\"mtk1\">.transfer(totalfee);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        no_of_agreement++;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk10\">Room_by_No</span><span class=\"mtk1\">[</span><span class=\"mtk12\">_index</span><span class=\"mtk1\">].currentTenant = msg.sender;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk10\">Room_by_No</span><span class=\"mtk1\">[</span><span class=\"mtk12\">_index</span><span class=\"mtk1\">].vacant = </span><span class=\"mtk4\">false</span><span class=\"mtk1\">;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk10\">Room_by_No</span><span class=\"mtk1\">[</span><span class=\"mtk12\">_index</span><span class=\"mtk1\">].timestamp = block.timestamp;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk10\">Room_by_No</span><span class=\"mtk1\">[</span><span class=\"mtk12\">_index</span><span class=\"mtk1\">].agreementid = no_of_agreement;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk10\">RoomAgreement_by_No</span><span class=\"mtk1\">[no_of_agreement]=</span><span class=\"mtk12\">RoomAgreement</span><span class=\"mtk1\">(</span><span class=\"mtk12\">_index</span><span class=\"mtk1\">,no_of_agreement,</span><span class=\"mtk10\">Room_by_No</span><span class=\"mtk1\">[</span><span class=\"mtk12\">_index</span><span class=\"mtk1\">].roomname,</span><span class=\"mtk10\">Room_by_No</span><span class=\"mtk1\">[</span><span class=\"mtk12\">_index</span><span class=\"mtk1\">].roomaddress,</span><span class=\"mtk10\">Room_by_No</span><span class=\"mtk1\">[</span><span class=\"mtk12\">_index</span><span class=\"mtk1\">].rent_per_month,</span><span class=\"mtk10\">Room_by_No</span><span class=\"mtk1\">[</span><span class=\"mtk12\">_index</span><span class=\"mtk1\">].securityDeposit,</span><span class=\"mtk7\">365</span><span class=\"mtk1\"> days,block.timestamp,msg.sender,</span><span class=\"mtk12\">_landlord</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        no_of_rent++;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk10\">Rent_by_No</span><span class=\"mtk1\">[no_of_rent] = </span><span class=\"mtk12\">Rent</span><span class=\"mtk1\">(no_of_rent,</span><span class=\"mtk12\">_index</span><span class=\"mtk1\">,no_of_agreement,</span><span class=\"mtk10\">Room_by_No</span><span class=\"mtk1\">[</span><span class=\"mtk12\">_index</span><span class=\"mtk1\">].roomname,</span><span class=\"mtk10\">Room_by_No</span><span class=\"mtk1\">[</span><span class=\"mtk12\">_index</span><span class=\"mtk1\">].roomaddress,</span><span class=\"mtk10\">Room_by_No</span><span class=\"mtk1\">[</span><span class=\"mtk12\">_index</span><span class=\"mtk1\">].rent_per_month,now,msg.sender,</span><span class=\"mtk12\">_landlord</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    }</span></span></code></pre>\n<p>Now, create a function that the tenant will use to pay the monthly rent to the landlord.</p>\n<p>Before creating the <code>payRent</code> function, remember the following:</p>\n<ul>\n<li>The function will only execute if the user's address and previous tenant's address both are the same, meaning that the user can only pay rent if he/she has signed an agreement with the landlord within the last 365 days.</li>\n<li>The function will only execute if the tenant had paid his/her previous rent more than a month ago.</li>\n<li>The function will only execute if the user has enough ether (payable 'ether') in his/her Ethereum wallet. (enough ether = enough room rent).</li>\n</ul>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"ruby\" data-index=\"21\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">    function payRent(uint </span><span class=\"mtk12\">_index</span><span class=\"mtk1\">) </span><span class=\"mtk4\">public</span><span class=\"mtk1\"> payable sameTenant(</span><span class=\"mtk12\">_index</span><span class=\"mtk1\">) </span><span class=\"mtk12\">RentTimesUp</span><span class=\"mtk1\">(</span><span class=\"mtk12\">_index</span><span class=\"mtk1\">) enoughRent(</span><span class=\"mtk12\">_index</span><span class=\"mtk1\">){</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk4\">require</span><span class=\"mtk1\">(msg.sender != address(</span><span class=\"mtk7\">0</span><span class=\"mtk1\">));</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        address payable </span><span class=\"mtk12\">_landlord</span><span class=\"mtk1\"> = </span><span class=\"mtk10\">Room_by_No</span><span class=\"mtk1\">[</span><span class=\"mtk12\">_index</span><span class=\"mtk1\">].landlord;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        uint </span><span class=\"mtk12\">_rent</span><span class=\"mtk1\"> = </span><span class=\"mtk10\">Room_by_No</span><span class=\"mtk1\">[</span><span class=\"mtk12\">_index</span><span class=\"mtk1\">].rent_per_month;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk12\">_landlord</span><span class=\"mtk1\">.transfer(</span><span class=\"mtk12\">_rent</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk10\">Room_by_No</span><span class=\"mtk1\">[</span><span class=\"mtk12\">_index</span><span class=\"mtk1\">].currentTenant = msg.sender;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk10\">Room_by_No</span><span class=\"mtk1\">[</span><span class=\"mtk12\">_index</span><span class=\"mtk1\">].vacant = </span><span class=\"mtk4\">false</span><span class=\"mtk1\">;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        no_of_rent++;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk10\">Rent_by_No</span><span class=\"mtk1\">[no_of_rent] = </span><span class=\"mtk12\">Rent</span><span class=\"mtk1\">(no_of_rent,</span><span class=\"mtk12\">_index</span><span class=\"mtk1\">,</span><span class=\"mtk10\">Room_by_No</span><span class=\"mtk1\">[</span><span class=\"mtk12\">_index</span><span class=\"mtk1\">].agreementid,</span><span class=\"mtk10\">Room_by_No</span><span class=\"mtk1\">[</span><span class=\"mtk12\">_index</span><span class=\"mtk1\">].roomname,</span><span class=\"mtk10\">Room_by_No</span><span class=\"mtk1\">[</span><span class=\"mtk12\">_index</span><span class=\"mtk1\">].roomaddress,</span><span class=\"mtk12\">_rent</span><span class=\"mtk1\">,now,msg.sender,</span><span class=\"mtk10\">Room_by_No</span><span class=\"mtk1\">[</span><span class=\"mtk12\">_index</span><span class=\"mtk1\">].landlord);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    }</span></span></code></pre>\n<p>Let's create a function that the landlord will use to mark an agreement complete.</p>\n<p>Before creating <code>agreementCompleted</code> function, remember the following:</p>\n<ul>\n<li>The function will only execute if the user's address and the landlord's address are the same.</li>\n<li>\n<p>The function will only execute if the tenant had signed that agreement more than a year ago.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"ruby\" data-index=\"22\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">function agreementCompleted(uint </span><span class=\"mtk12\">_index</span><span class=\"mtk1\">) </span><span class=\"mtk4\">public</span><span class=\"mtk1\"> payable onlyLandlord(</span><span class=\"mtk12\">_index</span><span class=\"mtk1\">) </span><span class=\"mtk12\">AgreementTimesUp</span><span class=\"mtk1\">(</span><span class=\"mtk12\">_index</span><span class=\"mtk1\">){</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk4\">require</span><span class=\"mtk1\">(msg.sender != address(</span><span class=\"mtk7\">0</span><span class=\"mtk1\">));</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk4\">require</span><span class=\"mtk1\">(</span><span class=\"mtk10\">Room_by_No</span><span class=\"mtk1\">[</span><span class=\"mtk12\">_index</span><span class=\"mtk1\">].vacant == </span><span class=\"mtk4\">false</span><span class=\"mtk1\">, </span><span class=\"mtk8\">&quot;Room is currently Occupied.&quot;</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk10\">Room_by_No</span><span class=\"mtk1\">[</span><span class=\"mtk12\">_index</span><span class=\"mtk1\">].vacant = </span><span class=\"mtk4\">true</span><span class=\"mtk1\">;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    address payable </span><span class=\"mtk12\">_Tenant</span><span class=\"mtk1\"> = </span><span class=\"mtk10\">Room_by_No</span><span class=\"mtk1\">[</span><span class=\"mtk12\">_index</span><span class=\"mtk1\">].currentTenant;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    uint </span><span class=\"mtk12\">_securitydeposit</span><span class=\"mtk1\"> = </span><span class=\"mtk10\">Room_by_No</span><span class=\"mtk1\">[</span><span class=\"mtk12\">_index</span><span class=\"mtk1\">].securityDeposit;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk12\">_Tenant</span><span class=\"mtk1\">.transfer(</span><span class=\"mtk12\">_securitydeposit</span><span class=\"mtk1\">);</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">}</span></span></code></pre>\n</li>\n</ul>\n<p>Let's create a function that the landlord will use to terminate an agreement.</p>\n<p>Before creating <code>agreementTerminated</code> function, remember the following:</p>\n<ul>\n<li>The function will only execute if the user's address and the landlord's address are the same.</li>\n<li>The function will only execute if the tenant had signed that agreement less than a year ago.</li>\n</ul>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"ruby\" data-index=\"23\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">    function agreementTerminated(uint </span><span class=\"mtk12\">_index</span><span class=\"mtk1\">) </span><span class=\"mtk4\">public</span><span class=\"mtk1\"> onlyLandlord(</span><span class=\"mtk12\">_index</span><span class=\"mtk1\">) </span><span class=\"mtk12\">AgreementTimesLeft</span><span class=\"mtk1\">(</span><span class=\"mtk12\">_index</span><span class=\"mtk1\">){</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk4\">require</span><span class=\"mtk1\">(msg.sender != address(</span><span class=\"mtk7\">0</span><span class=\"mtk1\">));</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk10\">Room_by_No</span><span class=\"mtk1\">[</span><span class=\"mtk12\">_index</span><span class=\"mtk1\">].vacant = </span><span class=\"mtk4\">true</span><span class=\"mtk1\">;</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    }</span></span></code></pre>\n<h3 id=\"compile\" style=\"position:relative;\"><a href=\"#compile\" aria-label=\"compile permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Compile</h3>\n<p>Now, click on the <code>Solidity Compile</code> option in the left sidebar.</p>\n<ol>\n<li>Select compiler version <code>0.5.16+</code></li>\n<li>Then click on <code>Compile Hostel.sol</code></li>\n</ol>\n<p>Similar to as follows:</p>\n<span class=\"gatsby-resp-image-wrapper\" style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 740px; \">\n      <span class=\"gatsby-resp-image-background-image\" style=\"padding-bottom: 194.6153846153846%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAnCAYAAAAPZ2gOAAAACXBIWXMAABYlAAAWJQFJUiTwAAAGVElEQVRIx4VWV29cRRhdhQASDzyRHm/vvfe1t6+9zWun27FT7JgkpFMcYyfGRIASSAABoUhBESDBAwIB4fcdzjd3qxOLh6Mpd+43XzlzZnTuZBPm4jzcwSLs9iS8vnG4PTn4/BMK0vcH8ggEC2rscmdhtSVg49oe7I4U/8urvu5A5zp2v/0EhvQsbOYophrzaDRPo9VeQL4wi3LlGGZmz6HB+fb0ImLxGvSGCEyWOEzmGIymKA2mUanOq7HOGa7CmJiG0zMBc3eBtjCCw2Mh1e/9aO72zTQ2isG8LhgqIhGvwOnOqQmvX0IrwuPN05sq7M4U9MYIjPzBQKNi2Ng1vB2yoS4QLiOVbcDlGYfZmkA40UQqN4NYehqZ/AwiiTp8oSoCkRqC0UnVugMluHxFuLixtDJ2+goqDTo/i+EO1WB2ZGGxJRFNtZjDRdSm5lGpzaHOfqN1Bq3pc2h3zqMzu4TcxCwCoQpCNC5tNF5HMFbXDAaiU1h76xLy8Sz05oTa1ektaOCuDoau4BlAvvXnu7C5xzWDZncBF9sFnCjlcNBIg8yll4ai3DHEgqXSbeayrpCk91Z7ql+4F+YwEqsgOd6ByZGDxRpXxqQoAqHDSFV3KIZpqPq6QKiEdKauCCwTQeYkwjREWACptI1GHc4sq51h20P2udZGzxUPPaSJwTEBizOnPIjGp1TyZ4+uIMlw/cEKglJhhv8iSFFiZIb0JRW6UKSMh5c76BTyOGiI0dPxfsjiodOVUxx1uujNDpDvvfToXN4JLDeLqGTy0JvIw0iVZ7fMdpJFqalFY3rtxFjI0+dPiTbXz2EkVkO2dJQ81HIYosFy9RSqk/MoVU6ynVM8jFNEfCSwhOgPlodQQoj5lm8maoHOR2L7AuScp3f0ikhn28hkp0mTJvPYQibXoaEy3N6Jfjp6kPWyiUdOioTsZ5UzuWb/LHu8IlkiU+Mqf9KXVqNTYYewh0IOx6rIlzoquTIhP/kDRaKkPAgwLIHmUWHkZ9M29VEeukUYnVqlZPdITPJRVKdEDMsJEa/1hvCOJ2SE2MJDqXQvZCGo1ZZSrWygjZPdUBP9aqv57jdpRVj6xHaSez0PJWcSYoJVDZPQ8URDnZo4ySsy31NoIbIURFIlFfbwm0mIPWxQPJSdRBeVR12YhuZ7fTmS1q6Xqj/q4UTfw2i0hhApEotNIUxP48xpjB5aKfNmemAh1yxyHfCKkLGJrYboIIfDHtrkbiFNzK5xjNmzGKPw6kn6g9YUDjO30goOqXEaRkdGwcRv5r6HqihZ9eHVpfvYdeN7vHztMdxbv8C2+RP2334C/cZT7GU7tv4UBvYPrP2IPatPsOvKN3iJt+brx1ZhNoaHDLo0g7uvfQvd+m94ZeNXuD5/BuODv+D54hnxLw5+8iecj/5RY+tnf3P8B3SrP0O3+TteW9iC2RAeClmOHnM4FqzhcKSOQ+Ep7AtOYi+xJ6BhX7f/RqCGvWz3B6cwxrWHow3o/WVYRnJISFHsTL5DQPW2swA2Jtxu1iD9AcIKFoZpJaRQ8v9IlTW1ETHVBNXCRI/xTjaYYgqKTkKfIWh0Sg6O3nDIMiFHT2SrUDpOGTuprtJi+ThxgsrcIInLSl16EAkLk2LSKvkayWH35ZClXGVylK90E+P5WdUXiPa5GI3IWA/yQJATI/PPHT1NbahxfA14fFrrdImMiZzl1djrFxWisPootkHNyyBfFu5hgyIODhqUA3/85E2cXbqD04trWLm4hTt3v8bGna/wznsPcePWA7y//iWu3rqPhfVPsbi0gQWuO7d8ly+MZfXA6vNQDMp5rE3Jk+MSmu03+Xy7iFPzNzE3f4sbXVc4NXcTR45fRWvxBlqdi1y3gs7MZUzkT2i33naDpcpptdtk/TzfMytoti6ocZv9RmuZBi6o/jQN1RtLal2Da7K5owODoyHfwtnzDPnMGq5c+xh3P3iMrXvf4UNic+sx3l19pNp7H/2A5ZVNzC/eZsib20Ie0sMI3zSJZJu3XItq3eS4wcufLU+D9GOJlvouc6l0RyGdmVEK36eNUuwuDw1kvci9QPoDRNScPEJL5SOQh2o+32HuOigUZ9TbXHs5RKt8V5/o0+b/MHzrWbpCLLkfnBQf71rezT1iv+hG672xNU9DQ16zbwjR88Hcfzu8BX0YIYblAAAAAElFTkSuQmCC'); background-size: cover; display: block;\"></span>\n  <img class=\"gatsby-resp-image-image\" alt=\"Compiler\" title=\"Compiler\" src=\"/static/bc558b256541ec86d2c0eb8e80ec9f12/50383/img1.png\" srcset=\"/static/bc558b256541ec86d2c0eb8e80ec9f12/a6d36/img1.png 650w,\n/static/bc558b256541ec86d2c0eb8e80ec9f12/50383/img1.png 740w\" sizes=\"(max-width: 740px) 100vw, 740px\" style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\" loading=\"lazy\">\n    </span>\n<h3 id=\"deploy\" style=\"position:relative;\"><a href=\"#deploy\" aria-label=\"deploy permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Deploy</h3>\n<p>Click on the <code>Deploy &#x26; Run Transactions</code> option in the left sidebar.</p>\n<ol>\n<li>Choose <code>Environment</code> > <code>JavaScript VM (London)</code></li>\n<li>Now click on <code>Deploy</code></li>\n</ol>\n<span class=\"gatsby-resp-image-wrapper\" style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 740px; \">\n      <span class=\"gatsby-resp-image-background-image\" style=\"padding-bottom: 194.6153846153846%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAnCAYAAAAPZ2gOAAAACXBIWXMAABYlAAAWJQFJUiTwAAAFlElEQVRIx41WyXLbRhDlIf+QSmJxAXeAK0AsBAmCOyWS4iIpkizL8qb4YKeiSjm3nFI5pirH3PIx+ZFUqpL/eOluEBRIy8uha2YamDfT3a+7J6Y6cyj9J1BrfeRyDsoVH5VqF6VyB1qpI+ty2Ze1fKvcf+P/yrTOF1zS+cjS/thXqzt88e5PJNwTZJUGFqtnmM6eYDa/Rq9/IvPF8gZ+dy06ni/pn+HoW6zWz2VeKncxGF4hpZiIFfQxkvYSBa0DJW0imWogntBlTCQN+UlJW7QOxnCd2sy3680Yq9X7sK0RCqqHdMZGtT4UqesjEdYdxOsCzgfxyIdFJQSWG9aMEVxvjiL5JKVYqBtjtL0VWu0V3NYSzdYCTfcYljPbjpVacCiP/H+RrMtkm3RDG7FStYeM1oNS8KDQCQywPv0Oq5NbLNe3mC9ekF9fYbF+hZOz15gdP4dpz2A3GXwOzz9DrU4WFtlCCopaHeLp8hg928NB0pJI8Yd01pFTeWTJ5pq0DsZ8oYVc3t0K67cmJws+no2auBh4+DpBPiT6sDkqmWGYUwF9dFATPx4c1GXOEg1c6FcJiuevcP3yJyRzbaRJYZiH6A8v0O2foUW+7A3O0emewu+dkf5cZEDfXfKxVuqKqSqPakdAYw37SPikap5c2SL/LFYvxVeToyfiz6PZDY6XL2j+WvzKuuH4iog9ECAOTqnSDwBVIuU36RbShYA2WskXChXlRHNjUmNDm3AemMf/B9SJmFxvjPD7mzVWPQJOWNCJBkbjUETVfPEl00LdCINEeccgoUhQinSj23kf41YXjxIm2p01rq5/wOXV9zi/fEs0WsJxFyTBmKWo7gPtABrmBO3BGZQ8BSVjoVztU4aMiVtE3tqA8rRH/rkXplQUIAougGWiSbnWE78pZE6ZNjEof9xPq1CYMg/pxYeV+oDoMRdATniH0ovpYphHaFjTHWFKMVWG48eSKfwPC8/LFHGJsm6OiWtr5IlPfILdnIuvdArKPiDr2AUjBqS00zfB4/8rtcE9bbKFNpWvAJBTi9OJ04sjGpXQT9Gytu/LmEY+K264x5tqVLKq9ZGkX4bAmXthmRLuSY47Dx62BeTiysKnGI0JJpPHGFKKeZ0VptNrMvGS/HYpZrOvggMD4Sxh01mfooofAQyCki8NoDtL6M0V9ZlD1GluExdb3lIAAhr1I9ITvUZ6oU0ImCeTM8TDqWVi5VBvsXQsbQPrZgOmZhDpjY8Ses+HHeQoyqWChb/uTPzzq4d//3iKv39b4L9fLPy8sPBl3JIDP8S/LbFDQL5hLmvhdujgx5mLu+MO7uYe3s0cTJ0W4ilLypvyEdkxOYgyVd4CtwTyiT5DrjyWed2cC5U4Qz4fcMPDdLqBDLXTbIZNNGWeIsowVcoUhKjPHky9fUCFNiaJV4k0C23mYkBrbgUMGJSv3ZtFSR8AbojNYOXBNVonb9A5ewvv9A2M49fQ/XNpoTZ1RJfy3G0vRTjnuUtyF2Q+Rkz2t9UmT08SfXwDc3IDZ/oc1eE1VGse5CyVOtuZSr5zf5axGeS0Rin8QFBs1Lnr0SOoRiWtxI8lehjpOtVGeig9ck8R17pIxGvbthDmdTbn7vlwA2hQS+BbuO05GlSJdFo7zSmaziES/iVSlQEU6iH7EQ578w4gf6jTbUzrkHrLUMAZ1GiMhTapgyqBNR6kDDe1927ICgZwW3MCncAiYJP85jSPUCy2Ed809KipYVXnXH7AZIdu0pJamKcayX7hRh7WR+kr5PyStIle0HYJqKj5Ukd5vUMbBuSWKZtIonNVXrO97ZqFAZguKu3nC9wDhvUwbW7NCE2RubKrjxbc996H0YqtfCL5P0fo5TCmt8vFJvXMD+bp50pMo9c79+Ywl3fqW6SKBNHVPyn/A3lb3I+hTik1AAAAAElFTkSuQmCC'); background-size: cover; display: block;\"></span>\n  <img class=\"gatsby-resp-image-image\" alt=\"Deploy\" title=\"Deploy\" src=\"/static/343cc66c27641d6a09263cfdd89f96c6/50383/img2.png\" srcset=\"/static/343cc66c27641d6a09263cfdd89f96c6/a6d36/img2.png 650w,\n/static/343cc66c27641d6a09263cfdd89f96c6/50383/img2.png 740w\" sizes=\"(max-width: 740px) 100vw, 740px\" style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\" loading=\"lazy\">\n    </span>\n<p><strong>🎉 Congratulations, your smart contract has been deployed. 🎉</strong></p>\n<h3 id=\"sample-transactions\" style=\"position:relative;\"><a href=\"#sample-transactions\" aria-label=\"sample transactions permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Sample Transactions</h3>\n<p>Remember that whenever a transaction is getting executed, it stores all the details in a unique <code>hash</code> key.</p>\n<p>Now, under <code>Deployed Contract</code> click on <code>> HOSTEL AT ..... (MEMORY)</code></p>\n<ol>\n<li>Click on the <code>V</code> icon (dropdown menu) of <code>addRoom</code> function.</li>\n<li>Fill up the details.</li>\n</ol>\n<p>Similar to as follows:</p>\n<span class=\"gatsby-resp-image-wrapper\" style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 740px; \">\n      <span class=\"gatsby-resp-image-background-image\" style=\"padding-bottom: 101.07692307692308%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAACXBIWXMAABYlAAAWJQFJUiTwAAADY0lEQVQ4y3VUyXLiVhRlmV9I2jbGgBgkxCAkJIEECIMkkACD7XaDux3b2aSrOl1ZZFimF6nKOlVZ5r+ySS/yIyf3PoSCu53FqfvG886dXkZyr/DlxXuUWj6KBQMdM4RpTaEbPlraOYxOQGsBtPZYjHmPLc8te0rzEOVKD209QL7QQeYo/hZfvPsDp9YKxVwbk+AGo9ElxpNrdHsxzsdXCMIbuhyJNZ/2w+kGbn9J66/EXFb6cNw1cmc6MnJtAKnmoUKvnOUNHB038eKogeOTJqGFI7K8dpJtifl+/SSrpWMm4jHfzzS1MXpOhLLsigW3v8DEf4nB8CLBSiiuqQOckgd85jnUmxOy5LLaHEHv+KgqREgxqJL8Wn0o3KgmkGt9SOUuCkUTBcl6iqKFItlSxRH3M2rDQ1kdI1vsoVJ10GgH0K0IbXOGFgXasGPoNNYMSlZvgQ7NLWcJi8a1xojGK9qPUdcmRGwjU1RG+O56ivXQwXHehqIOSaEHhaF6kGnOY2HVp7ZC6pX6iDwYokpgDzJFeYhF30XQdZAt2HTIRZ7cyNNrUrknYvt/qMj93Zg8Y5tnwj4F/u37X5CTHBRLllATzLbwww3MbkwH++Iiq0mxJyKUiExtjsU9UYf15jlsqreK7Igg88bAW6PnLqHpPiQqp517A4EqgV08DIlKHGwFIQdWpk2pwgptoaBAttY4R7uzS0bHijGLv0Y0v8c0uqPHKBG0Z5iRACctVchl8+f3C7wOhniRs8CFzqRVsvwq26bmE2mUEnD2GZoepkgV8oXAHcFouSIRTMaquWy4RFghk0yjNwhnO/jh7U4ZqdwjVajRJ+D51yiUHUiJy6KYE3U8b1CNmUTOD7D7jLYxFY99ppADzFXOqd/HkLPHZPuCZssxnC8fECeYXzyKuWnPnyrkXp4ElyL9h4RcGocKjSSGHEvzADo/SPivbFr059GfVjrIsogbuWd252kM48U9lqtvEJGdRA+YxI9kH1E35lC0meiUNCnSJy7vUVUGSXt5Sa159PNc4afHe/x4tyFs8QPZnx/ewKMGyeb4P0x6svyMy5+2V0nxsL28w18fRvj4q4d/fr/Bx98C/P3BwevVK3yVbT9P+FmrJZnnrtE7IW7XW2yWL7G9uBH2dr2BTW16embgX2/7nJYLqmA7AAAAAElFTkSuQmCC'); background-size: cover; display: block;\"></span>\n  <img class=\"gatsby-resp-image-image\" alt=\"AddRoom\" title=\"AddRoom\" src=\"/static/3bc47cb07ed572c00dd0e0588f8fccea/50383/img3.png\" srcset=\"/static/3bc47cb07ed572c00dd0e0588f8fccea/a6d36/img3.png 650w,\n/static/3bc47cb07ed572c00dd0e0588f8fccea/50383/img3.png 740w\" sizes=\"(max-width: 740px) 100vw, 740px\" style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\" loading=\"lazy\">\n    </span>\n<blockquote>\n<p><strong>Note:</strong> You're entering your details in <code>wei</code> not in <code>ether</code> (1 ether = 1000000000000000000 wei)</p>\n</blockquote>\n<ol start=\"3\">\n<li>\n<p>Then click on <code>transact</code></p>\n<p><strong>🎉 Congratulations, you've successfully added your 1st room in the contract. 🎉</strong></p>\n<p>(You can find the same in the terminal also.)</p>\n<p>Now the landlord of the room is your 1st Ether Address. (The one with 99.99 test ether in wallet.)</p>\n</li>\n<li>Change the <code>Account Address</code> from the dropdown menu. (Choose anyone except the one with 99.99 ether)</li>\n</ol>\n<span class=\"gatsby-resp-image-wrapper\" style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 740px; \">\n      <span class=\"gatsby-resp-image-background-image\" style=\"padding-bottom: 116.15384615384616%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAXCAYAAAALHW+jAAAACXBIWXMAABYlAAAWJQFJUiTwAAAEb0lEQVQ4y22UyXIbVRSGteIJGKoSx7asoTXYltSt1mSp1fPcmiVbNo4pKCjA4DDELFjwBkAVC0IoA96wg0rgBX/OuZKcuIrFX32Hvl+f859zO5XvTfFgcAlJdpHLNqA2PDSbPup1BzXZQl11xZqs2FBp3OA9evJes+XT3EOheET7LrK5JlIPk0u88eQZdjoT5NIK/PAUtjOH6x2jpw3guAsEtHbUTeDRWhAuEcVn0I0xouhM7JX3++jrc6T3VKRKBzpyFQvFUhd7mQa2d2ShnV2FVKexIsTz1VheS8Gj7RpJFiBe4/OpquLQ1yMUyhoy2SZqFHpVdiDXPaFsroXtbfkOvpuui4OvpArgRqnDmoUGeVHa18QCQyznBKa1gG7OYdrHND+mFGdiva9P6aMeFNUX7zZaMfYPDOSlIxFQ6qBKkwMLu1JPfE1tRgiic/LynPw5h+0u4fpnYh7Gj+F4S4IF4j1+drpjHJJld0CGXc4jjPoaHuw0kKMUeYPTyWRb2NtriDTTaXX1pCzYhiy9I57r93ldeJgtGRjrXUS9HrbSTVTIw1ojQLliQu2MkCtp2GYowXfoyeNHBGdtka9bXBguEheNlNL0MT6++g67+S6kfAOtugZbD+HbA7SUPjyLWseIYPVDRN4YSTBB7E+QCI0RuwN4egCr60Bvm0hVZBu9/oja5gjZYh+V5fdwPrtB8tUteh/+jPjLP2B/+ivcy+cYfH0L/+p3eFe/4eij52h+8AvpGeTzn1A9/ZHO/sBFMSFRlXJSBxlKf+/iTxjX/yD49l80Pv8L1vVL6E9fov3kbxhPX8C8fgH7mxfYOr3Fm7MbvEV6e36Dd9YSbXPzxRBnnoGHO3XUq1347gxhcIx+L4LnTOHYE5j6ABGtWcYItjXGfrEJKSOjkFVI8lo1pIp0UyLdIr+oD6ltatRGcXyK6eQCJh3mcULy3Dl8b47AX9B8if1yV9x99j3/mlKK6sH0FsgU+AUV1UofPh0KwxO0qeE9gsTREpY5huvMBNS2JigVO8jnGNi8U56UKh8akEo9FEjZNTAiAEfCkNn0PTFmWEApsxVaL0ZBar3Sa1C6yzbdhqmAMrByqAmgRz726W/DERnkH4M42iQ5o/VEHC4W2kIbsERKValtWp0QUrF7B+SUGKbRwRVwCIP8ZE9XH0pQLnUEREAFsCkiXf2+yD9OOZOpE7BPKR6LFDm10fBdURDXnorIOVLeYw9FZIUVTMq3Vimzh0X6Qa5SrqN22EPgUdv4c2jdEMPklKKcicjYS24hyxyJCCWOSlqBJOl/gHkCqpUuRtEC0+ESWtvBMKSKe9SL1HuhvyqKTVBOlQEb7zbFWQO1VaVzCnpyG/NojJPBDJHhYxpRqs4QcTBDHB6vmpy8LFPKG+C9Km+Aefqr7Odq8BQF53GMi0GCmWni8WiCkZsgMBOKdCaAHGWp2L7fhzTm+T1gJV/BuFHBJ+MQV4shzh0N7ychLsYUrRUhptTZX+5HuWaIiyAammFr8H9dzBVIG9tfBQAAAABJRU5ErkJggg=='); background-size: cover; display: block;\"></span>\n  <img class=\"gatsby-resp-image-image\" alt=\"Change Address\" title=\"Change Address\" src=\"/static/eb47d2dd91d0b7a616503cf0fab97c17/50383/img4.png\" srcset=\"/static/eb47d2dd91d0b7a616503cf0fab97c17/a6d36/img4.png 650w,\n/static/eb47d2dd91d0b7a616503cf0fab97c17/50383/img4.png 740w\" sizes=\"(max-width: 740px) 100vw, 740px\" style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\" loading=\"lazy\">\n    </span>\n<ol start=\"5\">\n<li>Add the total amount you have previously chosen as (rent cost + security deposit)</li>\n<li>And then from the dropdown <code>wei</code>, choose <code>ether</code></li>\n</ol>\n<span class=\"gatsby-resp-image-wrapper\" style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 740px; \">\n      <span class=\"gatsby-resp-image-background-image\" style=\"padding-bottom: 118.92307692307693%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAYCAYAAAD6S912AAAACXBIWXMAABYlAAAWJQFJUiTwAAAD80lEQVQ4y3VU2Y7jVBDNC9/Aosnizp44jpM4duI4sbN2Oquz9TTdUU/PDCAWoUEg8YCExBOMNE888zH8BRKCfzlUVex0Mi0eSnV9fe+pqnOqbiRvL6H09yiUu8hkGtDKHsp6FyXNhVrqkPcCc8Vr5cd/ZVrz2WzOln9puh/5cPMDPvj+DyTMBTLJOparB0ymt5jO9uj21rS+w2J5D9dbyR6vff8Bg8EOS/8FVnReLXnoD26RTFmI5KojKASWK3agXNQRTxiIxatIKAata7J3kTTlm9fhd7g+/c8+olf6sMwhsnlHIujVAfTKAJXaiGwoe9FYRcA5EHu+HAY4DcQWqRhD2O0ZcoW2RGCgVtuH7SzRbC3EGvYcdWty9JreJ+4G4nWqsFB0kUo3DiWrWhepQhfJLAFSBJvAVpvP4a8/E5stXmLhvyZuX2O9/YK+Hwh0CqtJ4I0pHHdDSVxShW0Bjaj6EPf+HI7hIKaYpFSTIjXkZypN6/Rhzfv8zT6TayGTtQNryf6x5ETWxZeTJjbdNj5JWFRKD2XiME8i1eoTORyN6ojFqsRlVfg85ZJ9uBZRvN4GN/ffIZ6yKTOTQK7g9XboeBvh0e2SJx6dji/G+8wrn1NL3IMOBXdJg0OXRBqtOTbbV8iRyrzBxC/8V8LdeLIX3qbzB8yWL4U/5vXyak/BViIIA2lEm0YicZaRvOriY4Wyy7VFpYLqiuJ5jnjSfwklsKDvQlXDFjqWXDdHePfVCpetDqKKhar038G4Nxk8RwqKLxyCvt/UoSkXBFhUO3iz7mNoe3gWr6PjrvHp/ls8v/0Gu5uvia8l0bA4Git7CsQgXIkSAtbMMZpEvJI5TApzUauPUTPGkmWp3CPrH41LPc3qSYZahbu9fyyHAbjZw5Y45Sjkk9uHWycsO9wXDnl8rOYE2WD0eAq4LaqUIWfKPlzzRLBovcE12kQNf7PxHc5eVK5bY/SHa+p+RwAZzHZ86TM+eDQas5p5Re9eF5PZC7pzI2cMc0J3fGkhASyo9DDmnOPjkKLRSgdjlUo3nhifiQclMkWhPapMEbkXswGHenUoo8fGM/34dIVvI10WAOuJIMJhkV7bfNDMfKFmXBJHO3qh1zRycwxGz2kUtzSCW+FSJdG04OliY+64XBZTRu8MkCIU9RGa7k6sXCeBOlu0va2AVimYqvWOQCXxPegkDAc5A+SSU/Q4OLoJVzfQLunoaFV4tC5lDUTjRlCe9V7/nX8LILdCmsarnDfx5xsTf//i4p/f7/DXrzP8+7OFH2cWPoqRYMn62didWyhKkGGGAPMZEz8tTLy9buDtXR+/3bh4d21hZZt4ljCR/J8JORXmP+0uC5Xy+qz1AAAAAElFTkSuQmCC'); background-size: cover; display: block;\"></span>\n  <img class=\"gatsby-resp-image-image\" alt=\"Change Value\" title=\"Change Value\" src=\"/static/d5fd5d1f68f4e5d37d78edf675a163a2/50383/img5.png\" srcset=\"/static/d5fd5d1f68f4e5d37d78edf675a163a2/a6d36/img5.png 650w,\n/static/d5fd5d1f68f4e5d37d78edf675a163a2/50383/img5.png 740w\" sizes=\"(max-width: 740px) 100vw, 740px\" style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\" loading=\"lazy\">\n    </span>\n<ol start=\"7\">\n<li>\n<p>Scroll down and click on <code>signAgreement</code>, enter <code>1</code>, and press <code>signAgreement</code></p>\n<p>You can check the same by entering <code>RoomAgreementNo</code> : <code>1</code></p>\n</li>\n</ol>\n<span class=\"gatsby-resp-image-wrapper\" style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 740px; \">\n      <span class=\"gatsby-resp-image-background-image\" style=\"padding-bottom: 194.3076923076923%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAnCAYAAAAPZ2gOAAAACXBIWXMAABYlAAAWJQFJUiTwAAAE70lEQVRIx41WyW7bVhT1ph9RIEVia54siRI1kiKp0ZYlW0o8JY4TI01XATqiaIN21UXRrtoCXfZfT+955KVpm0GyuLhv4Dvvjudxp9w/xu70GuX6GPl8D/uNAI3mGLW6j+q+h/16IOKjZsY+6rJf25e9mmfGlEJxIGsBcnJ+5/Ptt/js+//wuL9FbreF1eoKi/k5Dg8uMHKPcbA4x3r9EiPvBMujF1gfX+P45BXGk1OjKZWqJ/NL7GU62Ck259jtHKNYdpHJ9VC0DlC2l7GU7CPkqwHyhYHIEDnRheIwHpt1mefy/RCw0Zyg152bjwq1AM5Xv+Hp+3+x+uEvbH/6BwvR7aO3cIbH6PTXIit0epHIuCtrdvcIjdbCGLTTaM0wcFcoiYW5ooOmf4729Aq9xSv0D1/Dnr1Exz9Dw5qhKnFOk4rEr1gZhYA1CXq2EmCv4Ir5fQNcl48sAbDkMnrQbM3jQx+SksTRAJbrU9xs1wi6Lp5kB+Zg3Zqj3TuCLS61xR0Kx5Z9YA4XSm4MkhQD+KTo42bex2ng4tHeQEpFSoPWyeGGWEZNaapuL8xYLX4AOPK3uP7yRzzJSeaknsq1ELDVOTSHFZDS7i6N5h5jl2qhLR+dbF5J7Bxk8+KyZJpAPEzNw93B2uhWZ2kyS1Cu8WKWjIYga2IoFj3KDJExSaGFQewyQeg2hWu8gGNeRgkvOTRjWpzJCqDVnuHvd1uceB6+yPRNDPeb09hdBao1pF6dE/RF9DJKMgQGsCy+v12NMRl4eJwloPRucxbfTIt0bIraZH4Jm1Ugwjl1DNjqLOBMzrCXdyKXfWONuklNCzkejrbouxvUm7M7+9QMVVTYZJbA9HIuH9ZhaNVtAjRe1D1pQYJyni85ck7qUs6WKl6YlLp0gjNam8VcZGHSKs00reZeUlLLpmXP4Y835jYFVCAVKypkXmo6JdK0qlz17wISgKRw6/LYALL1CES3GbuBuDkKTuFPz+H4z8ycrjPrrEleaAA5IHox4XKYlLBUGDcCDL2nBpjaFWA3eGayW2tMTYh47iFglBS6yVsH7glcAfMm5/AnoWWj8SmC6QUmixcIZhdmLdVCTUpBssYQZAS8KDGqRUV+v0zISGqZyba2XmyhLGYFyLn8DuM3v2Ly5hcEN+8xvP4ZlhCuHXWF1b4rLTtcZ3dl0gC91++x+uZPrL/+w8js3e9oH9ygF3UG6f6+EJTdlZqUkpRBTTabvLmzNMnR1tICvl9/XHvociLLyoftBCdS061k3RlwFa3DNEAe1FZTVlEqC78dpVqa+ZiF2naWfRiTrrIOLy1I3D8ZMH4/Es+AzhnXW5bxPw7YsOYxeRoCjSxTtlZSZXvy+ztscx+Qb4oepGtqIdeUXNkZKobOpJ/ZpplsN91ClghjROGH9eivQRmba7qvkt7LhdteNv8t0WunY2WdsM83RnTtkyykZWohNQtcn8/7vybpSUmwjdZh8gnQZBCUtJX655Be2GEd2hHJJoE1GZwrc5tCryazXHnYKfomh66HVKVhUDqrCrtrSNiSH0yKeQLEGpbDeHaJqZDpeP5c6F9+k8dnmMiYMj24MnN+GxOs1Z7j8OgiJlhu8FYtarrNWqN0Bqs4MfqWmB6POibKMl2cpLrMkqCFnljhCfW78qfmjDZwvI3Mn5l5p7c073qp4mB3r43/Ac0kC8Qp6J4RAAAAAElFTkSuQmCC'); background-size: cover; display: block;\"></span>\n  <img class=\"gatsby-resp-image-image\" alt=\"Agreement Details\" title=\"Agreement Details\" src=\"/static/2e78f99488e2d4b996bf69e041b3f2a9/50383/img6.png\" srcset=\"/static/2e78f99488e2d4b996bf69e041b3f2a9/a6d36/img6.png 650w,\n/static/2e78f99488e2d4b996bf69e041b3f2a9/50383/img6.png 740w\" sizes=\"(max-width: 740px) 100vw, 740px\" style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\" loading=\"lazy\">\n    </span>\n<p><strong>🎉 Congratulations, you've successfully signed your 1st agreement. 🎉</strong></p>\n<p>All your transactions are shown in the <code>terminal</code>.</p>\n<span class=\"gatsby-resp-image-wrapper\" style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 768px; \">\n      <span class=\"gatsby-resp-image-background-image\" style=\"padding-bottom: 52.307692307692314%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAYAAAC0VX7mAAAACXBIWXMAABYlAAAWJQFJUiTwAAABTUlEQVQoz41Su3LCMBD0lwTrYVt+AZMBDMZgEXcU1GnSpcr/95e9sxUzCZmh2DnpJO2t9i5y+YnyAijPVNaeUnckhz2vy7qf4JHryKaHh0g46i3ZZE+RyVvKcNm5jjKQ8aGxzR/w5REgAGRt96RBpMyO9OZKOjuCsGjJuqkKLiVSsRWk2RzH9eFu3Yo6IcS7xfBBqvQUcZUMzHzJ5aNKVqT0Btg+BSF9WZNSGyhcdlSsPa1WA5UV/Ko8SDshDwUyF2IofJK1ROwtYnz7Ir0cWGHz40kyGczf4cqx+k/lg3z8KlE8dBU6XPbo9lnAyu59G/0N3h7mPEcIMbAs9u+kix4KQZhjNKr6It8tMD6z0rlZv39wf2aw182NNKyJjMFI8GhMD1iJxhg825CARXrE+DQgtDshCqaHZswNGRsRGhVyIZ/irYIIdf0kXb/RN+QnL80nDgFfAAAAAElFTkSuQmCC'); background-size: cover; display: block;\"></span>\n  <img class=\"gatsby-resp-image-image\" alt=\"Terminal\" title=\"Terminal\" src=\"/static/7ebf72a72c72bbb334e0d52d8ce3cbf8/e5715/img7.png\" srcset=\"/static/7ebf72a72c72bbb334e0d52d8ce3cbf8/a6d36/img7.png 650w,\n/static/7ebf72a72c72bbb334e0d52d8ce3cbf8/e5715/img7.png 768w,\n/static/7ebf72a72c72bbb334e0d52d8ce3cbf8/c27e7/img7.png 2144w\" sizes=\"(max-width: 768px) 100vw, 768px\" style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\" loading=\"lazy\">\n    </span>\n<p>Now, you can cross verify this by checking your <code>ether</code> account address.</p>\n<h2 id=\"advantages-of-smart-contracts\" style=\"position:relative;\"><a href=\"#advantages-of-smart-contracts\" aria-label=\"advantages of smart contracts permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Advantages of Smart Contracts</h2>\n<p>Now you may ask, \"what's the use of smart contracts when there are several centralized methods?\"</p>\n<p>Let me explain some advantages of smart contracts over centralized systems:</p>\n<ol>\n<li>Here data cannot be changed or tampered with. So, it is almost impossible for malicious actors to manipulate data.</li>\n<li>It's completely decentralized.</li>\n<li>Unlike any centralized payment wallet, you don't have to pay any commission percentages to a middle man to transact.</li>\n</ol>\n<h3 id=\"storage--others\" style=\"position:relative;\"><a href=\"#storage--others\" aria-label=\"storage  others permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Storage &#x26; Others</h3>\n<p>You may also ask \"how are all the transactions recorded?\"</p>\n<p>You have to remember that smart contracts store data in a block of the blockchain, and all transactions are stored with a unique <code>hash</code> key.</p>\n<p>In Remix IDE, you can download the complete transactions history as a JSON file. For that, follow these steps:</p>\n<ol>\n<li>Click <code>Deploy &#x26; Run Transaction</code></li>\n<li>Then, expand the <code>Transactions Recorded (..) V</code> dropdown menu.</li>\n<li>Then Click on the <code>Save</code> icon.</li>\n<li>Press <code>ok</code>.</li>\n</ol>\n<h3 id=\"gas-fee\" style=\"position:relative;\"><a href=\"#gas-fee\" aria-label=\"gas fee permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Gas Fee</h3>\n<p>You may have noticed that whenever a transaction is executed, a few <code>wei</code> is getting deducted from your ether wallet.</p>\n<p>It's called <em>gas fee</em>, which is the payment made by users to compensate for the computing energy required to process and validate transactions.</p>\n<p>As more Ethereum miners come up in near future, the <code>gas fee</code> will decrease in an inverse relation.</p>\n<h3 id=\"future-possibilities\" style=\"position:relative;\"><a href=\"#future-possibilities\" aria-label=\"future possibilities permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Future Possibilities</h3>\n<p>After this, if you want to build a fullstack website using React, you can use this smart contract as a backend.</p>\n<p>For that you need to install/download: </p>\n<p><strong>Frontend:</strong></p>\n<ol>\n<li><a href=\"https://nodejs.org/en/\">Node.js</a></li>\n</ol>\n<p><strong>Backend:</strong></p>\n<ol>\n<li><a href=\"https://www.npmjs.com/package/web3\">web3.js</a></li>\n<li><a href=\"https://www.trufflesuite.com/docs/truffle/getting-started/installation\">Truffle</a></li>\n</ol>\n<p><strong>Testing:</strong></p>\n<ol>\n<li><a href=\"https://www.trufflesuite.com/ganache\">Ganache</a></li>\n<li><a href=\"https://metamask.io/\">Metamask</a></li>\n</ol>\n<p>Just follow the <a href=\"https://web3js.readthedocs.io/en/v1.5.2/\">official documentation</a> of Web3.js to connect your smart contract with your React app.</p>\n<h2 id=\"conclusion\" style=\"position:relative;\"><a href=\"#conclusion\" aria-label=\"conclusion permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Conclusion</h2>\n<p>You've successfully understood what Solidity is and how smart contracts work. And you've successfully built and deployed a perfectly working smart contract (where a tenant can pay rent in ether (ETH) directly to the landlord's wallet without paying a single wei to a middle man).</p>\n<p>To download the complete code used in this tutorial, click <a href=\"https://github.com/LoginRadius/engineering-blog-samples/tree/master/Solidity/decentralised-pg-booking-system-using-ethereum-smart-contract\">here</a>.</p>\n<p>Want to quickly add user login and signup functionality to your React apps? <a href=\"https://www.loginradius.com/authentication/\">Use LoginRadius for free.</a></p>\n<style class=\"grvsc-styles\">\n  .grvsc-container {\n    overflow: auto;\n    -webkit-overflow-scrolling: touch;\n    padding-top: 1rem;\n    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));\n    padding-bottom: 1rem;\n    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));\n    border-radius: 8px;\n    border-radius: var(--grvsc-border-radius, 8px);\n    font-feature-settings: normal;\n  }\n  \n  .grvsc-code {\n    display: inline-block;\n    min-width: 100%;\n  }\n  \n  .grvsc-line {\n    display: inline-block;\n    box-sizing: border-box;\n    width: 100%;\n    padding-left: 1.5rem;\n    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));\n    padding-right: 1.5rem;\n    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));\n  }\n  \n  .grvsc-line-highlighted {\n    background-color: var(--grvsc-line-highlighted-background-color, transparent);\n    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, transparent);\n  }\n  \n  .dark-default-dark {\n    background-color: #1E1E1E;\n    color: #D4D4D4;\n  }\n  .dark-default-dark .mtk1 { color: #D4D4D4; }\n  .dark-default-dark .mtk7 { color: #B5CEA8; }\n  .dark-default-dark .mtk12 { color: #9CDCFE; }\n  .dark-default-dark .mtk4 { color: #569CD6; }\n  .dark-default-dark .mtk10 { color: #4EC9B0; }\n  .dark-default-dark .mtk8 { color: #CE9178; }\n</style>","frontmatter":{"date":"November 24, 2021","updated_date":null,"description":"Smart contracts are an exciting way to build decentralized applications (dapps) on a blockchain. This tutorial helps you learn and build your first smart contract using Solidity on Ethereum blockchain.","title":"Build Your First Smart Contract with Ethereum & Solidity","tags":["Blockchain","Ethereum","Solidity"],"pinned":null,"coverImage":{"childImageSharp":{"fluid":{"aspectRatio":1.5037593984962405,"src":"/static/32b53a158fcbe237c5223007d8b14857/ee604/coverimage.png","srcSet":"/static/32b53a158fcbe237c5223007d8b14857/69585/coverimage.png 200w,\n/static/32b53a158fcbe237c5223007d8b14857/497c6/coverimage.png 400w,\n/static/32b53a158fcbe237c5223007d8b14857/ee604/coverimage.png 800w,\n/static/32b53a158fcbe237c5223007d8b14857/f3583/coverimage.png 1200w","sizes":"(max-width: 800px) 100vw, 800px"}}},"author":{"id":"Aritra Belel","github":"belelaritra","avatar":null}}}},{"node":{"excerpt":"JSON (JavaScript Object Notation) is a text-based, language-independent format that is easily understandable by humans and machines. JOSE…","fields":{"slug":"/engineering/guest-post/what-are-jwt-jws-jwe-jwk-jwa/"},"html":"<p>JSON (JavaScript Object Notation) is a text-based, language-independent format that is easily understandable by humans and machines.</p>\n<p>JOSE (Javascript Object Signing and Encryption) is a framework used to facilitate the secure transfer of claims between any two parties. Its specifications provide a general approach to encryption of any content, not necessarily in JSON. However, it is built on JSON for easy use in web applications. Let's explore some of these specifications.</p>\n<h2 id=\"jwt--json-web-token\" style=\"position:relative;\"><a href=\"#jwt--json-web-token\" aria-label=\"jwt  json web token permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>JWT — JSON Web Token</h2>\n<p><a href=\"https://www.loginradius.com/blog/engineering/guest-post/jwt-authentication-best-practices-and-when-to-use/\">JWT</a> is a standard mechanism used for authentication. It is compact and URL-safe to represent the claims to be transferred between two parties. Claims are a set of key/value pairs that provide a target system with information about a client to apply an appropriate level of access control to its resources. Claim names could be Registered (IANA), Public, or Private. Some registered claim names are:</p>\n<ul>\n<li>\"iss\": Issuer claim — identifies the issuer of the claim</li>\n<li>\"sub\": Subject claim — identifying the subject of a claim</li>\n<li>\"jti\": JWT ID — Uniquely identify a claim</li>\n</ul>\n<h3 id=\"structure\" style=\"position:relative;\"><a href=\"#structure\" aria-label=\"structure permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Structure</h3>\n<p>JWT is mainly composed of three parts: header, payload, and signature that are Base64 URL-encoded.</p>\n<ul>\n<li>The header is used to identify the algorithm used to generate a signature.</li>\n<li>The payload consists of the claims and signature (secret key) used to validate the token.</li>\n<li>The structure of sending the information could be Serialized or Deserialized. In the Serialized form, JWT is represented as a string containing the header, payload, and signature separated by dots.</li>\n</ul>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"\" data-index=\"0\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">[header].[payload].[signature]</span></code></pre>\n<p>Here's a simple JWT example.</p>\n<p>JSON Web Token:</p>\n<p><code>eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MTIzNDU2Nzg5LCJuYW1lIjoiSm9zZXBoIn0.OpOSSw7e485LOP5PrzScxHb7SR6sAOMRckfFwi4rp7o</code></p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"\" data-index=\"1\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">header:</span>\n<span class=\"grvsc-line\">{</span>\n<span class=\"grvsc-line\">  &quot;alg&quot; : &quot;HS256&quot;,                      Header</span>\n<span class=\"grvsc-line\">                            ---------------------------------&gt;  eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9</span>\n<span class=\"grvsc-line\">  &quot;typ&quot; : &quot;JWT&quot;</span>\n<span class=\"grvsc-line\">}</span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\">Payload:</span>\n<span class=\"grvsc-line\">{</span>\n<span class=\"grvsc-line\">  &quot;id&quot; : 123456789,                     Payload</span>\n<span class=\"grvsc-line\">                            ---------------------------------&gt;  eyJpZCI6MTIzNDU2Nzg5LCJuYW1lIjoiSm9zZXBoIn0</span>\n<span class=\"grvsc-line\">  &quot;name&quot; : &quot;Joseph&quot;</span>\n<span class=\"grvsc-line\">}</span>\n<span class=\"grvsc-line\">                                                Signature</span>\n<span class=\"grvsc-line\">OpOSSw7e485LOP5PrzScxHb7SR6sAOMRckfFwi4rp7o  ----------------&gt;  OpOSSw7e485LOP5PrzScxHb7SR6sAOMRckfFwi4rp7o</span></code></pre>\n<p>This shows the decoded JSON Web Token. In the deserialized form, JWT contains only the header and the payload as plain JSON objects.</p>\n<p>JWT is implemented using JWS or JWE. Learn more about JWT <a href=\"https://jwt.io/\">here</a></p>\n<h2 id=\"jws--json-web-signature\" style=\"position:relative;\"><a href=\"#jws--json-web-signature\" aria-label=\"jws  json web signature permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>JWS — JSON Web Signature</h2>\n<p>JWS is used to represent content secured with digital signatures or Hash-based Message Authentication Codes (HMACs) with the help of JSON data structures. It cryptographically secures a JWS Header and JWS Payload with a JWS Signature. The encoded strings of these three are concatenated using dots similar to JWT. The identifiers and algorithms used are specified in the JSON Web Algorithms specification.</p>\n<p>The JWS Header MUST contain an alg parameter, as it uses the algorithm to encode the JWS Header and the JWS Payload to produce the JWS Signature. Some of the commonly used algorithms to sign the JWS Header and Payload are:</p>\n<ul>\n<li>HMAC using SHA-256 or SHA-512 hash algorithms (HS256, HS512)</li>\n<li>RSA using SHA-256 or SHA-512 hash algorithms (RS256, RS512)</li>\n</ul>\n<p>JWS example:</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"\" data-index=\"2\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9 ----------------&gt; JWS Header</span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\">eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ --------------&gt; JWS Payload</span></code></pre>\n<p>It has an Encoded JWS Header followed by an Encoded JWS Payload separated by a '.'. This is the JWS Signing input which, on signing with the HMAC SHA-256 algorithm and base64url encoding, gives the Encoded JWS Signature value:</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"\" data-index=\"3\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk</span></code></pre>\n<p>On concatenation:</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"\" data-index=\"4\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">eyJ0eXAiOiJKV1QiLA0KICJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJqb2UiLA0KICJleHAiOjEzMDA4MTkzODAsDQogImh0dHA6Ly9leGFtcGxlLmNvbS9pc19yb290Ijp0cnVlfQ.dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk</span></code></pre>\n<p>Learn more about JWS <a href=\"https://openid.net/specs/draft-jones-json-web-signature-04.html\">here</a></p>\n<h2 id=\"jwe--json-web-encryption\" style=\"position:relative;\"><a href=\"#jwe--json-web-encryption\" aria-label=\"jwe  json web encryption permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>JWE — JSON Web Encryption</h2>\n<p>JSON Web Encryption enables encrypting a token so that only the intended recipient can read it. It standardizes the way to represent the encoded data in a JSON data structure. Representation of the encrypted payload may be by JWE compact serialization or JWE JSON serialization.</p>\n<h3 id=\"structure-1\" style=\"position:relative;\"><a href=\"#structure-1\" aria-label=\"structure 1 permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Structure</h3>\n<p>The JWE compact serialization form has five main components:</p>\n<ol>\n<li>JOSE header</li>\n<li>JWE Encrypted Key</li>\n<li>JWE initialization vector</li>\n<li>JWE Ciphertext</li>\n<li>JWE Authentication Tag</li>\n</ol>\n<p>All these components are base64url-encoded and are concatenated using dots (<code>.</code>).</p>\n<ul>\n<li>\n<p>The JOSE Header, the first element of the token, is the same as the headers of the previously mentioned JWT and JWS.</p>\n<p>JWE has additional elements to the Header — <code>enc</code> and <code>zip</code>.</p>\n<p><code>enc</code> defines the <em>content encryption algorithm</em> while the <code>alg</code> element defines the encryption algorithm for the <em>Content Encryption Key (CEK)</em>.</p>\n<p><code>zip</code> provides a compression algorithm if token compression is needed.</p>\n</li>\n<li>During the encryption process, the issuer generates a random key, which is 256-bits in size, that is used to encrypt the message. This is placed in the JWE Encrypted key section.</li>\n<li>Some encryption algorithms require an initialization vector, which is a randomly generated number that is used along with a secret key to encrypt data. This prevents repeated encryption of the same data using the same secret key. The recipient requires this initialization vector to decrypt the message, and hence, is placed in the JWE token.</li>\n<li>The fourth section of the token is the JWE ciphertext that is computed by encrypting the plaintext JSON payload. It uses the algorithm mentioned in the header's <code>enc</code> element.</li>\n<li>The JWE Authentication Tag is the last part of the JWE Token generated along with the ciphertext. It ensures the integrity of the ciphertext.</li>\n</ul>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"\" data-index=\"5\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"> &quot;header&quot;:</span>\n<span class=\"grvsc-line\">{</span>\n<span class=\"grvsc-line\">    &quot;alg&quot; : &quot;RSA-OAEP&quot;,                --------------------&gt; For content encryption key</span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\">    &quot;enc&quot; : &quot;A256GCM&quot;                  --------------------&gt; For content encryption algorithm</span>\n<span class=\"grvsc-line\">},</span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"> &quot;encrypted_key&quot; : &quot;qtF60gW8O8cXKiYyDsBPX8OL0GQfhOxwGWUmYtHOds7FJWTNoSFnv5E6A_Bgn_2W&quot;</span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\">&quot;iv&quot; : &quot;HRhA5nn8HLsvYf8F-BzQew&quot;,       --------------------&gt; initialization vector</span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\">&quot;ciphertext&quot; : &quot;ai5j5Kk43skqPLwR0Cu1ZIyWOTUpLFKCN5cuZzxHdp0eXQjYLGpj8jYvU8yTu9rwZQeN9EY0_81hQHXEzMQgfCsRm0HXjcEwXInywYcVLUls8Yik&quot;,</span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\">&quot;tag&quot; : &quot;thh69dp0Pz73kycQ&quot;             --------------------&gt; Authentication tag</span>\n<span class=\"grvsc-line\">}</span></code></pre>\n<p>Learn more about JWE <a href=\"https://datatracker.ietf.org/doc/html/draft-jones-json-web-encryption\">here</a></p>\n<h2 id=\"jwk--json-web-key\" style=\"position:relative;\"><a href=\"#jwk--json-web-key\" aria-label=\"jwk  json web key permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>JWK — JSON Web Key</h2>\n<p>JWK is a JSON structure representing a set of public keys as a JSON object using the Elliptic Curve or RSA algorithms. Public key representations can help verify the signature with the corresponding private key.</p>\n<h3 id=\"structure-2\" style=\"position:relative;\"><a href=\"#structure-2\" aria-label=\"structure 2 permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Structure</h3>\n<p>JWK consists of a JWK Container Object and an array of JWK Key Objects.</p>\n<ul>\n<li>The JWK Container Object is a JSON object that contains a specific member that is an array. This member is a required element in the Container Object.</li>\n<li>The JWK Key Objects are stored within the array of the JWK Container object. They have a set of members that is common to all key types. As mentioned before, JWK Key objects can use Elliptic Curve or RSA algorithms. To do so, the <code>alg</code> field must hold <code>EC</code> or <code>RSA</code>, respectively. Here is an example of a JWK using RSA:</li>\n</ul>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"\" data-index=\"6\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">{</span>\n<span class=\"grvsc-line\">&quot;alg&quot;:&quot;RSA&quot;,</span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\">&quot;mod&quot;: &quot;0vx7agoebGcQSuuPiLJXZptN9nndrQmbXEps2aiAFbWhM78LhWx4cbbfAAtVT86zwu1RK7aPFFxuhDR1L6tSoc_BJECPebWKRXjBZCiFV4n3oknjhMs</span>\n<span class=\"grvsc-line\">tn64tZ_2W-5JsGY4Hc5n9yBXArwl93lqt7_RN5w6Cf0h4QyQ5v-65YGjQR0_FDW2QvzqY368QQMicAtaSqzs8KJZgnYb9c7d0zgdAZHzu6qMQvRL5hajrn1n91CbOpbI</span>\n<span class=\"grvsc-line\">SD08qNLyrdkt-bFTWhAI4vMQFh6WeZu0fM4lFd2NcRwr3XPksINHaQ-G_xBniIqbw0Ls1jF44-csFCur-kEgU8awapJzKnqDKgw&quot;,</span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\">&quot;exp&quot;:&quot;AQAB&quot;,</span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\">&quot;kid&quot;:&quot;2011-04-29&quot;</span>\n<span class=\"grvsc-line\">}</span></code></pre>\n<p>It provides a Key ID for matching.</p>\n<h2 id=\"jwa--json-web-algorithms\" style=\"position:relative;\"><a href=\"#jwa--json-web-algorithms\" aria-label=\"jwa  json web algorithms permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>JWA — JSON Web Algorithms</h2>\n<p>The JWA specification focuses mainly on enumerating the algorithms necessary for JWS, JWK AND JWE. It also describes the operations that are specific to these algorithms and key types.</p>\n<p><strong>Algorithms for JWS:</strong> These algorithms are used to sign the contents of the JWS Header and the JWS Payload</p>\n<figure>\n  <span class=\"gatsby-resp-image-wrapper\" style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 768px; \">\n      <span class=\"gatsby-resp-image-background-image\" style=\"padding-bottom: 45.07692307692307%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAJCAIAAAC9o5sfAAAACXBIWXMAABJ0AAASdAHeZh94AAABYklEQVQoz0VRy3KEIBD0/78rl8Rbcti4iKCAiA/EFV+7YqW1tipdluVAT3fPGMVfn9/fP5zxZVmkEOkJKgpRFAWlNEnubdcex2G77uNCHMfTPL9er2maorzIe+dwjdpaCyrQddZ2tm3apmmez2fYdz95zplSJTzA3Pd9nucoJaRpT+0QdiklIYTSNGMZY4zcATIvC27hc0+SPM/RhuYQAlQiIQrnBtRwMMZIpSpjqgqPRlmW5TAMoHrvhRBQR0ww37EJwVQdtCGppEwpzbKMIyLLaMaSJDGmDgHOHkEY59u2/TvrUkP1uKDU2dw0UMPQ2JGt6xpjw2RdV63B1ba3sAH5bMYlRg8XSl0yxvveIeoDGB/OOaiAAEMsEmegofntjKPlWgmgdcV53tt+9H44cTa7wXk/YU6oQDKcq8XrQJZISYXY64bvFSu53X6xF30By0NSpdQ4+nEcc87xq9YLCIKTP+8W9OFzvfFkAAAAAElFTkSuQmCC'); background-size: cover; display: block;\"></span>\n  <img class=\"gatsby-resp-image-image\" alt=\"JWS algorithms\" title=\"JWS algorithms\" src=\"/static/59304762300dd863a8ceddb2ca893b4b/e5715/JWS_algo.png\" srcset=\"/static/59304762300dd863a8ceddb2ca893b4b/a6d36/JWS_algo.png 650w,\n/static/59304762300dd863a8ceddb2ca893b4b/e5715/JWS_algo.png 768w,\n/static/59304762300dd863a8ceddb2ca893b4b/23266/JWS_algo.png 923w\" sizes=\"(max-width: 768px) 100vw, 768px\" style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\" loading=\"lazy\">\n    </span>\n  <figcaption align=\"center\">Source: <a href=\"https://tools.ietf.org/id/draft-ietf-jose-json-web-algorithms-10.html\">ietf-jose-json-web-algorithms</a></figcaption>\n</figure>\n<p><strong>Algorithms for JWE</strong> These algorithms encrypt the Content Encryption Key (CEK) and produce the JWE Encrypted Key</p>\n<figure>\n  <span class=\"gatsby-resp-image-wrapper\" style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 768px; \">\n      <span class=\"gatsby-resp-image-background-image\" style=\"padding-bottom: 51.53846153846153%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAIAAAA7N+mxAAAACXBIWXMAABJ0AAASdAHeZh94AAABjUlEQVQoz2VR23aDIBD0/3+tfeppmmgSAshFwRvaCIJJO6SP3Yd1XXd2dsbi/e1NCBG3LXi/rityjGld9xifP/8ihMA5U1I55xhlhZRiHMfgAyGUc8FrXtea0kHU/TAMfd93HVJvrQ3Bg4IyprXGIkppMY7D/X73ayhLRYiVUmmtsLHROaRSUiCho4dh3rboJrC65/OHMVZgu/c+xUjI5Xq9YqzJOKQGIGMMSmNaaychvq39np3rus6vnnMO8HhfV2i+AEsIRtu2xa3GWCChCMfP8zxNYByheVnmaZxijJkZorZtAzk0ZDYpGeP4QK6krmvgcVqXAxaM2IIOpKHImuHwn40vCGf0hkfTGjgERGtyQIO1RimNDubnZd73PZ+N65Z5htu3Gxe1guEAwzLY1jRNtqB1UnqlBxDg2ryxbZdlycy4GcxbiB8f9PAlD1/seDx9HsrD57GqqrIqT8dTVV3O5zOlDLofjwdoAYGoIqWECu/d64eCrR+cMcm5mGLaU8L2hAqk24ax5yv+wL+X/ipQl3BZNQAAAABJRU5ErkJggg=='); background-size: cover; display: block;\"></span>\n  <img class=\"gatsby-resp-image-image\" alt=\"JWE algorithms\" title=\"JWE algorithms\" src=\"/static/41748e3c88f2a5504335f64ed916a05c/e5715/JWE_algo.png\" srcset=\"/static/41748e3c88f2a5504335f64ed916a05c/a6d36/JWE_algo.png 650w,\n/static/41748e3c88f2a5504335f64ed916a05c/e5715/JWE_algo.png 768w,\n/static/41748e3c88f2a5504335f64ed916a05c/e0885/JWE_algo.png 918w\" sizes=\"(max-width: 768px) 100vw, 768px\" style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\" loading=\"lazy\">\n    </span>\n  <figcaption align=\"center\">Source: <a href=\"https://tools.ietf.org/id/draft-ietf-jose-json-web-algorithms-10.html\">ietf-jose-json-web-algorithms</a> </figcaption>\n</figure>\n<p><strong>Algorithms for JWK:</strong> JWA specifies a set of algorithm families to be used for the public keys represented by JWK</p>\n<figure>\n  <span class=\"gatsby-resp-image-wrapper\" style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 768px; \">\n      <span class=\"gatsby-resp-image-background-image\" style=\"padding-bottom: 18.153846153846153%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAECAIAAAABPYjBAAAACXBIWXMAABJ0AAASdAHeZh94AAAAvUlEQVQI1yVO0Q6DIBDz///MBzOTzZkFJ8tkmDhAkCFygO6y9eFy6bW9Fk3TXNt2nmcpxb3rBsZyjgAbQAwBth+89zHGjpCyLKuqOp1qt64hhMIsBgByzsYYzkcplRAg5Ka1dG49jmPfd7ziMrChruvL+dxTigzyRYoJU1NKUrwpHRn7PJ/m8WCc88Va55y1dvUeBdM0EUIYe9mPxbfoKv7ZOLE5uZG+x1yqlFqw0oIwSio0owBTxA9a67/lCyFN3+7p71lbAAAAAElFTkSuQmCC'); background-size: cover; display: block;\"></span>\n  <img class=\"gatsby-resp-image-image\" alt=\"JWK algo\" title=\"JWK algo\" src=\"/static/1a4fdfb901193d11ded56baade0feaa7/e5715/JWK_algo.png\" srcset=\"/static/1a4fdfb901193d11ded56baade0feaa7/a6d36/JWK_algo.png 650w,\n/static/1a4fdfb901193d11ded56baade0feaa7/e5715/JWK_algo.png 768w,\n/static/1a4fdfb901193d11ded56baade0feaa7/6da96/JWK_algo.png 922w\" sizes=\"(max-width: 768px) 100vw, 768px\" style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\" loading=\"lazy\">\n    </span>\n  <figcaption align=\"center\">Source: <a href=\"https://tools.ietf.org/id/draft-ietf-jose-json-web-algorithms-10.html\">ietf-jose-json-web-algorithms</a> </figcaption>\n</figure>\n<p>Learn more about JWA <a href=\"https://datatracker.ietf.org/doc/html/draft-ietf-jose-json-web-algorithms-40\">here</a>.</p>\n<h2 id=\"conclusion\" style=\"position:relative;\"><a href=\"#conclusion\" aria-label=\"conclusion permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Conclusion</h2>\n<p>The IETF JSON Object Signing and Encryption (JOSE) working group was chartered to develop a secure object format based on JSON and simplify adding object-based security features to internet applications.</p>\n<p>The basic requirements for these object formats are confidentiality and integrity mechanisms encoded in JSON. JWT, JWS, JWE, JWK, and JWA are the JOSE working group items intended to describe these object formats.</p>\n<p>The JOSE specifications have many use cases and are sought out for integrity protection, encryption, security tokens, OAuth, web cryptography, etc. Check out <a href=\"https://datatracker.ietf.org/doc/rfc7165/\">this site</a> to know more about JOSE use cases.</p>\n<p>Want to learn how to use JWT for authentication in your apps? Check out this informational <a href=\"https://www.loginradius.com/blog/engineering/guest-post/jwt-authentication-best-practices-and-when-to-use/\">JWT authentication guide</a>.</p>\n<p><strong>References:</strong></p>\n<ul>\n<li><a href=\"https://tools.ietf.org/\">IETF</a></li>\n<li><a href=\"https://openid.net/\">OpenID</a></li>\n</ul>\n<style class=\"grvsc-styles\">\n  .grvsc-container {\n    overflow: auto;\n    -webkit-overflow-scrolling: touch;\n    padding-top: 1rem;\n    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));\n    padding-bottom: 1rem;\n    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));\n    border-radius: 8px;\n    border-radius: var(--grvsc-border-radius, 8px);\n    font-feature-settings: normal;\n  }\n  \n  .grvsc-code {\n    display: inline-block;\n    min-width: 100%;\n  }\n  \n  .grvsc-line {\n    display: inline-block;\n    box-sizing: border-box;\n    width: 100%;\n    padding-left: 1.5rem;\n    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));\n    padding-right: 1.5rem;\n    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));\n  }\n  \n  .grvsc-line-highlighted {\n    background-color: var(--grvsc-line-highlighted-background-color, transparent);\n    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, transparent);\n  }\n  \n  .dark-default-dark {\n    background-color: #1E1E1E;\n    color: #D4D4D4;\n  }\n</style>","frontmatter":{"date":"November 24, 2021","updated_date":null,"description":"Learn about the JOSE framework and its specifications, including JSON Web Token (JWT), JSON Web Signature (JWS), JSON Web Encryption (JWE), JSON Web Key (JWK), and JSON Web Algorithms (JWA). For easier reference, bookmark this article.","title":"What are JWT, JWS, JWE, JWK, and JWA?","tags":["JSON","Encryption"],"pinned":null,"coverImage":{"childImageSharp":{"fluid":{"aspectRatio":1.5037593984962405,"src":"/static/77dde0fdc2f90c1277d228bc32c367d2/ee604/coverImage.png","srcSet":"/static/77dde0fdc2f90c1277d228bc32c367d2/69585/coverImage.png 200w,\n/static/77dde0fdc2f90c1277d228bc32c367d2/497c6/coverImage.png 400w,\n/static/77dde0fdc2f90c1277d228bc32c367d2/ee604/coverImage.png 800w,\n/static/77dde0fdc2f90c1277d228bc32c367d2/f3583/coverImage.png 1200w","sizes":"(max-width: 800px) 100vw, 800px"}}},"author":{"id":"Yashesvinee V","github":"Yashesvinee","avatar":null}}}},{"node":{"excerpt":"In this tutorial, you'll learn how to easily convert an OpenCV project into a web app that you can showcase. You'll use a library called…","fields":{"slug":"/engineering/guest-post/opencv-web-app-with-streamlit/"},"html":"<p>In this tutorial, you'll learn how to easily convert an OpenCV project into a web app that you can showcase. You'll use a library called Streamlit, which helps you easily build a web user interface in Python. Yes, you heard it right — no HTML, CSS, or JavaScript required. Just Python!</p>\n<h2 id=\"prerequisites\" style=\"position:relative;\"><a href=\"#prerequisites\" aria-label=\"prerequisites permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Prerequisites</h2>\n<ul>\n<li>You should be comfortable using basic <a href=\"https://opencv.org/\">OpenCV</a> functions.</li>\n<li>You should be comfortable coding in Python.</li>\n</ul>\n<p>Let's get started.</p>\n<h2 id=\"install-dependencies\" style=\"position:relative;\"><a href=\"#install-dependencies\" aria-label=\"install dependencies permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Install Dependencies</h2>\n<p>Install OpenCV and Streamlit using pip. You would also need Pillow — another image library.</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"py\" data-index=\"0\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">pip install opencv-python streamlit Pillow</span></span></code></pre>\n<blockquote>\n<p>If you use Python 2.7, note that OpenCV doesn't directly support Python 2.7 in their latest versions. Accordingly, you have to specify an older version like this <code>pip install opencv-python==4.2.0.32</code></p>\n</blockquote>\n<h2 id=\"create-a-small-opencv-project\" style=\"position:relative;\"><a href=\"#create-a-small-opencv-project\" aria-label=\"create a small opencv project permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Create a Small OpenCV Project</h2>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"py\" data-index=\"1\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk15\">import</span><span class=\"mtk1\"> cv2</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">def</span><span class=\"mtk1\"> </span><span class=\"mtk11\">brighten_image</span><span class=\"mtk1\">(</span><span class=\"mtk12\">image</span><span class=\"mtk1\">, </span><span class=\"mtk12\">amount</span><span class=\"mtk1\">):</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    img_bright = cv2.convertScaleAbs(image, </span><span class=\"mtk12\">beta</span><span class=\"mtk1\">=amount)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> img_bright</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">def</span><span class=\"mtk1\"> </span><span class=\"mtk11\">blur_image</span><span class=\"mtk1\">(</span><span class=\"mtk12\">image</span><span class=\"mtk1\">, </span><span class=\"mtk12\">amount</span><span class=\"mtk1\">):</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    img = cv2.cvtColor(image, </span><span class=\"mtk7\">1</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    blur_img = cv2.GaussianBlur(img, (</span><span class=\"mtk7\">11</span><span class=\"mtk1\">, </span><span class=\"mtk7\">11</span><span class=\"mtk1\">), amount)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> blur_img</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">def</span><span class=\"mtk1\"> </span><span class=\"mtk11\">enhance_details</span><span class=\"mtk1\">(</span><span class=\"mtk12\">img</span><span class=\"mtk1\">):</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    hdr = cv2.detailEnhance(img, </span><span class=\"mtk12\">sigma_s</span><span class=\"mtk1\">=</span><span class=\"mtk7\">12</span><span class=\"mtk1\">, </span><span class=\"mtk12\">sigma_r</span><span class=\"mtk1\">=</span><span class=\"mtk7\">0.15</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> hdr</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">img = cv2.imread(</span><span class=\"mtk12\">filename</span><span class=\"mtk1\">=</span><span class=\"mtk8\">&#39;tony_stark.jpg&#39;</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk3\"># do some cool image processing stuff</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">img = enhance_details(img)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">img = brighten_image(img, </span><span class=\"mtk12\">amount</span><span class=\"mtk1\">=</span><span class=\"mtk7\">25</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">img = blur_image(img, </span><span class=\"mtk12\">amount</span><span class=\"mtk1\">=</span><span class=\"mtk7\">0.2</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">cv2.imshow(</span><span class=\"mtk8\">&#39;Tony Stark&#39;</span><span class=\"mtk1\">, img)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">cv2.waitKey(</span><span class=\"mtk7\">0</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">cv2.destroyAllWindows()</span></span></code></pre>\n<p>Here are three image processing functions that accept an image, do some processing, and return the processed image.</p>\n<ol>\n<li><code>brighten_image</code> — increases the brightness of the image.</li>\n<li><code>blur_image</code> — applies a blur effect on the image.</li>\n<li><code>enhance_details</code> — applies an effect to enhance the details of the image.</li>\n</ol>\n<p>These functions make use of the OpenCV functions to do the actual processing — for e.g.: cv2.GaussianBlur, etc. I'm not explaining in-depth about them and the various parameters they accept since this tutorial is more focused on integrating OpenCV with Streamlit. However, feel free to jump to the OpenCV documentation to know more details about them. </p>\n<p>This program reads the image from the <code>filepath</code> using <code>cv2.imread()</code>; then, it passes the image to these functions that do the processing. Finally, the image is displayed using <code>cv2.imshow()</code>. <code>cv2.waitKey(0)</code> is to wait till the user presses any key, after which the program is exited.</p>\n<h2 id=\"streamlit-basics\" style=\"position:relative;\"><a href=\"#streamlit-basics\" aria-label=\"streamlit basics permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Streamlit Basics</h2>\n<p>Streamlit offers some common UI components out of the box that you can place on your webpage. This makes it super easy to code up something real quick. The way Streamlit works is that it reruns the Python script every time a user interacts with the components. They have some caching and optimizations, but this simple design makes it easy to build interactive webpages using Streamlit.</p>\n<blockquote>\n<p>Someone said, “Talk is cheap. Show me the code.” So, let's see some code.</p>\n</blockquote>\n<p>Open an editor and copy-paste this to <code>demo-app.py</code></p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"py\" data-index=\"2\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk15\">import</span><span class=\"mtk1\"> streamlit </span><span class=\"mtk15\">as</span><span class=\"mtk1\"> st</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">st.title(</span><span class=\"mtk8\">&quot;OpenCV Demo App&quot;</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">st.subheader(</span><span class=\"mtk8\">&quot;This app allows you to play with Image filters!&quot;</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">st.text(</span><span class=\"mtk8\">&quot;We use OpenCV and Streamlit for this demo&quot;</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk15\">if</span><span class=\"mtk1\"> st.checkbox(</span><span class=\"mtk8\">&quot;Main Checkbox&quot;</span><span class=\"mtk1\">):</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    st.text(</span><span class=\"mtk8\">&quot;Check Box Active&quot;</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">slider_value = st.slider(</span><span class=\"mtk8\">&quot;Slider&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk12\">min_value</span><span class=\"mtk1\">=</span><span class=\"mtk7\">0.5</span><span class=\"mtk1\">, </span><span class=\"mtk12\">max_value</span><span class=\"mtk1\">=</span><span class=\"mtk7\">3.5</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">st.text(</span><span class=\"mtk4\">f</span><span class=\"mtk8\">&quot;Slider value is </span><span class=\"mtk4\">{</span><span class=\"mtk1\">slider_value</span><span class=\"mtk4\">}</span><span class=\"mtk8\">&quot;</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">st.sidebar.text(</span><span class=\"mtk8\">&quot;text on side panel&quot;</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">st.sidebar.checkbox(</span><span class=\"mtk8\">&quot;Side Panel Checkbox&quot;</span><span class=\"mtk1\">)</span></span></code></pre>\n<p>To start a streamlit app, simply run the command <code>streamlit run</code> with the filename — for example:</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"py\" data-index=\"3\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk1\">streamlit run demo-app.py</span></span></code></pre>\n<p>You should get a similar output as follows. </p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"\" data-index=\"4\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">  You can now view your Streamlit app in your browser.</span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\">  Local URL: http://localhost:8501</span>\n<span class=\"grvsc-line\">  Network URL: http://192.168.1.8:8501</span></code></pre>\n<p>Click on the links in the output to open the Streamlit app in your browser. You'll see something as follows. </p>\n<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 768px; \"\n    >\n      <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 44.46153846153847%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAJCAYAAAAywQxIAAAACXBIWXMAAAsTAAALEwEAmpwYAAAA+klEQVQoz5VRCY7CMAzM/78ICyxCHGmThp65Z510U4q0B1ga2VHG44nD1E1BcUJ1h+QNdNcDziJakwFHmYDoAYQnRE88T/fB0tHmzG6VwvkiIGSP5j7C2NRI/SukqGuJ65WD8xpVJTLWUXhMyI7ILWRDgmqAMW4mxLggxel4wsdmh/3ugM/DEVuqaxKVQkJrvfQwRa4KZPO7YD8MxGkxUrM2FtpaGOdy7b1fnLLkKiEL/uAQ34Kupd22AylPD3QjaEJ+bggh42WHZpzgJg2vafnOz7BuznHmJ6cvC6Yc0nn1CXH5kfh48n+CpX760bKKMnTFf8vhX0NKfAEhYsCUIq0VpgAAAABJRU5ErkJggg=='); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"Streamlit basic web app\"\n        title=\"Streamlit Basic Demo\"\n        src=\"/static/20e9892f3865cba95d9280b802e06874/e5715/streamlit-1.png\"\n        srcset=\"/static/20e9892f3865cba95d9280b802e06874/a6d36/streamlit-1.png 650w,\n/static/20e9892f3865cba95d9280b802e06874/e5715/streamlit-1.png 768w,\n/static/20e9892f3865cba95d9280b802e06874/36eca/streamlit-1.png 1526w\"\n        sizes=\"(max-width: 768px) 100vw, 768px\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        loading=\"lazy\"\n      />\n    </span></p>\n<p>If you see the code, it's very straightforward. It imports streamlit as st. The default is a simple linear layout where you can place components on the webpage in a sequential manner.</p>\n<p>For example, <code>st.title() , st.checkbox(), st.slider()</code> places the components on the main page in the order they're called.. </p>\n<p>Streamlit also offers a side panel. In order to place components in the sidepanel, you can do as follows:</p>\n<p><code>st.sidebar.title() , st.sidebar.checkbox(), st.sidebar.slider()</code></p>\n<p>There are other components also apart from these. You can <a href=\"https://docs.streamlit.io/library/get-started\">explore more in the docs</a>.</p>\n<h2 id=\"integrate-streamlit-into-your-opencv-project\" style=\"position:relative;\"><a href=\"#integrate-streamlit-into-your-opencv-project\" aria-label=\"integrate streamlit into your opencv project permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Integrate Streamlit into Your OpenCV Project</h2>\n<p>Let's integrate your OpenCV program into Streamlit. Here is the complete code:</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"py\" data-index=\"5\"><code class=\"grvsc-code\"><span class=\"grvsc-line\"><span class=\"mtk15\">import</span><span class=\"mtk1\"> cv2</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk15\">import</span><span class=\"mtk1\"> streamlit </span><span class=\"mtk15\">as</span><span class=\"mtk1\"> st</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk15\">import</span><span class=\"mtk1\"> numpy </span><span class=\"mtk15\">as</span><span class=\"mtk1\"> np</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk15\">from</span><span class=\"mtk1\"> PIL </span><span class=\"mtk15\">import</span><span class=\"mtk1\"> Image</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">def</span><span class=\"mtk1\"> </span><span class=\"mtk11\">brighten_image</span><span class=\"mtk1\">(</span><span class=\"mtk12\">image</span><span class=\"mtk1\">, </span><span class=\"mtk12\">amount</span><span class=\"mtk1\">):</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    img_bright = cv2.convertScaleAbs(image, </span><span class=\"mtk12\">beta</span><span class=\"mtk1\">=amount)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> img_bright</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">def</span><span class=\"mtk1\"> </span><span class=\"mtk11\">blur_image</span><span class=\"mtk1\">(</span><span class=\"mtk12\">image</span><span class=\"mtk1\">, </span><span class=\"mtk12\">amount</span><span class=\"mtk1\">):</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    blur_img = cv2.GaussianBlur(image, (</span><span class=\"mtk7\">11</span><span class=\"mtk1\">, </span><span class=\"mtk7\">11</span><span class=\"mtk1\">), amount)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> blur_img</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">def</span><span class=\"mtk1\"> </span><span class=\"mtk11\">enhance_details</span><span class=\"mtk1\">(</span><span class=\"mtk12\">img</span><span class=\"mtk1\">):</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    hdr = cv2.detailEnhance(img, </span><span class=\"mtk12\">sigma_s</span><span class=\"mtk1\">=</span><span class=\"mtk7\">12</span><span class=\"mtk1\">, </span><span class=\"mtk12\">sigma_r</span><span class=\"mtk1\">=</span><span class=\"mtk7\">0.15</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> hdr</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk4\">def</span><span class=\"mtk1\"> </span><span class=\"mtk11\">main_loop</span><span class=\"mtk1\">():</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    st.title(</span><span class=\"mtk8\">&quot;OpenCV Demo App&quot;</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    st.subheader(</span><span class=\"mtk8\">&quot;This app allows you to play with Image filters!&quot;</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    st.text(</span><span class=\"mtk8\">&quot;We use OpenCV and Streamlit for this demo&quot;</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    blur_rate = st.sidebar.slider(</span><span class=\"mtk8\">&quot;Blurring&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk12\">min_value</span><span class=\"mtk1\">=</span><span class=\"mtk7\">0.5</span><span class=\"mtk1\">, </span><span class=\"mtk12\">max_value</span><span class=\"mtk1\">=</span><span class=\"mtk7\">3.5</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    brightness_amount = st.sidebar.slider(</span><span class=\"mtk8\">&quot;Brightness&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk12\">min_value</span><span class=\"mtk1\">=-</span><span class=\"mtk7\">50</span><span class=\"mtk1\">, </span><span class=\"mtk12\">max_value</span><span class=\"mtk1\">=</span><span class=\"mtk7\">50</span><span class=\"mtk1\">, </span><span class=\"mtk12\">value</span><span class=\"mtk1\">=</span><span class=\"mtk7\">0</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    apply_enhancement_filter = st.sidebar.checkbox(</span><span class=\"mtk8\">&#39;Enhance Details&#39;</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    image_file = st.file_uploader(</span><span class=\"mtk8\">&quot;Upload Your Image&quot;</span><span class=\"mtk1\">, </span><span class=\"mtk12\">type</span><span class=\"mtk1\">=[</span><span class=\"mtk8\">&#39;jpg&#39;</span><span class=\"mtk1\">, </span><span class=\"mtk8\">&#39;png&#39;</span><span class=\"mtk1\">, </span><span class=\"mtk8\">&#39;jpeg&#39;</span><span class=\"mtk1\">])</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk15\">if</span><span class=\"mtk1\"> </span><span class=\"mtk4\">not</span><span class=\"mtk1\"> image_file:</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        </span><span class=\"mtk15\">return</span><span class=\"mtk1\"> </span><span class=\"mtk4\">None</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    original_image = Image.open(image_file)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    original_image = np.array(original_image)</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    processed_image = blur_image(original_image, blur_rate)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    processed_image = brighten_image(processed_image, brightness_amount)</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    </span><span class=\"mtk15\">if</span><span class=\"mtk1\"> apply_enhancement_filter:</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">        processed_image = enhance_details(processed_image)</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    st.text(</span><span class=\"mtk8\">&quot;Original Image vs Processed Image&quot;</span><span class=\"mtk1\">)</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    st.image([original_image, processed_image])</span></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"></span>\n<span class=\"grvsc-line\"><span class=\"mtk15\">if</span><span class=\"mtk1\"> </span><span class=\"mtk12\">__name__</span><span class=\"mtk1\"> == </span><span class=\"mtk8\">&#39;__main__&#39;</span><span class=\"mtk1\">:</span></span>\n<span class=\"grvsc-line\"><span class=\"mtk1\">    main_loop()</span></span></code></pre>\n<p><strong>Let's understand what's happening here.</strong></p>\n<p>Apart from the image processing functions, you have a 'main_loop' function to add the logic for the webpage.</p>\n<p>Nothing fancy about <code>st.title(), st.subheader(), st.text()</code> — they just print some text in different sizes.</p>\n<p>Next, there are two sliders to get the amount by which you need to apply the blur and brightness filters.</p>\n<p>Note that <code>st.sidebar</code> places these components in the sidebar.</p>\n<p><code>slider()</code> takes in some arguments: name of the slider, min value, max value, and the default value of the slider. This function returns the current value of the slider.</p>\n<p>Next, there's a checkbox component.</p>\n<p><code>checkbox()</code> returns <em>True</em> if the checkbox is checked; else, it would return <em>False</em>.</p>\n<p>Next, there's a <code>file_uploader</code> component, through which users can upload files of different types specified by the <code>type</code> parameter. Here, it's restricted to the image file types needed for the demo usecase.</p>\n<p>When the program starts, there are no files selected by the user. At this time, this component returns <em>None</em>. When a file is uploaded from the UI, this component returns the path of the file. </p>\n<p>This is why there's an if-check on the return value of this component. If no files are selected, you can skip the rest of the program by returning from the <code>main_loop()</code> function.</p>\n<p>Remember that the entire program is rerun whenever there's user interaction on any components of the page. When a user uploads a file, the whole program is executed again — and the if-check fails so that the program executes the image processing logic.</p>\n<p><code>Pillow.Image()</code> is used to open this file, then it's converted to a numpy array using <code>np.array()</code> so that OpenCV can process it.</p>\n<p>Now, it's passed to the different processing functions along with the <code>amount</code> parameter.</p>\n<p>Finally, the program displays the original and processed images using the <code>st.image()</code> component.</p>\n<p>The web app is ready! </p>\n<p>To start the app, simply run:</p>\n<pre class=\"grvsc-container dark-default-dark\" data-language=\"\" data-index=\"6\"><code class=\"grvsc-code\"><span class=\"grvsc-line\">streamlit run demo-app.py</span></code></pre>\n<p>Now you can play with the filters. Of course, these are some basic filters, but you can extend it to more interesting filters — like cartoonify filters, etc. — using the rich features of OpenCV.</p>\n<p><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 768px; \"\n    >\n      <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 50.92307692307693%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAYAAAC0VX7mAAAACXBIWXMAAAsTAAALEwEAmpwYAAABjUlEQVQoz32ST0vDMBiH/WQePfkB/ABePe42cCKIOry4zYOIHhX/DUFURNgUvewku6jI7KqgW5cuabu2a7r2Z5JOsToX+jSB/PL0zUsnKO2BCWjXgW25iKOBAnGMvueh8dyA1tCgvUia6Ps+Qh6IbZmJxJwARAhDjgnj1QAlNrrMBbM86YF41AjDEK1WG4SYCsMgoJTBYjaiOEmp/PAA50JItBbYuymEHiwljBWJcCAkVNAFZQ5cL4Dnc4XT89ETJMIkHwRCaOptdDpMHHBh2d73pqxTLl23D9txRUXAQLy4+Eg4hPMwVYASShEVvZOz7fipQNswUC4f4fa6guPdbRDTxN/xSyj7JhklNE2Ceu0Kd5VzZGamcHiwj4+P92Hv4hSpCn8LoyhSgbdXHdnFHNY3t7CWW8BSLofLanW8cFSFX0Jd17GSX8bxwR52isu4r9fFtbsp4dc6EQbjr0xIB7WbU1yelTE7PYmNUhGPTw//CuVvNr7Cpoa5TAb5QgmF/Crms1mcnF/8Ef6UfgI5CvBw1x6gPgAAAABJRU5ErkJggg=='); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"Streamlit final Screenshot\"\n        title=\"Streamlit OpenCV Webapp\"\n        src=\"/static/c53bb2b09e9fc430d05e56164d86bf39/e5715/streamlit-final.png\"\n        srcset=\"/static/c53bb2b09e9fc430d05e56164d86bf39/a6d36/streamlit-final.png 650w,\n/static/c53bb2b09e9fc430d05e56164d86bf39/e5715/streamlit-final.png 768w,\n/static/c53bb2b09e9fc430d05e56164d86bf39/29114/streamlit-final.png 1920w\"\n        sizes=\"(max-width: 768px) 100vw, 768px\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        loading=\"lazy\"\n      />\n    </span></p>\n<h2 id=\"how-to-publish-your-app\" style=\"position:relative;\"><a href=\"#how-to-publish-your-app\" aria-label=\"how to publish your app permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>How to Publish Your App?</h2>\n<p>To publish your app, you need to host this program somewhere. There are different hosting providers for complex projects. But for this hobby project, is there a simple and quick solution?</p>\n<p>Yes, there's one!</p>\n<p>You can host the Streamlit application in <a href=\"https://streamlit.io/cloud\">Streamlit Cloud</a> for free. You can host up to 3 apps in an account for free with up to 1GB of memory.</p>\n<p>Check out this tutorial from the community to host your app in Streamlit Cloud.</p>\n<h2 id=\"conclusion\" style=\"position:relative;\"><a href=\"#conclusion\" aria-label=\"conclusion permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Conclusion</h2>\n<p>You can find the source code for this tutorial <a href=\"https://github.com/LoginRadius/engineering-blog-samples/tree/master/Python/OpenCV-Streamlit-Integration\">here</a>. The web app discussed above is <a href=\"https://share.streamlit.io/dingusagar/opencv-streamlit-demo/main/demo-app.py\">hosted here</a> if you want to try it out.</p>\n<p>Want to add user authentication and registration in your app quickly? Check out the <a href=\"https://www.loginradius.com/integrations/python/\">LoginRadius Python integration</a>.</p>\n<style class=\"grvsc-styles\">\n  .grvsc-container {\n    overflow: auto;\n    -webkit-overflow-scrolling: touch;\n    padding-top: 1rem;\n    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));\n    padding-bottom: 1rem;\n    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));\n    border-radius: 8px;\n    border-radius: var(--grvsc-border-radius, 8px);\n    font-feature-settings: normal;\n  }\n  \n  .grvsc-code {\n    display: inline-block;\n    min-width: 100%;\n  }\n  \n  .grvsc-line {\n    display: inline-block;\n    box-sizing: border-box;\n    width: 100%;\n    padding-left: 1.5rem;\n    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));\n    padding-right: 1.5rem;\n    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));\n  }\n  \n  .grvsc-line-highlighted {\n    background-color: var(--grvsc-line-highlighted-background-color, transparent);\n    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, transparent);\n  }\n  \n  .dark-default-dark {\n    background-color: #1E1E1E;\n    color: #D4D4D4;\n  }\n  .dark-default-dark .mtk1 { color: #D4D4D4; }\n  .dark-default-dark .mtk15 { color: #C586C0; }\n  .dark-default-dark .mtk4 { color: #569CD6; }\n  .dark-default-dark .mtk11 { color: #DCDCAA; }\n  .dark-default-dark .mtk12 { color: #9CDCFE; }\n  .dark-default-dark .mtk7 { color: #B5CEA8; }\n  .dark-default-dark .mtk8 { color: #CE9178; }\n  .dark-default-dark .mtk3 { color: #6A9955; }\n</style>","frontmatter":{"date":"November 10, 2021","updated_date":null,"description":"You can now easily publish your OpenCV apps to the web using Streamlit, a Python library. Follow this tutorial to learn the process step by step.","title":"How to Build an OpenCV Web App with Streamlit","tags":["OpenCV","Streamlit","Python"],"pinned":null,"coverImage":{"childImageSharp":{"fluid":{"aspectRatio":1.5037593984962405,"src":"/static/f0dac1cb4c79fe1494333f33ec9a3861/ee604/coverimage.png","srcSet":"/static/f0dac1cb4c79fe1494333f33ec9a3861/69585/coverimage.png 200w,\n/static/f0dac1cb4c79fe1494333f33ec9a3861/497c6/coverimage.png 400w,\n/static/f0dac1cb4c79fe1494333f33ec9a3861/ee604/coverimage.png 800w,\n/static/f0dac1cb4c79fe1494333f33ec9a3861/f3583/coverimage.png 1200w","sizes":"(max-width: 800px) 100vw, 800px"}}},"author":{"id":"Dingu Sagar","github":"dingusagar","avatar":null}}}}]},"markdownRemark":{"excerpt":"Google has prepared a roadmap to restrict third-party cookies in Chrome. Since 04 January 2024, Chrome has rolled out third-party cookie…","fields":{"slug":"/engineering/identity-impact-of-google-chrome-thirdparty-cookie-restrictions/"},"html":"<p>Google has prepared a roadmap to restrict third-party cookies in Chrome. Since 04 January 2024, Chrome has rolled out third-party cookie restrictions for 1% of stable clients and 20% of Canary, Dev, and Beta clients.</p>\n<p><strong>What does it mean for user authentication?</strong></p>\n<p>On one hand, Google believes third-party cookies are widely used for cross-site tracking, greatly affecting user privacy. Hence, Google wants to phase out (or restrict) supporting third-party cookies in Chrome by early Q2 2025 (subject to regulatory processes).</p>\n<p>On the other hand, Google introduced Privacy Sandbox to support the use cases (other than cross-site tracking and advertising) previously implemented using third-party cookies.</p>\n<p>In this article, we’ll discuss:</p>\n<ul>\n<li>How is user authentication (identity) affected?</li>\n<li>What is Google offering as part of Privacy Sandbox to support various identity use cases when third-party cookies are phased out?</li>\n</ul>\n<h2 id=\"how-is-user-authentication-affected\" style=\"position:relative;\"><a href=\"#how-is-user-authentication-affected\" aria-label=\"how is user authentication affected permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>How is User Authentication Affected?</h2>\n<p>Third-party cookie restrictions affect user authentication in three ways, as follows.</p>\n<h3 id=\"external-identity-providers\" style=\"position:relative;\"><a href=\"#external-identity-providers\" aria-label=\"external identity providers permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>External Identity Providers</h3>\n<p>If your website or app uses an external Identity Provider (IdP) — like LoginRadius, the IdP sets a third-party cookie when the user authenticates on your app.</p>\n<h3 id=\"web-sso\" style=\"position:relative;\"><a href=\"#web-sso\" aria-label=\"web sso permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Web SSO</h3>\n<p>If you have multiple apps across domains within your organization and authentication is handled using an IdP (internal or external) with web SSO, you already use third-party cookies to facilitate seamless access for each user using a single set of credentials.</p>\n<p>If you have implemented web SSO with one primary domain and multiple sub-domains of the primary domain, third-party cookie restrictions may not apply. For now, Google doesn’t consider the cookies set by sub-domains as third-party cookies, although this stance may change in the future.</p>\n<p>For example, you have apps at <code>example.com</code>, <code>travel.example.com</code>, <code>stay.example.com</code>, and web SSO is handled by <code>auth.example.com</code>. In this case, third-party cookie restrictions don’t apply.</p>\n<h3 id=\"federated-sso\" style=\"position:relative;\"><a href=\"#federated-sso\" aria-label=\"federated sso permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Federated SSO</h3>\n<p>Federated SSO is similar to, albeit different from, web SSO. It can handle multiple IdPs and applications—aka., Service Providers (SPs)—spanning multiple organizations. It can also implement authentication scenarios that are usually implemented through web SSO.</p>\n<p>Usually, authentication is handled on a separate pop-up or page when the user wants to authenticate rather than on the application or website a user visits. </p>\n<p>For example, you already use federated SSO if you facilitate authentication for a set of apps through multiple social identity providers as well as traditional usernames and passwords.</p>\n<blockquote>\n<p><strong>Note</strong>: It is also possible to store tokens locally, not within cookies. In this case, third-party cookie restrictions won’t affect token-based authentication. However, the restrictions still affect authentication where tokens are stored within third-party cookies (a common and secure method).</p>\n</blockquote>\n<h2 id=\"chromes-alternatives-for-third-party-cookies\" style=\"position:relative;\"><a href=\"#chromes-alternatives-for-third-party-cookies\" aria-label=\"chromes alternatives for third party cookies permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Chrome’s Alternatives for Third-Party Cookies</h2>\n<p>Google has been developing alternative features and capabilities for Chrome to replace third-party cookies as part of its Privacy Sandbox for Web initiative.</p>\n<p>Specific to authentication, Google recommends the following:</p>\n<ol>\n<li>Cookies Having Independent Partitioned State (CHIPS)</li>\n<li>Storage Access API</li>\n<li>Related Website Sets</li>\n<li>Federated Credential Management (FedCM) API</li>\n</ol>\n<h3 id=\"cookies-having-independent-partitioned-state-chips\" style=\"position:relative;\"><a href=\"#cookies-having-independent-partitioned-state-chips\" aria-label=\"cookies having independent partitioned state chips permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Cookies Having Independent Partitioned State (CHIPS)</h3>\n<p><a href=\"https://developers.google.com/privacy-sandbox/3pcd/chips\">CHIPS</a> are a restricted way of setting third-party cookies on a top-level site without making them accessible on other top-level sites. Thus, they limit cross-site tracking and enable specific cross-site functionalities, such as maps, chat, and payment embeds.</p>\n<p>For example, a user visits <code>a.com</code> with a map embed from <code>map-example.com</code>, which can set a partitioned cookie that is only accessible on a.com. </p>\n<p>If the user visits <code>b.com</code> with a map embed from <code>map-example.com</code>, it cannot access the partitioned cookie set on <code>a.com</code>. It has to create a separate partitioned cookie specific to <code>b.com</code>, thus blocking cross-site tracking yet allowing limited cross-site functionality.</p>\n<p>You should specifically opt for partitioned cookies (CHIPS), which are set with partitioned and secure cookie attributes.</p>\n<p>If you’re using an external identity provider for your application, CHIPS is a good option to supplant third-party cookie restrictions. </p>\n<p>However, CHIPS may not be ideal if you have a web SSO or federated SSO implementation. It creates separate partitioned cookies for each application with a separate domain, which can increase complexity and create compatibility issues.</p>\n<h3 id=\"storage-access-api\" style=\"position:relative;\"><a href=\"#storage-access-api\" aria-label=\"storage access api permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Storage Access API</h3>\n<p>With <a href=\"https://developers.google.com/privacy-sandbox/3pcd/storage-access-api\">Storage Access API</a>, you can access the local storage in a third-party context through iframes, similar to when users visit it as a top-level site in a first-party context. That is, it gives access to unpartitioned cookies and storage.</p>\n<p>Storage Access API requires explicit user approval to grant access, similar to locations, camera, and microphone permissions. If the user denies access, unpartitioned cookies and storage won’t be accessible in a third-party context.</p>\n<p>It is most suitable when loading cross-site resources and interactions, such as:</p>\n<p>Verifying user sessions when allowing interactions on an embedded social post or providing personalization for an embedded video.\nEmbedded documents requiring user verification status to be accessible.</p>\n<p>As it requires explicit user approval, it is advisable to use Storage Access API when you can’t implement an identity use case with the other options.</p>\n<h3 id=\"related-website-sets\" style=\"position:relative;\"><a href=\"#related-website-sets\" aria-label=\"related website sets permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Related Website Sets</h3>\n<p>With <a href=\"https://developers.google.com/privacy-sandbox/3pcd/related-website-sets\">Related Website Sets</a>, you can declare a <code>primary</code> website and <code>associatedSites</code> for limited purposes to grant third-party cookie access and local storage for a limited number of sites.</p>\n<p>Chrome automatically recognizes related website sets declared, accepted, and maintained in this open-source GitHub repository: <a href=\"https://github.com/GoogleChrome/related-website-sets\">Related Website Sets</a></p>\n<p>It provides access through Storage Access API directly without prompting for user approval, but only after the user interacts with the relevant iframe.</p>\n<p>It is important to declare a limited number of domains in related website sets that are meaningful and used for specific purposes. Google may block or suspend any exploitative use of this feature.</p>\n<p>The top-level site can also request approval for specific cross-site resources and scripts to Storage Access API using <code>resuestStorageAccessFor()</code> API.</p>\n<p>If you’re using an external identity provider for your web application, you can declare the domain of the identity provider in the related set to ensure limited third-party cookies and storage access to the identity provider, thus ensuring seamless user authentication.</p>\n<p>Related Website Sets can also work to supplement third-party cookie restrictions in web SSO and federated SSO if the number of web applications (or domains) is limited.</p>\n<h3 id=\"federated-credential-management-fedcm-api\" style=\"position:relative;\"><a href=\"#federated-credential-management-fedcm-api\" aria-label=\"federated credential management fedcm api permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Federated Credential Management (FedCM) API</h3>\n<p>FedCM API enables federated SSO without third-party cookies.</p>\n<p>With FedCM API, a user follows these steps for authentication:</p>\n<ol>\n<li>The User navigates to a Service Provider (SP) — aka., Relying Party (RP)</li>\n<li>As the user requests to authenticate, the SP requests the browser through FedCM API to initiate authentication.</li>\n<li>The browser displays a list of available identity providers (supported by the RP), such as social IdPs like Google, Apple, LinkedIn, and Facebook, or other OAuth IdPs like LoginRadius.</li>\n<li>Once the user selects an IdP, the browser communicates with the IdP. Upon valid authentication, the IdP generates a secure token.\nThe browser delivers this secure token to the RP to facilitate user authorization.</li>\n</ol>\n<p>You can access a user demo of FedCM here: <a href=\"https://fedcm-rp-demo.glitch.me/\">FedCM</a>. </p>\n<p>For more information about implementing federated SSO with FedCM API, go through the <a href=\"https://developers.google.com/privacy-sandbox/3pcd/fedcm-developer-guide\">FedCM developer guide</a>.</p>\n<h2 id=\"how-is-loginradius-preparing-for-the-third-party-cookie-phase-out\" style=\"position:relative;\"><a href=\"#how-is-loginradius-preparing-for-the-third-party-cookie-phase-out\" aria-label=\"how is loginradius preparing for the third party cookie phase out permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>How is LoginRadius Preparing for the Third-party Cookie Phase-out?</h2>\n<p>Firstly, we’re committed to solving our customers' user identity pain points — and preparing for the third-party cookies phase-out is no different.</p>\n<p>We’ll implement the most relevant and widely useful solutions to facilitate a smooth transition for our customers.</p>\n<p>Please subscribe to our blog for more information. We’ll update you on how we help with the third-party cookie phase-out.</p>\n<h2 id=\"in-conclusion\" style=\"position:relative;\"><a href=\"#in-conclusion\" aria-label=\"in conclusion permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>In Conclusion</h2>\n<p>The proposed changes to phase out third-party cookies and suggested alternatives are evolving as Google has been actively collaborating and discussing changes with the border community.</p>\n<p>Moreover, browsers like Firefox, Safari, and Edge may approach restricting third-party cookies differently than Google does.</p>\n<p>From LoginRadius, we’ll keep you updated on what we’re doing as a leading Customer Identity and Access Management (CIAM) vendor to prepare for the third-party cookie phase-out.</p>\n<h2 id=\"glossary\" style=\"position:relative;\"><a href=\"#glossary\" aria-label=\"glossary permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Glossary</h2>\n<p><strong>Top-level site</strong>: It is the primary site a user has visited.</p>\n<p><strong>First-party cookie</strong>: A cookie set by the top-level site.</p>\n<p><strong>Third-party cookie</strong>: A cookie set by a domain other than the top-level site. For example, let’s assume that a user has visited <code>a.com</code>, which might use an embed from <code>loginradius.com</code> to facilitate authentication. If <code>loginradius.com</code> sets a cookie when the user visits <code>a.com</code>, it is called a third-party cookie as the user hasn’t directly visited <code>loginradius.com</code>.</p>\n<h2 id=\"references\" style=\"position:relative;\"><a href=\"#references\" aria-label=\"references permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>References</h2>\n<ul>\n<li><a href=\"https://developers.google.com/privacy-sandbox/3pcd/prepare/prepare-for-phaseout\">Changes to Chrome's treatment of third-party cookies</a></li>\n<li><a href=\"https://developers.google.com/privacy-sandbox/3pcd/guides/identity\">Check the impact of the third-party cookie changes on your sign-in workflows</a></li>\n</ul>\n<style class=\"grvsc-styles\">\n  .grvsc-container {\n    overflow: auto;\n    -webkit-overflow-scrolling: touch;\n    padding-top: 1rem;\n    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));\n    padding-bottom: 1rem;\n    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));\n    border-radius: 8px;\n    border-radius: var(--grvsc-border-radius, 8px);\n    font-feature-settings: normal;\n  }\n  \n  .grvsc-code {\n    display: inline-block;\n    min-width: 100%;\n  }\n  \n  .grvsc-line {\n    display: inline-block;\n    box-sizing: border-box;\n    width: 100%;\n    padding-left: 1.5rem;\n    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));\n    padding-right: 1.5rem;\n    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));\n  }\n  \n  .grvsc-line-highlighted {\n    background-color: var(--grvsc-line-highlighted-background-color, transparent);\n    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, transparent);\n  }\n  \n</style>","frontmatter":{"date":"July 08, 2024","updated_date":null,"description":"Google Chrome has planned to phase out third-party cookies, which will affect different website functionalities depending on third-party cookies. This blog focuses on how this phase-out affects identity and user authentication and discusses alternatives for overcoming challenges.","title":"How Chrome’s Third-Party Cookie Restrictions Affect User Authentication?","tags":["Identity","Cookies","Chrome"],"pinned":null,"coverImage":{"childImageSharp":{"fluid":{"aspectRatio":1.5037593984962405,"src":"/static/eb7396060c0adc430dbed2d04b63d431/ee604/third-party-cookies-phaseout-chrome.png","srcSet":"/static/eb7396060c0adc430dbed2d04b63d431/69585/third-party-cookies-phaseout-chrome.png 200w,\n/static/eb7396060c0adc430dbed2d04b63d431/497c6/third-party-cookies-phaseout-chrome.png 400w,\n/static/eb7396060c0adc430dbed2d04b63d431/ee604/third-party-cookies-phaseout-chrome.png 800w,\n/static/eb7396060c0adc430dbed2d04b63d431/f3583/third-party-cookies-phaseout-chrome.png 1200w","sizes":"(max-width: 800px) 100vw, 800px"}}},"author":{"id":"Raghunath Reddy","github":"raghunath-r-a","avatar":null}}}},"pageContext":{"limit":6,"skip":30,"currentPage":6,"type":"//engineering//","numPages":52,"pinned":"17fa0d7b-34c8-51c4-b047-df5e2bbaeedb"}},"staticQueryHashes":["1171199041","1384082988","2100481360","23180105","528864852"]}