[{"data":1,"prerenderedAt":137},["ShallowReactive",2],{"content-paved-path-lift-and-shift-a-web-app-to-serverless-7-authentication-and-authorization-migration":3},{"markdown":4,"frontMatterAttributes":5,"bodyRaw":9,"contributorPaths":10,"menuType":12,"contentName":13,"slug":14,"readingTime":15,"menu":16,"nextDocItem":89,"previousDocItem":75},"\u003Cp>The original application handled the authentication and authorization by itself. There is a user directory in the database, with the passwords and emails for each of the users. There are APIs and middleware that take care of validating that the user is logged in before showing the application. All the logic for this is developed inside the Node.js\u002FExpress application.\u003C\u002Fp>\n\u003Cp>However, with the current migrated application every time you log in, you are logged out unexpectedly from the application. This is because the server code is responsible for handling the authentication and the authorization of the users, and now our server is running in an AWS Lambda function and functions are stateless. This means that there will be one function running per request—a request can load all the products in the landing page, get the details for a product, or log in to the site—and if you do something in one of these functions, the state is not shared across.\u003C\u002Fp>\n\u003Cp>To solve this, you must remove the authentication and authorization mechanisms from the function and use a service that can preserve the state across multiple invocations of the functions.\u003C\u002Fp>\n\u003Cp>There are many ways to solve this challenge. You can add a layer of authentication and session management with a database like Redis, or build a new microservice that is in charge of authentication and authorization that can handle the state, or use an existing managed service for this.\u003C\u002Fp>\n\u003Cp>Because of the migration requirements, we want to keep the cost as low as possible, with the fewest changes to the application. The better solution is to use an existing managed service to handle authentication and authorization.\u003C\u002Fp>\n\u003Cp>This demo uses Amazon Cognito, which provides user authentication and authorization to AWS resources in a managed, pay as you go way.\u003C\u002Fp>\n\u003Chr>\n\u003Cp>One rapid approach is to replace all the server code with calls to Amazon Cognito using the AWS SDK. But this adds complexity that can be replaced completely by just invoking Amazon Cognito APIs from the React application.\u003C\u002Fp>\n\u003Cimg src=\"\u002Fassets\u002Fexternal\u002Fpaved-path\u002Flift-and-shift-a-web-app-to-serverless\u002Fassets\u002Fexample-1.png\" \u002F>\n\n\u003Cp>For example, when a new user is registered, the application creates the user in the Amazon Cognito user pool directory, as well as in the application database. But when a user logs in to the web app, the application calls \u003Ca href=\"https:\u002F\u002Fdocs.aws.amazon.com\u002Fcognito\u002Flatest\u002Fdeveloperguide\u002Fcognito-reference.html\">Amazon Cognito API\u003C\u002Fa> directly from the AWS Amplify application. This way minimizes the amount of code needed.\u003C\u002Fp>\n\u003Cp>In the original application, all authenticated server APIs are secured with a middleware that validates that the user is authenticated by providing an access token. With the new setup that doesn’t change, but the token is generated by Amazon Cognito and then it can be validated in the backend.\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-js\">let auth = (req, res, next) =&gt; {\n    const token = req.headers.authorization;\n    const jwtToken = token.replace(&#39;Bearer &#39;, &#39;&#39;);\n\n    verifyToken(jwtToken)\n        .then((valid) =&gt; {\n            if (valid) {\n                getCognitoUser(jwtToken).then((email) =&gt; {\n                    User.findByEmail(email, (err, user) =&gt; {\n                        if (err) throw err;\n                        if (!user)\n                            return res.json({\n                                isAuth: false,\n                                error: true,\n                            });\n\n                        req.user = user;\n                        next();\n                    });\n                });\n            } else {\n                throw Error(&#39;Not valid Token&#39;);\n            }\n        })\n        .catch((error) =&gt; {\n            return res.json({\n                isAuth: false,\n                error: true,\n            });\n        });\n};\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>You can see how this is implemented step by step in this video at the top of the page.\u003C\u002Fp>\n",{"title":6,"order":7,"youtubeVideoID":8},"Authentication and authorization migration",7,"KRnZvbVT7uk","The original application handled the authentication and authorization by itself. There is a user directory in the database, with the passwords and emails for each of the users. There are APIs and middleware that take care of validating that the user is logged in before showing the application. All the logic for this is developed inside the Node.js\u002FExpress application.\n\nHowever, with the current migrated application every time you log in, you are logged out unexpectedly from the application. This is because the server code is responsible for handling the authentication and the authorization of the users, and now our server is running in an AWS Lambda function and functions are stateless. This means that there will be one function running per request—a request can load all the products in the landing page, get the details for a product, or log in to the site—and if you do something in one of these functions, the state is not shared across.\n\nTo solve this, you must remove the authentication and authorization mechanisms from the function and use a service that can preserve the state across multiple invocations of the functions.\n\nThere are many ways to solve this challenge. You can add a layer of authentication and session management with a database like Redis, or build a new microservice that is in charge of authentication and authorization that can handle the state, or use an existing managed service for this.\n\nBecause of the migration requirements, we want to keep the cost as low as possible, with the fewest changes to the application. The better solution is to use an existing managed service to handle authentication and authorization.\n\nThis demo uses Amazon Cognito, which provides user authentication and authorization to AWS resources in a managed, pay as you go way.\n\n---\n\nOne rapid approach is to replace all the server code with calls to Amazon Cognito using the AWS SDK. But this adds complexity that can be replaced completely by just invoking Amazon Cognito APIs from the React application.\n\n\u003Cimg src=\"\u002Fassets\u002Fexternal\u002Fpaved-path\u002Flift-and-shift-a-web-app-to-serverless\u002Fassets\u002Fexample-1.png\" \u002F>\n\nFor example, when a new user is registered, the application creates the user in the Amazon Cognito user pool directory, as well as in the application database. But when a user logs in to the web app, the application calls [Amazon Cognito API](https:\u002F\u002Fdocs.aws.amazon.com\u002Fcognito\u002Flatest\u002Fdeveloperguide\u002Fcognito-reference.html) directly from the AWS Amplify application. This way minimizes the amount of code needed.\n\nIn the original application, all authenticated server APIs are secured with a middleware that validates that the user is authenticated by providing an access token. With the new setup that doesn’t change, but the token is generated by Amazon Cognito and then it can be validated in the backend.\n\n```js\nlet auth = (req, res, next) => {\n    const token = req.headers.authorization;\n    const jwtToken = token.replace('Bearer ', '');\n\n    verifyToken(jwtToken)\n        .then((valid) => {\n            if (valid) {\n                getCognitoUser(jwtToken).then((email) => {\n                    User.findByEmail(email, (err, user) => {\n                        if (err) throw err;\n                        if (!user)\n                            return res.json({\n                                isAuth: false,\n                                error: true,\n                            });\n\n                        req.user = user;\n                        next();\n                    });\n                });\n            } else {\n                throw Error('Not valid Token');\n            }\n        })\n        .catch((error) => {\n            return res.json({\n                isAuth: false,\n                error: true,\n            });\n        });\n};\n```\n\nYou can see how this is implemented step by step in this video at the top of the page.\n",[11],"content\u002Fcontributors\u002Fmarcia-villalba.json","LESSON","Lift and shift a web app to serverless","\u002Fcontent\u002Fpaved-path\u002Flift-and-shift-a-web-app-to-serverless\u002F7-authentication-and-authorization-migration","3 min",[17,37,47,55,64,73,82,87,96,105,113,122,130],{"title":18,"content":19},"Introduction",[20],{"title":18,"order":21,"youtubeVideoID":22,"learningGoals":23,"resources":28,"time":33,"path":34,"id":35,"link":36},1,"O-hSs7aF7JE",[24,25,26,27],"Understand what lift and shift migrations are","Understand the benefits of serverless architecture","Learn how to migrate applications and databases from serverful to serverless","Learn patterns for migrating your services onto AWS.",[29],{"link":30,"text":31,"type":32},"https:\u002F\u002Fblog.marcia.dev\u002Flift-and-shift-a-web-app-to-serverless#heading-requirements-for-migration","Lift and shift to Serverless","text","2 min","1-introduction","1-introduction.md","\u002Fcontent\u002Fpaved-path\u002Flift-and-shift-a-web-app-to-serverless\u002F1-introduction",{"title":38,"content":39},"Guide",[40],{"title":41,"order":42,"time":43,"path":44,"id":45,"link":46},"Requirements for migration",2,"1 min","2-requirements-for-migration","2-requirements-for-migration.md","\u002Fcontent\u002Fpaved-path\u002Flift-and-shift-a-web-app-to-serverless\u002F2-requirements-for-migration",{"title":-1,"content":48},[49],{"title":50,"order":51,"time":43,"path":52,"id":53,"link":54},"Application overview",3,"3-application-overview","3-application-overview.md","\u002Fcontent\u002Fpaved-path\u002Flift-and-shift-a-web-app-to-serverless\u002F3-application-overview",{"title":-1,"content":56},[57],{"title":58,"order":59,"youtubeVideoID":60,"time":43,"path":61,"id":62,"link":63},"Database migration",4,"Mic2TGzzVXk","4-database-migration","4-database-migration.md","\u002Fcontent\u002Fpaved-path\u002Flift-and-shift-a-web-app-to-serverless\u002F4-database-migration",{"title":-1,"content":65},[66],{"title":67,"order":68,"youtubeVideoID":69,"time":33,"path":70,"id":71,"link":72},"Backend migration",5,"MvVaFPCdiZY","5-backend-migration","5-backend-migration.md","\u002Fcontent\u002Fpaved-path\u002Flift-and-shift-a-web-app-to-serverless\u002F5-backend-migration",{"title":-1,"content":74},[75],{"title":76,"order":77,"youtubeVideoID":78,"time":33,"path":79,"id":80,"link":81},"Web app migration",6,"gQn4XPfpdZE","6-webapp-migration","6-webapp-migration.md","\u002Fcontent\u002Fpaved-path\u002Flift-and-shift-a-web-app-to-serverless\u002F6-webapp-migration",{"title":-1,"content":83},[84],{"title":6,"order":7,"youtubeVideoID":8,"time":15,"path":85,"id":86,"link":14},"7-authentication-and-authorization-migration","7-authentication-and-authorization-migration.md",{"title":-1,"content":88},[89],{"title":90,"order":91,"youtubeVideoID":92,"time":33,"path":93,"id":94,"link":95},"Storage migration",9,"Z4frDpp4PcM","8-storage-migration","8-storage-migration.md","\u002Fcontent\u002Fpaved-path\u002Flift-and-shift-a-web-app-to-serverless\u002F8-storage-migration",{"title":-1,"content":97},[98],{"title":99,"order":100,"youtubeVideoID":101,"time":43,"path":102,"id":103,"link":104},"Testing this application",11,"U_7xD-o5mCA","9-testing-this-application","9-testing-this-application.md","\u002Fcontent\u002Fpaved-path\u002Flift-and-shift-a-web-app-to-serverless\u002F9-testing-this-application",{"title":-1,"content":106},[107],{"title":108,"order":109,"youtubeVideoID":101,"time":33,"path":110,"id":111,"link":112},"How much does this application cost?",12,"10-pricing-of-migrated-application","10-pricing-of-migrated-application.md","\u002Fcontent\u002Fpaved-path\u002Flift-and-shift-a-web-app-to-serverless\u002F10-pricing-of-migrated-application",{"title":-1,"content":114},[115],{"title":116,"order":117,"youtubeVideoID":118,"time":15,"path":119,"id":120,"link":121},"Performance analysis",13,"B0pDPSQcAf4","11-performance-analysis","11-performance-analysis.md","\u002Fcontent\u002Fpaved-path\u002Flift-and-shift-a-web-app-to-serverless\u002F11-performance-analysis",{"title":-1,"content":123},[124],{"title":125,"order":126,"time":43,"path":127,"id":128,"link":129},"Conclusion",14,"12-conclusion","12-conclusion.md","\u002Fcontent\u002Fpaved-path\u002Flift-and-shift-a-web-app-to-serverless\u002F12-conclusion",{"title":-1,"content":131},[132],{"title":133,"order":117,"time":43,"path":134,"id":135,"link":136},"Extra resources","13-extra-resources","13-extra-resources.md","\u002Fcontent\u002Fpaved-path\u002Flift-and-shift-a-web-app-to-serverless\u002F13-extra-resources",1792578866456]