{"componentChunkName":"component---src-templates-blog-list-template-js","path":"/56","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":"Introduction Marketing is one of the main components of business management and commerce. Consumer response to your product depends highly…","fields":{"slug":"/growth/consumer-identity-rule-personalized-marketing-2022/"},"html":"<h2 id=\"introduction\" style=\"position:relative;\"><a href=\"#introduction\" aria-label=\"introduction permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Introduction</h2>\n<p>Marketing is one of the main components of business management and commerce. Consumer response to your product depends highly on the marketing strategy adopted by businesses. How you are selling your product or service is of more significance than what you are selling.</p>\n<p>Personalization is becoming more and more common these days with <a href=\"https://www.loginradius.com/resource/the-enterprise-buyers-guide-to-consumer-identity/\">consumer identity</a> at the center of it all. In personalization, the entire consumer experience and services revolve around a consumer and how they connect with a brand personally. </p>\n<h2 id=\"what-is-consumer-identity\" style=\"position:relative;\"><a href=\"#what-is-consumer-identity\" aria-label=\"what is consumer identity 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 Consumer Identity</h2>\n<p>Consumer identity can be described as the pattern of consumers- what are the products they are buying? How are they interacting with brands? Which platforms are they using to interact with brands? All these things can be included in consumer identity.</p>\n<p>Consumer identity can be obtained in many ways. Organizations can gather data like contact details, age or demographic details, social identity, etc. All these factors help the organizations make the marketing experience personalized for the customers.</p>\n<p>Customer identity and personalization have benefitted customers in numerous ways, but the main concern for people is- safety. </p>\n<p>By implementing a customer identity and access management system, numerous organizations leverage authorization and authentication of users to keep data safe.</p>\n<p>Let's talk more about it.</p>\n<h2 id=\"what-is-customer-identity-and-access-management\" style=\"position:relative;\"><a href=\"#what-is-customer-identity-and-access-management\" aria-label=\"what is customer identity and access management 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 Customer Identity and Access Management</h2>\n<p><a href=\"https://www.loginradius.com/blog/identity/customer-identity-and-access-management/\">Customer identity and access management</a> (CIAM) regulates the authentication and authorization of users who interact with different applications. This system revolves around a customer account that has all the information provided by the user. Using this information, the application makes the entire experience personalized for the user. </p>\n<p><strong>Customer identity programs for marketing</strong> can enhance the user experience by making it safer and easier. </p>\n<h2 id=\"benefits-of-using-customer-identity-programs-for-personalized-marketing\" style=\"position:relative;\"><a href=\"#benefits-of-using-customer-identity-programs-for-personalized-marketing\" aria-label=\"benefits of using customer identity programs for personalized marketing 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 Using Customer Identity Programs for Personalized Marketing</h2>\n<p>With the digitization of business operations, including marketing, customers are focusing more on user experience and data safety. This may be achieved through consumer identity and access management to create a safe and individualized interface for users. </p>\n<ul>\n<li><strong><em>Sign in or registration</em></strong></li>\n</ul>\n<p>When registering for an application the first time, you have to fill out details, including your email id, user name, password, social identity, contact details, social media handles etc; some applications also need other preferences. The main objectives of sharing these details are: </p>\n<ol>\n<li>Authentication</li>\n<li>Personalization</li>\n</ol>\n<p>After this, the application observes your activities and keeps the interface evolving according to the user activities.</p>\n<p><a href=\"https://www.loginradius.com/resource/guide-to-modern-customer-identity/\"><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 768px; \"\n    >\n      <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 30.307692307692307%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAGCAYAAADDl76dAAAACXBIWXMAAAsSAAALEgHS3X78AAABoElEQVQY0zWPyUtbURjFH9aa4QmWakBrGmmrGXyJxEaeUWNsBqOpAzhAMArWlm4cKkhdiGlF3KjgQgQFqYVStSmCqCClcWF1IXXVVTcu/Fd+3ncli8O9373nO4NidYV4+KKZhbk5rk6zHH3bYnd7gz+5E3Z3vuIMdlEo/q2uVszV4tRilAX7KK2LYfHGMbvbMNe0CISwOEMoqiAWPAuSGnrPxc8dzvY3Od1b5+D7F7JrC3ib2nkgBcWCWFSFiCMyhBZPYdX7MfkSWJ0tUswQVvIXrXmAd4PDLM/OsL40z+ToGIsfZ6iL9klDI2FFQxK7/pongQ7KA53YGwT0JJV6FyXaK0x5QZOo4gokSfa+oX9gjHhnGndtmPqXMcp9EUk0eAZs9Qnsjd08DXbjaOqRJqo7LEPJypIo3Kt8UWr97Xj8CZ5rEWwOndLKAI89baieMEqFn4nMKv9vbjn8dc6P499kT3JcXv8jd/mXR94oRSKYkneW1cWDpeYeqpiLhbNR1UBBlU6jaDA+v8Lw9CfSUxnSHzK8nV1iZPozxcLUaHIH2VzYTeppS8MAAAAASUVORK5CYII='); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"EB-GD-to-Mod-Cust-ID\"\n        title=\"EB-GD-to-Mod-Cust-ID\"\n        src=\"/static/e8ca49370e6ab28514cbd05ef77951af/e5715/EB-GD-to-Mod-Cust-ID.png\"\n        srcset=\"/static/e8ca49370e6ab28514cbd05ef77951af/a6d36/EB-GD-to-Mod-Cust-ID.png 650w,\n/static/e8ca49370e6ab28514cbd05ef77951af/e5715/EB-GD-to-Mod-Cust-ID.png 768w,\n/static/e8ca49370e6ab28514cbd05ef77951af/81501/EB-GD-to-Mod-Cust-ID.png 2886w\"\n        sizes=\"(max-width: 768px) 100vw, 768px\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        loading=\"lazy\"\n      />\n    </span></a></p>\n<ul>\n<li><strong><em>Multi-factor authentication</em></strong></li>\n</ul>\n<p>In most applications, authentication ends with registration, where the user has to generate an ID and a password. But this is not the case with CIAM. What makes CIAM more secure than other systems is its feature of ongoing authentication. The application continuously works on context-sensitive data and behavioral factors to authenticate the user in an ongoing authentication.</p>\n<p><a href=\"https://www.loginradius.com/multi-factor-authentication/\">Multi-factor authentication</a> does require many sign-ups, but it uses other methods like codes, one time passwords and a series of questions that are usually personal. </p>\n<p>For example, in the case of net banking, you sign into your account to authorize a transaction. Before finalizing the transaction, you have to enter a specific code sent to your contact number or email address. </p>\n<ul>\n<li><strong><em>Central data management</em></strong></li>\n</ul>\n<p>The <a href=\"https://www.loginradius.com/blog/fuel/how-to-make-personalized-marketing-effective-with-consumer-identity/\">consumer identity program for marketing</a> uses consumer data and information to analyze and personalize the activities. An application has multiple functions and users, which results in a huge amount of data to store and process. Huge data is not the problem; scattered data is. </p>\n<p>The effective and efficient use of data is possible only when it is organized systematically. CIAM uses a central data dashboard that stores all the relevant data in one place. There, data can be retrieved, updated and added without causing any disruption to the system. </p>\n<ul>\n<li><strong><em>Encryption</em></strong></li>\n</ul>\n<p>Consumer data is precious for your business, and its safety is the number one concern of the users. But, what happens in case of a data breach? If you are using CIAM for your business, you don't have to worry as the system does high-end data encryption while performing other functions. User authentication and data encryption make data more secure in cases of breaches. </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 many benefits of consumer identity programs for marketing, the two most important benefits being safety and personalization. Both of these can be achieved by proper implementation of CIAM from the business leaders. </p>\n<p><a href=\"https://www.loginradius.com/book-a-demo/\"><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 768px; \"\n    >\n      <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 30.307692307692307%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAGCAYAAADDl76dAAAACXBIWXMAAAsSAAALEgHS3X78AAABdElEQVQY002RO0/CUBzFG6PtbZWHCAmRmBB5P8vDII9SSC0omog4oAEGjZMO6OKEuLjoJ2Fx0cSBwUQnXZxcHPwux38LJA7nNvfec8+5v1tOCCiwpbbhye2BxbYgBMtgIRVioDRRsARGXxZUzLlEHmehBaesQ4rrEMPViYf2DR9nDGKkChbVICVqsMt1WJI1sHCFwhUsUIFohJH49TxECvRUjhDW2mAbB5iP6hB8hUkhiRPN5KIZYJdrsEYrcCSpmQqMm6/m9ylUhSulY7N5ivROB3L9GOlGF3Ktbc4zuz341UPw/uIk0ESbBjoSGlYIx8BfzjSwVmyCEYEUUmCPa3Bnd+hwC75yC95S05SxbolU/iEbOCFCpDexEfIioTNCNd6Tp6IlMnNuGeeDe3z//OLx5RWj5zFGT2O8fXxh/P4Ja6w6vSEFCnTIlW2YiDzhzX7ATFKojDlvjpBPcDF4QPdyiG5/iE7/BmfXd+hd3VKpCoG8fzxWw2+c+yTpAAAAAElFTkSuQmCC'); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"book-a-demo-Consultation\"\n        title=\"book-a-demo-Consultation\"\n        src=\"/static/fcc4c4b5dc38cc4528f99d09480f4eb2/e5715/book-a-demo-loginradius.png\"\n        srcset=\"/static/fcc4c4b5dc38cc4528f99d09480f4eb2/a6d36/book-a-demo-loginradius.png 650w,\n/static/fcc4c4b5dc38cc4528f99d09480f4eb2/e5715/book-a-demo-loginradius.png 768w,\n/static/fcc4c4b5dc38cc4528f99d09480f4eb2/63ff0/book-a-demo-loginradius.png 2887w\"\n        sizes=\"(max-width: 768px) 100vw, 768px\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        loading=\"lazy\"\n      />\n    </span></a></p>\n<style class=\"grvsc-styles\">\n  .grvsc-container {\n    overflow: auto;\n    -webkit-overflow-scrolling: touch;\n    padding-top: 1rem;\n    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));\n    padding-bottom: 1rem;\n    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));\n    border-radius: 8px;\n    border-radius: var(--grvsc-border-radius, 8px);\n    font-feature-settings: normal;\n  }\n  \n  .grvsc-code {\n    display: inline-block;\n    min-width: 100%;\n  }\n  \n  .grvsc-line {\n    display: inline-block;\n    box-sizing: border-box;\n    width: 100%;\n    padding-left: 1.5rem;\n    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));\n    padding-right: 1.5rem;\n    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));\n  }\n  \n  .grvsc-line-highlighted {\n    background-color: var(--grvsc-line-highlighted-background-color, transparent);\n    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, transparent);\n  }\n  \n</style>","frontmatter":{"date":"December 14, 2021","updated_date":null,"description":"Consumer identity management is actually a great way to help companies grow. It is through high quality CIAM that a business can create better targeted, safer, more meaningful marketing experiences for their customers.","title":"Do Consumer Identity Programs Really Work for Personalized Marketing?","tags":["identity management","ciam solution","mfa","cx"],"pinned":null,"coverImage":{"childImageSharp":{"fluid":{"aspectRatio":1.694915254237288,"src":"/static/7abe0fa91b757ef6b52e8858806cde68/14b42/personalized-marketing.jpg","srcSet":"/static/7abe0fa91b757ef6b52e8858806cde68/f836f/personalized-marketing.jpg 200w,\n/static/7abe0fa91b757ef6b52e8858806cde68/2244e/personalized-marketing.jpg 400w,\n/static/7abe0fa91b757ef6b52e8858806cde68/14b42/personalized-marketing.jpg 800w,\n/static/7abe0fa91b757ef6b52e8858806cde68/16310/personalized-marketing.jpg 1024w","sizes":"(max-width: 800px) 100vw, 800px"}}},"author":{"id":"Navanita Devi","github":null,"avatar":null}}}},{"node":{"excerpt":"The LoginRadius PerfectMind integration is delivering a seamless user experience and helping cities in increasing user conversions allowing…","fields":{"slug":"/identity/loginradius-perfectmind-integration-sso-ux/"},"html":"<p>The LoginRadius PerfectMind integration is delivering a seamless user experience and helping cities in increasing user conversions allowing their users to register and authenticate flawlessly.</p>\n<p><a href=\"https://www.loginradius.com/authentication/\">Authentication</a> is one of the most important aspects that should be carried out without any friction since a great consumer experience is a key to business success; LoginRadius understands this and developed an out of the box SSO solution to deliver a seamless user experience between LoginRadius and PerfectMind applications.  </p>\n<p>Users expect authentication experiences that are quick, delightful, secure, and seamless. Hence, a robust authentication mechanism becomes the need of the hour for enterprises collecting and storing vast amounts of user information and leveraging this across distinct systems and toolsets.</p>\n<p>LoginRadius’ cutting-edge single sign-on helps overcome all the challenges related to consumer experience and data integration.  Let’s understand how LoginRadius paves the path for a robust user experience by integrating PerfectMind. </p>\n<h2 id=\"what-is-perfectmind\" style=\"position:relative;\"><a href=\"#what-is-perfectmind\" aria-label=\"what is perfectmind 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 PerfectMind?</h2>\n<p>PerfectMind (part of Xplor) is a membership management software that uses cloud-based technology to help organizations of all sizes connect with their communities. </p>\n<p>PerfectMind started as a software solution for martial arts schools but has expanded over the years to serve other industries, most notably parks and recreation departments.</p>\n<h2 id=\"intent-behind-the-integration\" style=\"position:relative;\"><a href=\"#intent-behind-the-integration\" aria-label=\"intent behind the integration permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Intent Behind the Integration</h2>\n<p>Canadian municipal and community organizations were looking for a way to connect their native website to PerfectMind so users could log in and enjoy a seamless experience between the sites.</p>\n<p>Since, PerfectMind does not support industry-standard <a href=\"https://www.loginradius.com/blog/identity/loginradius-federated-identity-management/\">federated Single Sign-On</a> methods like SAML, OAuth/OIDC, or JWT, LoginRadius offered its out-of-the-box SSO Connector solutions to create a Single Sign-on user experience between LoginRadius and the PerfectMind applications by leveraging APIs.</p>\n<p><a href=\"https://www.loginradius.com/resource/perfectmind-integration\"><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 768px; \"\n    >\n      <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 30.307692307692307%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAGCAYAAADDl76dAAAACXBIWXMAAAsSAAALEgHS3X78AAABu0lEQVQY002PPWgTcRiHr0nuetWapL1LmiNp0pC7XKtJU2Pa2Ia4KBZE7Naqi1AViV8UwUlwd9PJxU1UFNIOVsQOikgRHERU/KjXJphav0IRScDW4fGviPjCw8s7vA+/n9RmFVDNYdrtEfy9BXxie+1hNll52s1B1GgGJZIWbEEO2SixDP7UDnw9aeTuFO6QhVuL4dGiuDsjSBuSBeSeQS5eucq7apXFSoUlwYs3C8w/fcb2PeNIuoUqnhWjFzWeJTw0ip3fSWtfEU+sH1n/T9hmjaDEh7hVnuZL/SO15QrLNYefP75R//yewt4JJM1EFQm1ZA7NyqKbA+jWVrqsDIFEP3oijRqM4+oIC6Go6xEJyzev0fjk0Fh5y+VLFzhUOs6R01NEBoq4jD5aw5uRDRtX0MQr6kZSebrsLHJAiDq78Qj+Cd2xHDOz91hvfufrhxrVRYfnL1/hLFUo7juIFEwieaOUzp7n9YLD9J05rpdvc2NmlkePnzB3/yEbjQSSL/RXGN3G3Qfz/J766iqNZpP1tbU/9+7xSaSOOC0Bk9yuMY6dOcf+o6eYOHxScEI0meLAZAklEKPFb/ALF67zGWX+5Q8AAAAASUVORK5CYII='); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"DS-perfectmind-int\"\n        title=\"DS-perfectmind-int\"\n        src=\"/static/9dfd5053b2cf5348ba48bca7ef31cb14/e5715/DS-perfectmind-int.png\"\n        srcset=\"/static/9dfd5053b2cf5348ba48bca7ef31cb14/a6d36/DS-perfectmind-int.png 650w,\n/static/9dfd5053b2cf5348ba48bca7ef31cb14/e5715/DS-perfectmind-int.png 768w,\n/static/9dfd5053b2cf5348ba48bca7ef31cb14/81501/DS-perfectmind-int.png 2886w\"\n        sizes=\"(max-width: 768px) 100vw, 768px\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        loading=\"lazy\"\n      />\n    </span></a></p>\n<p>Through LoginRadius PerfectMind integration, the PerfectMind consumers are leveraging all the powerful capabilities of the cutting-edge CIAM platform, including social login, <a href=\"https://www.loginradius.com/blog/identity/passwordless-authentication-the-future-of-identity-and-security/\">passwordless login</a>, single sign-on, reinforced by robust security. </p>\n<h2 id=\"final-thoughts\" style=\"position:relative;\"><a href=\"#final-thoughts\" aria-label=\"final thoughts 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>Final Thoughts</h2>\n<p>With the LoginRadius PerfectMind SSO, businesses can establish a flawless user experience by overcoming the barriers of frictionless authentication and authorization across multiple platforms/ servers. </p>\n<p><a href=\"https://www.loginradius.com/book-a-demo/\"><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 768px; \"\n    >\n      <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 30.307692307692307%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAGCAYAAADDl76dAAAACXBIWXMAAAsTAAALEwEAmpwYAAABeElEQVQY001RuU4CURSdODrMACJgKFQiEGXfXUBg2AZnQKKIiQVqpbGhsLGg0MTCGENiYeEHGC2JVi6NsbQwNhb+z/G+GUwsTt5y3zvLvZwpIMORqsOdXYcYUcDOYqAIyV+AFDAg6ntZv7PEanBmWphM1GCO1iCFKzCzGvtHdU5/HKlCiiqQ4irsSRXWhAoxWNLJx/xF4zGB9yzDRKLTlQ6C1W3w6RZGwjXw3gxM84Yo96dsCpXJqQZbpAx7rApzbBW2pIaplRZG/TJcKRW59gHSa3tYaOwi1Riu9R1kN/fhLbQgzOXI4ZCQOXKQO2dcgZPiSHENjnQDPnkLQrAMa6iICRJypTW6a8OT28AsYSbT1A2Mh8v/IhMp+yTGWGTNiMxikohAzi2hEjj3Io7OrvD5/YP7x1fcPbzgdvCE948vDJ7fiFQhh3mKPIzrWmpigoYjEInumg3Eb4A1nfdloXS66F3eoHvaN3DSx/H5NQ57F9SqCvUxj1/TksOl/PGdLwAAAABJRU5ErkJggg=='); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"Book-a-demo-loginradius\"\n        title=\"Book-a-demo-loginradius\"\n        src=\"/static/a854d948ee1cb58ffca614fbff39f749/e5715/BD-Developers2-1024x310.png\"\n        srcset=\"/static/a854d948ee1cb58ffca614fbff39f749/a6d36/BD-Developers2-1024x310.png 650w,\n/static/a854d948ee1cb58ffca614fbff39f749/e5715/BD-Developers2-1024x310.png 768w,\n/static/a854d948ee1cb58ffca614fbff39f749/2bef9/BD-Developers2-1024x310.png 1024w\"\n        sizes=\"(max-width: 768px) 100vw, 768px\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        loading=\"lazy\"\n      />\n    </span></a></p>\n<style class=\"grvsc-styles\">\n  .grvsc-container {\n    overflow: auto;\n    -webkit-overflow-scrolling: touch;\n    padding-top: 1rem;\n    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));\n    padding-bottom: 1rem;\n    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));\n    border-radius: 8px;\n    border-radius: var(--grvsc-border-radius, 8px);\n    font-feature-settings: normal;\n  }\n  \n  .grvsc-code {\n    display: inline-block;\n    min-width: 100%;\n  }\n  \n  .grvsc-line {\n    display: inline-block;\n    box-sizing: border-box;\n    width: 100%;\n    padding-left: 1.5rem;\n    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));\n    padding-right: 1.5rem;\n    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));\n  }\n  \n  .grvsc-line-highlighted {\n    background-color: var(--grvsc-line-highlighted-background-color, transparent);\n    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, transparent);\n  }\n  \n</style>","frontmatter":{"date":"December 14, 2021","updated_date":null,"description":"LoginRadius’ cutting-edge single sign-on helps overcome all the challenges related to consumer experience and data integration.  Let’s understand how LoginRadius paves the path for a robust user experience by integrating PerfectMind.","title":"LoginRadius Offers PerfectMind Integration for a Seamless UX","tags":["authentication","federated sso","passwordless login"],"pinned":null,"coverImage":{"childImageSharp":{"fluid":{"aspectRatio":1.8018018018018018,"src":"/static/8fe54186ea558472cf50336523587257/14b42/perfectmind-cover.jpg","srcSet":"/static/8fe54186ea558472cf50336523587257/f836f/perfectmind-cover.jpg 200w,\n/static/8fe54186ea558472cf50336523587257/2244e/perfectmind-cover.jpg 400w,\n/static/8fe54186ea558472cf50336523587257/14b42/perfectmind-cover.jpg 800w,\n/static/8fe54186ea558472cf50336523587257/16310/perfectmind-cover.jpg 1024w","sizes":"(max-width: 800px) 100vw, 800px"}}},"author":{"id":"Jitender Agarwal","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":"Introduction You must have seen advertisements where a new product bought by a customer causes a stir in the entire neighbourhood. And…","fields":{"slug":"/growth/how-to-protect-consumer-social-identity/"},"html":"<h2 id=\"introduction\" style=\"position:relative;\"><a href=\"#introduction\" aria-label=\"introduction permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Introduction</h2>\n<p>You must have seen advertisements where a new product bought by a customer causes a stir in the entire neighbourhood. And suddenly, the product becomes the talk of the town and encourages other people to do the same.</p>\n<p>Take another example of an advertisement where a certain product, let's say an automatic washing machine, positions its owner as a woman who is smart, savvy and an environment enthusiast. </p>\n<p>All these marketing techniques are very common, and you can find them everywhere, promoting different products and brands. But the one thing that remains the same is the psychology behind this, i.e. social identity.</p>\n<p>Every consumer in the market has a social identity that affects their preferences and responses to a certain product. Social identity is influenced greatly by the community to which a person belongs. </p>\n<p>Therefore, to market and sell their products to people, organisations must have a proper understanding of the concept of consumer social identity. Organisations may receive favourable responses from their existing and potential consumers by tapping into the right social identity of a group. </p>\n<p>This theory holds an important place in the marketing world as it explains consumer behaviour and how organisations can use it. Below, we have mentioned factors that make this concept crucial for business organisations. </p>\n<h2 id=\"why-does-social-identity-matter\" style=\"position:relative;\"><a href=\"#why-does-social-identity-matter\" aria-label=\"why does social identity matter permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Why Does Social Identity Matter</h2>\n<p>A consumer's identity can affect a business in many ways. Proper identification, the community they belong to, and the context can be the difference between a successful and an unsuccessful marketing campaign.</p>\n<ul>\n<li>\n<p><strong>Tapping into customers’ desirable image</strong></p>\n<p>People are constantly using products and brands to create an image in today’s world. The image that a person wants to project depends heavily on the community they belong to. Intensive research on people's social behaviour around different groups and in different contexts can bring out how people want to position themselves in society. This can help companies create a brand image that fits their target audience's needs and desires. </p>\n</li>\n<li>\n<p><strong>Increased  engagement</strong></p>\n<p>Consumers who are more connected to their social identity and community are more likely to associate themselves with a brand that they think represents their image to other people. Companies can use this as an advantage to attract more and more people with strong consumer social identities to position their brand with a specific quality or a strong USP. </p>\n</li>\n</ul>\n<p><strong>Also Read</strong>: <a href=\"https://www.loginradius.com/blog/fuel/consumer-experience-and-privacy/\">Walking the Fine Line Between Consumer Experience and Privacy</a></p>\n<ul>\n<li>\n<p><strong>Customization</strong></p>\n<p>Consumer is king. Organisations have realized this in modern times. Due to globalization, competition has increased, and customers have many choices. The best way to get a customer's attention is by providing a product that suits the consumer's social identity. </p>\n<p>The marketing strategy and consumer experience can be customized according to the needs and demands of the target group. This gives the organisation an edge over the competitors.</p>\n</li>\n<li>\n<p><strong>Converting potential customers into real consumers</strong></p>\n<p>Before making a marketing strategy, companies conduct various researches to understand consumer behaviour and preferences. From data collection to preparing a strategy to sell the product, social identity and the context in which it regulates play an important role. In many cases, people who respond positively to a product may not do the same in different contexts or social situations. This provides an incorrect estimate of potential customers and incorrect judgement of the marketing strategy's success. </p>\n<p>To convert potential customers into real ones, organisations should observe their customers in different contexts, i.e. how their identity changes their reactions to the brand. Only then, the organisation will get a correct sense of consumer social identity. </p>\n</li>\n<li>\n<p><strong>Building brand loyalty</strong></p>\n<p>Many groups of people like to associate themselves with different brands to represent their social identity. This social identity can be changed easily. Marketing research, if done right,  can tell the organisations a lot about the social identity of a certain group. By tailoring your brand to give out a certain image that fits the social image of the target audience, colonies can create brand loyalty.  </p>\n</li>\n</ul>\n<h2 id=\"how-can-you-protect-a-consumers-social-identity\" style=\"position:relative;\"><a href=\"#how-can-you-protect-a-consumers-social-identity\" aria-label=\"how can you protect a consumers social identity 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 Can You Protect a Consumer’s Social Identity</h2>\n<p>Companies can gain insight into a person's social identity using various tools. This may include keeping information about a consumer's locality, age, social media, occupation, etc. This information collected by the organisations is sensitive and should be confidential. </p>\n<p>Consumers are very concerned about their information, where it goes and how it is used. They are willing to give the information to make the experience smoother and more customized, but in return, they want security and anonymity of their data.</p>\n<p>Implementing a robust CIAM solution can protect consumer data. These solutions provide authentication features like multi-factor and risk-based authentication to ensure that the consumer identities are always protected. The CIAM also allows customers to use their <a href=\"https://www.loginradius.com/social-login/\">social identity to access applications</a>. </p>\n<p>CIAM enables personalisation and privacy by providing self-care controls that enforce consent and privacy at various stages of operations.  It is beneficial for both businesses and customers. </p>\n<h3 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</h3>\n<p>Businesses can benefit from greater customer engagement and loyalty by providing customers with a platform that keeps their shared information safe. Customers, on the other hand, get the assurance of a secure and confidential experience. </p>\n<p>Today, data is king. Sensitive information about the social identity of consumers is used by organisations for many reasons, but it's also organisations' responsibility to maintain privacy. This can only be achieved by investing in the best CIAM. </p>\n<p><a href=\"https://www.loginradius.com/book-a-demo/\"><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 768px; \"\n    >\n      <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 30.307692307692307%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAGCAYAAADDl76dAAAACXBIWXMAAAsSAAALEgHS3X78AAABdElEQVQY002RO0/CUBzFG6PtbZWHCAmRmBB5P8vDII9SSC0omog4oAEGjZMO6OKEuLjoJ2Fx0cSBwUQnXZxcHPwux38LJA7nNvfec8+5v1tOCCiwpbbhye2BxbYgBMtgIRVioDRRsARGXxZUzLlEHmehBaesQ4rrEMPViYf2DR9nDGKkChbVICVqsMt1WJI1sHCFwhUsUIFohJH49TxECvRUjhDW2mAbB5iP6hB8hUkhiRPN5KIZYJdrsEYrcCSpmQqMm6/m9ylUhSulY7N5ivROB3L9GOlGF3Ktbc4zuz341UPw/uIk0ESbBjoSGlYIx8BfzjSwVmyCEYEUUmCPa3Bnd+hwC75yC95S05SxbolU/iEbOCFCpDexEfIioTNCNd6Tp6IlMnNuGeeDe3z//OLx5RWj5zFGT2O8fXxh/P4Ja6w6vSEFCnTIlW2YiDzhzX7ATFKojDlvjpBPcDF4QPdyiG5/iE7/BmfXd+hd3VKpCoG8fzxWw2+c+yTpAAAAAElFTkSuQmCC'); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"book-a-demo-Consultation\"\n        title=\"book-a-demo-Consultation\"\n        src=\"/static/fcc4c4b5dc38cc4528f99d09480f4eb2/e5715/book-a-demo-loginradius.png\"\n        srcset=\"/static/fcc4c4b5dc38cc4528f99d09480f4eb2/a6d36/book-a-demo-loginradius.png 650w,\n/static/fcc4c4b5dc38cc4528f99d09480f4eb2/e5715/book-a-demo-loginradius.png 768w,\n/static/fcc4c4b5dc38cc4528f99d09480f4eb2/63ff0/book-a-demo-loginradius.png 2887w\"\n        sizes=\"(max-width: 768px) 100vw, 768px\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        loading=\"lazy\"\n      />\n    </span></a></p>\n<style class=\"grvsc-styles\">\n  .grvsc-container {\n    overflow: auto;\n    -webkit-overflow-scrolling: touch;\n    padding-top: 1rem;\n    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));\n    padding-bottom: 1rem;\n    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));\n    border-radius: 8px;\n    border-radius: var(--grvsc-border-radius, 8px);\n    font-feature-settings: normal;\n  }\n  \n  .grvsc-code {\n    display: inline-block;\n    min-width: 100%;\n  }\n  \n  .grvsc-line {\n    display: inline-block;\n    box-sizing: border-box;\n    width: 100%;\n    padding-left: 1.5rem;\n    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));\n    padding-right: 1.5rem;\n    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));\n  }\n  \n  .grvsc-line-highlighted {\n    background-color: var(--grvsc-line-highlighted-background-color, transparent);\n    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, transparent);\n  }\n  \n</style>","frontmatter":{"date":"December 07, 2021","updated_date":null,"description":"Consumer is king. Organisations have realized this in modern times. Due to globalization, competition has increased, and customers have many choices. Therefore, the best way to get a customer's attention is by providing a product that suits the consumer's social identity.","title":"Why Consumers’ Social Identities Matter & How You Can Protect It?","tags":null,"pinned":null,"coverImage":{"childImageSharp":{"fluid":{"aspectRatio":2.0408163265306123,"src":"/static/224b3b3a57cf3107e02363393b8b0be2/14b42/social-id.jpg","srcSet":"/static/224b3b3a57cf3107e02363393b8b0be2/f836f/social-id.jpg 200w,\n/static/224b3b3a57cf3107e02363393b8b0be2/2244e/social-id.jpg 400w,\n/static/224b3b3a57cf3107e02363393b8b0be2/14b42/social-id.jpg 800w,\n/static/224b3b3a57cf3107e02363393b8b0be2/16310/social-id.jpg 1024w","sizes":"(max-width: 800px) 100vw, 800px"}}},"author":{"id":"Navanita Devi","github":null,"avatar":null}}}},{"node":{"excerpt":"Introduction Cloud computing has offered endless opportunities to diverse businesses in the modern, digitally advanced business landscape…","fields":{"slug":"/identity/loginradius-private-cloud-ciam-benefits/"},"html":"<h2 id=\"introduction\" style=\"position:relative;\"><a href=\"#introduction\" aria-label=\"introduction permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Introduction</h2>\n<p>Cloud computing has offered endless opportunities to diverse businesses in the modern, digitally advanced business landscape. </p>\n<p>Whether we talk about efficiency, agility, or security, enterprises are swiftly inching towards leveraging cloud services that thrive business success. </p>\n<p>Like every other industry, the CIAM (consumer identity and access management) offers enterprises and clients new horizons through rich experiences and world-class security. </p>\n<p>However, many businesses relying on conventional consumer IAMs aren’t aware that they’re not just putting their consumer information at risk but are also missing endless business opportunities by not considering a <a href=\"https://www.loginradius.com/\">cutting-edge cloud-based CIAM</a> solution. </p>\n<p>This post will talk about LoginRadius’ CIAM solution offering a private cloud that helps businesses take total control over every aspect of their business in the consumer identity and access management landscape. </p>\n<h2 id=\"what-is-loginradius-private-cloud-architecture\" style=\"position:relative;\"><a href=\"#what-is-loginradius-private-cloud-architecture\" aria-label=\"what is loginradius private 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>What is LoginRadius’ Private Cloud Architecture</h2>\n<p>LoginRadius’ single-tenant private cloud runs on a dedicated infrastructure. This means that the hardware, storage, and network are dedicated to a single client, and there are no neighbors to share hosted resources with. They may reside in a dedicated offsite data center or managed private cloud provider.</p>\n<p>In a single-tenancy architecture, each tenant gets their database. This way, data from each tenant remains separated from the other. Furthermore, the architecture is built to allow only one software instance per SaaS server.</p>\n<p><strong>Also Read</strong>: <a href=\"https://www.loginradius.com/blog/identity/single-tenant-vs-multi-tenant/\">Understanding the Difference Between Single-Tenant and Multi-Tenant Cloud</a></p>\n<h2 id=\"benefits-of-loginradius-single-tenant-private-cloud-ciam\" style=\"position:relative;\"><a href=\"#benefits-of-loginradius-single-tenant-private-cloud-ciam\" aria-label=\"benefits of loginradius single tenant private cloud ciam 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 LoginRadius' Single-Tenant Private Cloud CIAM</h2>\n<p>Since enterprises are rapidly <a href=\"https://www.loginradius.com/blog/identity/identity-management-in-cloud-computing/\">adopting cloud computing</a> capabilities, most prefer single tenancy over multi-tenancy for diverse reasons. Here are some reasons why LoginRadius’ single-tenant private cloud could be the ultimate solution for enterprises seeking agility, security, and efficiency in the CIAM landscape. </p>\n<ul>\n<li><strong>Quick and easy deployment:</strong> It can take months to build your solution or install one on-premises. And doing so takes time and resources from your engineering team, which will speed on identity functionality and best practices.LoginRadius can be deployed on any cloud (AWS, Azure, Google, or Alibaba Cloud) in mere days. Millions of customer identities can be migrated with no interruption in service.</li>\n<li><strong>Reliability:</strong> LoginRadius’ Single-tenant architecture is typically more reliable since one software instance serves one client. So the entire system remains unaffected by other cloud traffic and <a href=\"https://www.loginradius.com/scalability/\">peak load performance</a>. 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>Hassle-free migration:</strong> It is easier to migrate data from LoginRadius’ single-tenant architecture since the data store contains data from a single customer. One does not need to worry about mixing customer data or using complicated migration scripts.</li>\n<li><strong>Easy personalizations:</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 instance, server logs access to customers. The same level of ownership or customization cannot be provided for multi-tenant customers.</li>\n<li><strong>Stringent data security:</strong> LoginRadius’ single-tenant cloud architecture separates application instances and supporting components like database and infrastructure for each customer within the same provider. As a result, even if a customer with the same service provider experiences a data breach, other tenants remain protected. Hence, there is no way for others outside of your organization to access your data in case of vulnerability. </li>\n<li><strong>Stability:</strong> On-premises deployments are vulnerable to outages. They can also develop neglected issues because no one has the resources to address them. In contrast, LoginRadius’ single-tenant private cloud solution achieves 100% availability, with automated failovers and a network of servers from trusted cloud partners Microsoft, Google, Amazon, and others. Our uptime is unmatched in the industry.</li>\n</ul>\n<h2 id=\"final-thoughts\" style=\"position:relative;\"><a href=\"#final-thoughts\" aria-label=\"final thoughts 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>Final Thoughts</h2>\n<p>Enterprises that aren’t leveraging cutting-edge technology to handle consumer identities must immediately put their best foot forward in adopting cloud-based identity and access management solutions. </p>\n<p>LoginRadius’ private cloud helps enterprises deliver a flawless user experience backed with robust security that thrives business success.  If you wish to see the future of <a href=\"https://www.loginradius.com/\">cloud CIAM</a> in action, reach us for a personalized demo today. </p>\n<p><a href=\"https://www.loginradius.com/book-a-demo/\"><span\n      class=\"gatsby-resp-image-wrapper\"\n      style=\"position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 768px; \"\n    >\n      <span\n    class=\"gatsby-resp-image-background-image\"\n    style=\"padding-bottom: 30.307692307692307%; position: relative; bottom: 0; left: 0; background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAGCAYAAADDl76dAAAACXBIWXMAAAsSAAALEgHS3X78AAABdElEQVQY002RO0/CUBzFG6PtbZWHCAmRmBB5P8vDII9SSC0omog4oAEGjZMO6OKEuLjoJ2Fx0cSBwUQnXZxcHPwux38LJA7nNvfec8+5v1tOCCiwpbbhye2BxbYgBMtgIRVioDRRsARGXxZUzLlEHmehBaesQ4rrEMPViYf2DR9nDGKkChbVICVqsMt1WJI1sHCFwhUsUIFohJH49TxECvRUjhDW2mAbB5iP6hB8hUkhiRPN5KIZYJdrsEYrcCSpmQqMm6/m9ylUhSulY7N5ivROB3L9GOlGF3Ktbc4zuz341UPw/uIk0ESbBjoSGlYIx8BfzjSwVmyCEYEUUmCPa3Bnd+hwC75yC95S05SxbolU/iEbOCFCpDexEfIioTNCNd6Tp6IlMnNuGeeDe3z//OLx5RWj5zFGT2O8fXxh/P4Ja6w6vSEFCnTIlW2YiDzhzX7ATFKojDlvjpBPcDF4QPdyiG5/iE7/BmfXd+hd3VKpCoG8fzxWw2+c+yTpAAAAAElFTkSuQmCC'); background-size: cover; display: block;\"\n  ></span>\n  <img\n        class=\"gatsby-resp-image-image\"\n        alt=\"book-a-demo-loginradius\"\n        title=\"book-a-demo-loginradius\"\n        src=\"/static/fcc4c4b5dc38cc4528f99d09480f4eb2/e5715/book-a-demo-loginradius.png\"\n        srcset=\"/static/fcc4c4b5dc38cc4528f99d09480f4eb2/a6d36/book-a-demo-loginradius.png 650w,\n/static/fcc4c4b5dc38cc4528f99d09480f4eb2/e5715/book-a-demo-loginradius.png 768w,\n/static/fcc4c4b5dc38cc4528f99d09480f4eb2/63ff0/book-a-demo-loginradius.png 2887w\"\n        sizes=\"(max-width: 768px) 100vw, 768px\"\n        style=\"width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;\"\n        loading=\"lazy\"\n      />\n    </span></a></p>\n<style class=\"grvsc-styles\">\n  .grvsc-container {\n    overflow: auto;\n    -webkit-overflow-scrolling: touch;\n    padding-top: 1rem;\n    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));\n    padding-bottom: 1rem;\n    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));\n    border-radius: 8px;\n    border-radius: var(--grvsc-border-radius, 8px);\n    font-feature-settings: normal;\n  }\n  \n  .grvsc-code {\n    display: inline-block;\n    min-width: 100%;\n  }\n  \n  .grvsc-line {\n    display: inline-block;\n    box-sizing: border-box;\n    width: 100%;\n    padding-left: 1.5rem;\n    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));\n    padding-right: 1.5rem;\n    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));\n  }\n  \n  .grvsc-line-highlighted {\n    background-color: var(--grvsc-line-highlighted-background-color, transparent);\n    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, transparent);\n  }\n  \n</style>","frontmatter":{"date":"December 07, 2021","updated_date":null,"description":"Businesses relying on conventional consumer IAMs aren’t aware that they’re not just putting their consumer information at risk but are also missing endless business opportunities. This blog explains how LoginRadius’ CIAM solution offers a private cloud that helps businesses take total control over every aspect of their business.","title":"Take Control of Your CIAM Environment with LoginRadius' Private Cloud","tags":["cloud computing","ciam solutions","cx"],"pinned":null,"coverImage":{"childImageSharp":{"fluid":{"aspectRatio":1.7857142857142858,"src":"/static/0272c995e27fb5c8ffcfb377f3197685/14b42/lr-private-cloud.jpg","srcSet":"/static/0272c995e27fb5c8ffcfb377f3197685/f836f/lr-private-cloud.jpg 200w,\n/static/0272c995e27fb5c8ffcfb377f3197685/2244e/lr-private-cloud.jpg 400w,\n/static/0272c995e27fb5c8ffcfb377f3197685/14b42/lr-private-cloud.jpg 800w,\n/static/0272c995e27fb5c8ffcfb377f3197685/16310/lr-private-cloud.jpg 1024w","sizes":"(max-width: 800px) 100vw, 800px"}}},"author":{"id":"Manish Tiwari","github":null,"avatar":null}}}}]},"markdownRemark":{"excerpt":"Identity is evolving, and developers are at the forefront of this transformation. Every day brings a new learning—adapting to new standards…","fields":{"slug":"/identity/developer-first-identity-provider-loginradius/"},"html":"<p>Identity is evolving, and developers are at the forefront of this transformation. Every day brings a new learning—adapting to new standards and refining approaches to building secure, seamless experiences.</p>\n<p>We’re here to support developers on that journey. We know how important simplicity, efficiency, and well-structured documentation are when working with identity and access management solutions. That’s why we’ve redesigned the <a href=\"https://www.loginradius.com/\">LoginRadius website</a>—to be faster, more intuitive, and developer-first in every way.</p>\n<p>The goal? Having them spend less time searching and more time building.</p>\n<h2 id=\"whats-new-and-improved-on-the-loginradius-website\" style=\"position:relative;\"><a href=\"#whats-new-and-improved-on-the-loginradius-website\" aria-label=\"whats new and improved on the loginradius website permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>What’s New and Improved on the LoginRadius Website?</h2>\n<p>LoginRadius’ vision is to give developers a product that simplifies identity management so they can focus on building, deploying, and scaling their applications. To enhance this experience, we’ve spent the last few months redesigning our interface— making navigation more intuitive and reassuring that essential resources are easily accessible.</p>\n<p>Here’s a closer look at what’s new and why it’s important:</p>\n<h3 id=\"a-developer-friendly-dark-theme\" style=\"position:relative;\"><a href=\"#a-developer-friendly-dark-theme\" aria-label=\"a developer friendly dark theme permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>A Developer-Friendly Dark Theme</h3>\n<p><img src=\"/f46881583c7518a93bb24e94c32320de/a-developer-friendly-dark-theme.webp\" alt=\"This image shows how LoginRadius offers several authentication methods like traditional login, social login, passwordless login, passkeys and more in a dark mode.\">    </p>\n<p>Developers spend long hours working in dark-themed IDEs and terminals, so we’ve designed the LoginRadius experience to be developer-friendly and align with that preference.</p>\n<p>The new dark mode reduces eye strain, enhances readability, and provides a seamless transition between a coding environment and our platform. Our new design features a clean, modern aesthetic with a consistent color scheme and Barlow typography, ensuring better readability. High-quality graphics and icons are thoughtfully placed to enhance the content without adding visual clutter.</p>\n<p>So, whether you’re navigating our API docs or configuring authentication into your system, our improved interface will make those extended development hours more comfortable and efficient.</p>\n<h3 id=\"clear-categorization-for-loginradius-capabilities\" style=\"position:relative;\"><a href=\"#clear-categorization-for-loginradius-capabilities\" aria-label=\"clear categorization for loginradius capabilities permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Clear Categorization for LoginRadius Capabilities</h3>\n<p><img src=\"/e5358b82be414940f3fb146013845933/capabilities.webp\" alt=\"This image shows a breakdown of all the LoginRadius CIAM capabilities, including authentication, security, UX, scalability and multi-brand management.\"></p>\n<p>We’ve restructured our website to provide a straightforward breakdown of our customer identity and access management platform capabilities, helping you quickly find what you need:</p>\n<ul>\n<li>Authentication: Easily understand <a href=\"https://www.loginradius.com/blog/identity/authentication-option-for-your-product/\">how to choose the right login method</a>, from traditional passwords and OTPs to social login, federated SSO, and passkeys with few lines of code.</li>\n<li>Security: Implement no-code security features like bot detection, IP throttling, breached password alerts, DDoS protection, and adaptive MFA to safeguard user accounts.</li>\n<li>User Experience: Leverage AI builder, hosted pages, and drag-and-drop workflows to create smooth, branded sign-up and login experiences.</li>\n<li>High Performance &#x26; Scalability: Confidently scale with sub-100ms API response times, 100% uptime, 240K+ RPS, and 28+ global data center regions.</li>\n<li>Multi-Brand Management: Efficiently manage multiple identity apps, choosing isolated or shared data stores based on your brand’s unique needs.</li>\n</ul>\n<p>This structured layout ensures you can quickly understand each capability and how it integrates into your identity ecosystem.</p>\n<h3 id=\"developer-first-navigation\" style=\"position:relative;\"><a href=\"#developer-first-navigation\" aria-label=\"developer first navigation permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Developer-First Navigation</h3>\n<p><img src=\"/a8c155c2b6faf3d5f4b4de4e2b14d763/developers-menu.webp\" alt=\"This image shows the LoginRadius menu bar, highlighting the developer dropdown.\">   </p>\n<p>We’ve been analyzing developer workflows to identify how you access key resources. That’s why we redesigned our navigation with one goal in mind: to reduce clicks and make essential resources readily available.</p>\n<p>The new LoginRadius structure puts APIs, SDKs, and integration guides right at the menu bar under the Developers dropdown so you can get started faster. Our Products, Solutions, and Customer Services are also clearly categorized, helping development teams quickly find the right tools and make informed decisions.</p>\n<h3 id=\"quick-understanding-of-integration-benefits\" style=\"position:relative;\"><a href=\"#quick-understanding-of-integration-benefits\" aria-label=\"quick understanding of integration benefits permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Quick Understanding of Integration Benefits</h3>\n<p><img src=\"/b2f9a964a2da0ea83e2f8596b833bba7/we-support-your-tech-stack.webp\" alt=\"This image shows a list of popular programming languages and frameworks offered by LoginRadius.\"></p>\n<p>Developers now have a clear view of the tech stack available with LoginRadius, designed to support diverse business needs.</p>\n<p>Our platform offers pre-built SDKs for Node.js, Python, Java, and more, making CIAM integration seamless across popular programming languages and frameworks.</p>\n<h2 id=\"over-to-you-now\" style=\"position:relative;\"><a href=\"#over-to-you-now\" aria-label=\"over to you now permalink\" class=\"anchor before\"><svg aria-hidden=\"true\" focusable=\"false\" height=\"16\" version=\"1.1\" viewBox=\"0 0 16 16\" width=\"16\"><path fill-rule=\"evenodd\" d=\"M4 9h1v1H4c-1.5 0-3-1.69-3-3.5S2.55 3 4 3h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V8.59c.58-.45 1-1.27 1-2.09C10 5.22 8.98 4 8 4H4c-.98 0-2 1.22-2 2.5S3 9 4 9zm9-3h-1v1h1c1 0 2 1.22 2 2.5S13.98 12 13 12H9c-.98 0-2-1.22-2-2.5 0-.83.42-1.64 1-2.09V6.25c-1.09.53-2 1.84-2 3.25C6 11.31 7.55 13 9 13h4c1.45 0 3-1.69 3-3.5S14.5 6 13 6z\"></path></svg></a>Over to You Now!</h2>\n<p>Check out our <a href=\"https://www.loginradius.com/\">revamped LoginRadius website</a> and see how the improved experience makes it easier to build, scale, and secure your applications.</p>\n<p>Do not forget to explore the improved navigation and API documentation, and get started with our free trial today. We’re excited to see what you’ll build with LoginRadius!</p>\n<style class=\"grvsc-styles\">\n  .grvsc-container {\n    overflow: auto;\n    -webkit-overflow-scrolling: touch;\n    padding-top: 1rem;\n    padding-top: var(--grvsc-padding-top, var(--grvsc-padding-v, 1rem));\n    padding-bottom: 1rem;\n    padding-bottom: var(--grvsc-padding-bottom, var(--grvsc-padding-v, 1rem));\n    border-radius: 8px;\n    border-radius: var(--grvsc-border-radius, 8px);\n    font-feature-settings: normal;\n  }\n  \n  .grvsc-code {\n    display: inline-block;\n    min-width: 100%;\n  }\n  \n  .grvsc-line {\n    display: inline-block;\n    box-sizing: border-box;\n    width: 100%;\n    padding-left: 1.5rem;\n    padding-left: var(--grvsc-padding-left, var(--grvsc-padding-h, 1.5rem));\n    padding-right: 1.5rem;\n    padding-right: var(--grvsc-padding-right, var(--grvsc-padding-h, 1.5rem));\n  }\n  \n  .grvsc-line-highlighted {\n    background-color: var(--grvsc-line-highlighted-background-color, transparent);\n    box-shadow: inset var(--grvsc-line-highlighted-border-width, 4px) 0 0 0 var(--grvsc-line-highlighted-border-color, transparent);\n  }\n  \n</style>","frontmatter":{"date":"February 21, 2025","updated_date":null,"description":"LoginRadius’ vision is to give developers a product that simplifies identity management so they can focus on building, deploying, and scaling their applications. To enhance this experience, we’ve redesigned our website interface, making navigation more intuitive and reassuring that essential resources are easily accessible.","title":"Revamped & Ready: Introducing the New Developer-First LoginRadius Website","tags":["Developer tools","API","Identity Management","User Authentication"],"pinned":true,"coverImage":{"childImageSharp":{"fluid":{"aspectRatio":1.7857142857142858,"src":"/static/80b4e4fbe176a10a327d273504607f32/58556/hero-section.webp","srcSet":"/static/80b4e4fbe176a10a327d273504607f32/61e93/hero-section.webp 200w,\n/static/80b4e4fbe176a10a327d273504607f32/1f5c5/hero-section.webp 400w,\n/static/80b4e4fbe176a10a327d273504607f32/58556/hero-section.webp 800w,\n/static/80b4e4fbe176a10a327d273504607f32/99238/hero-section.webp 1200w,\n/static/80b4e4fbe176a10a327d273504607f32/7c22d/hero-section.webp 1600w,\n/static/80b4e4fbe176a10a327d273504607f32/1258b/hero-section.webp 2732w","sizes":"(max-width: 800px) 100vw, 800px"}}},"author":{"id":"Rakesh Soni","github":"oyesoni","avatar":"rakesh-soni.jpg"}}}},"pageContext":{"limit":6,"skip":330,"currentPage":56,"type":"///","numPages":161,"pinned":"ee8a4479-3471-53b1-bf62-d0d8dc3faaeb"}},"staticQueryHashes":["1171199041","1384082988","2100481360","23180105","528864852"]}