[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"navigation":3,"\u002Fblog\u002Fsingle-sign-on-sso-implementation-using-passportjs-in-typescript":58,"\u002Fblog\u002Fsingle-sign-on-sso-implementation-using-passportjs-in-typescript-surround":440},[4],{"title":5,"path":6,"stem":7,"children":8,"page":57},"Blog","\u002Fblog","blog",[9,13,17,21,25,29,33,37,41,45,49,53],{"title":10,"path":11,"stem":12},"A Guide to Server-Side Rendering (SSR) with Vite and React.js","\u002Fblog\u002Fa-guide-to-server-side-rendering-ssr-with-vite-and-reactjs","blog\u002Fa-guide-to-server-side-rendering-ssr-with-vite-and-reactjs",{"title":14,"path":15,"stem":16},"🔄 Background DNS Refresh in Node.js: Keeping Cached IPs Updated","\u002Fblog\u002Fbackground-dns-refresh-in-nodejs-keeping-cached-ips-updated","blog\u002Fbackground-dns-refresh-in-nodejs-keeping-cached-ips-updated",{"title":18,"path":19,"stem":20},"Comprehensive Guide: Encrypting Images, Uploading to Cloudinary, and Serving Them Securely","\u002Fblog\u002Fcomprehensive-guide-encrypting-images-uploading-to-cloudinary-and-serving-them-securely","blog\u002Fcomprehensive-guide-encrypting-images-uploading-to-cloudinary-and-serving-them-securely",{"title":22,"path":23,"stem":24},"Comprehensive Guide to Using Uploadthing with Express and Typescript","\u002Fblog\u002Fcomprehensive-guide-to-using-uploadthing-with-express-and-typescript","blog\u002Fcomprehensive-guide-to-using-uploadthing-with-express-and-typescript",{"title":26,"path":27,"stem":28},"🌐 DNS Caching in Node.js: Supercharge Your App's Speed & Reliability 🚀","\u002Fblog\u002Fdns-caching-in-nodejs-supercharge-your-apps-speed-and-reliability","blog\u002Fdns-caching-in-nodejs-supercharge-your-apps-speed-and-reliability",{"title":30,"path":31,"stem":32},"Enhancing Redis for Message Queues: Using External Databases for Payload Storage","\u002Fblog\u002Fenhancing-redis-for-message-queues-using-external-databases-for-payload-storage","blog\u002Fenhancing-redis-for-message-queues-using-external-databases-for-payload-storage",{"title":34,"path":35,"stem":36},"Full Stack Learning Management System (LMS) with MERN Stack: A Complete Guide","\u002Fblog\u002Ffull-stack-learning-management-system-lms-with-mern-stack-a-complete-guide","blog\u002Ffull-stack-learning-management-system-lms-with-mern-stack-a-complete-guide",{"title":38,"path":39,"stem":40},"Getting Started with Redis: Elevating Your Web Applications","\u002Fblog\u002Fgetting-started-with-redis-elevating-your-web-applications","blog\u002Fgetting-started-with-redis-elevating-your-web-applications",{"title":42,"path":43,"stem":44},"How Queues Enhance Your Application Development Process","\u002Fblog\u002Fhow-queues-enhance-your-application-development-process","blog\u002Fhow-queues-enhance-your-application-development-process",{"title":46,"path":47,"stem":48},"Next-Gen E-Learning: Transforming Education for Students and Creators","\u002Fblog\u002Fnext-gen-e-learning-transforming-education-for-students-and-creators","blog\u002Fnext-gen-e-learning-transforming-education-for-students-and-creators",{"title":50,"path":51,"stem":52},"Single Sign-On (SSO) Implementation Using Passport.js in TypeScript","\u002Fblog\u002Fsingle-sign-on-sso-implementation-using-passportjs-in-typescript","blog\u002Fsingle-sign-on-sso-implementation-using-passportjs-in-typescript",{"title":54,"path":55,"stem":56},"Using Multer for Local File Uploads: Benefits, Trade-offs, and Cloud Transfer Integration","\u002Fblog\u002Fusing-multer-for-local-file-uploads-benefits-trade-offs-and-cloud-transfer-integration","blog\u002Fusing-multer-for-local-file-uploads-benefits-trade-offs-and-cloud-transfer-integration",false,{"id":59,"title":50,"author":60,"body":66,"date":432,"description":433,"extension":434,"image":435,"meta":436,"minRead":414,"navigation":437,"path":51,"seo":438,"stem":52,"__hash__":439},"blog\u002Fblog\u002Fsingle-sign-on-sso-implementation-using-passportjs-in-typescript.md",{"name":61,"to":62,"username":63,"avatar":64},"Sachin Thapa","https:\u002F\u002Fsachinthapa.hashnode.dev\u002F","sachinthapa572",{"src":65,"alt":61},"https:\u002F\u002Fcdn.hashnode.com\u002Fres\u002Fhashnode\u002Fimage\u002Fupload\u002Fv1733546636355\u002Fa4ae8ce5-eb4c-4ed8-ab9d-15a4b8f32ea5.png",{"type":67,"value":68,"toc":413},"minimark",[69,73,81,84,95,98,104,111,114,125,131,134,141,147,149,155,161,164,170,172,178,181,187,193,196,202,205,207,213,216,221,227,229,235,238,244,250,252,258,264,270,276,278,284,287,292,298,300,306,309,314,320,327,333,335,341,348,354,361,367,369,375,386,392,394,400,407],[70,71,72],"p",{},"Implementing Single Sign-On (SSO) in your application enhances user experience by allowing seamless access across multiple platforms with a single set of credentials. In Node.js applications, the Passport middleware simplifies this process by providing a flexible and modular authentication framework. This guide focuses on using Passport.js with TypeScript to maintain type safety and robust application architecture.",[74,75,77],"h2",{"id":76},"what-is-passportjs",[78,79,80],"strong",{},"What Is Passport.js?",[70,82,83],{},"Passport.js is an authentication middleware for Node.js that supports various strategies, including social logins (e.g., Google, GitHub) and traditional username-password mechanisms. It is modular, allowing developers to choose specific strategies as needed.",[70,85,86,87,94],{},"For more details, visit ",[88,89,93],"a",{"href":90,"rel":91},"https:\u002F\u002Fwww.passportjs.org\u002Fdocs",[92],"nofollow","Passport.js documentation",".",[96,97],"hr",{},[74,99,101],{"id":100},"steps-to-implement-sso-in-typescript",[78,102,103],{},"Steps to Implement SSO in TypeScript",[105,106,108],"h3",{"id":107},"install-required-dependencies",[78,109,110],{},"Install Required Dependencies",[70,112,113],{},"Begin by installing the necessary packages:",[115,116,121],"pre",{"className":117,"code":119,"language":120},[118],"language-text","npm install passport passport-google-oauth20 passport-github2 express-session @types\u002Fpassport @types\u002Fexpress-session\n","text",[122,123,119],"code",{"__ignoreMap":124},"",[105,126,128],{"id":127},"initialize-passport",[78,129,130],{},"Initialize Passport",[70,132,133],{},"Configure Passport and session handling in your application.",[135,136,138],"h4",{"id":137},"code-implementation",[78,139,140],{},"Code Implementation:",[115,142,145],{"className":143,"code":144,"language":120},[118],"import express, { Application, Request, Response, NextFunction } from \"express\";\nimport session from \"express-session\";\nimport passport from \"passport\";\n\nconst app: Application = express();\n\napp.use(\n  session({\n    secret: \"your_secret_key\",\n    resave: false,\n    saveUninitialized: true,\n  })\n);\n\napp.use(passport.initialize());\napp.use(passport.session());\n",[122,146,144],{"__ignoreMap":124},[96,148],{},[105,150,152],{"id":151},"configure-authentication-strategies",[78,153,154],{},"Configure Authentication Strategies",[135,156,158],{"id":157},"google-strategy",[78,159,160],{},"Google Strategy",[70,162,163],{},"To authenticate users via Google, configure the Google strategy:",[115,165,168],{"className":166,"code":167,"language":120},[118],"import { Strategy as GoogleStrategy } from \"passport-google-oauth20\";\n\npassport.use(\n  new GoogleStrategy(\n    {\n      clientID: process.env.GOOGLE_CLIENT_ID!,\n      clientSecret: process.env.GOOGLE_CLIENT_SECRET!,\n      callbackURL: \"http:\u002F\u002Flocalhost:3000\u002Fauth\u002Fgoogle\u002Fcallback\",\n    },\n    async (\n      accessToken: string,\n      refreshToken: string,\n      profile: any,\n      done: Function\n    ) => {\n      try {\n        \u002F\u002F Replace with your DB logic\n        const user = await findOrCreateUser({ googleId: profile.id });\n        return done(null, user);\n      } catch (error) {\n        return done(error);\n      }\n    }\n  )\n);\n",[122,169,167],{"__ignoreMap":124},[96,171],{},[135,173,175],{"id":174},"github-strategy",[78,176,177],{},"GitHub Strategy",[70,179,180],{},"Similarly, configure the GitHub strategy:",[115,182,185],{"className":183,"code":184,"language":120},[118],"import { Strategy as GitHubStrategy } from \"passport-github2\";\n\npassport.use(\n  new GitHubStrategy(\n    {\n      clientID: process.env.GITHUB_CLIENT_ID!,\n      clientSecret: process.env.GITHUB_CLIENT_SECRET!,\n      callbackURL: \"http:\u002F\u002Flocalhost:3000\u002Fauth\u002Fgithub\u002Fcallback\",\n    },\n    async (\n      accessToken: string,\n      refreshToken: string,\n      profile: any,\n      done: Function\n    ) => {\n      try {\n        \u002F\u002F Replace with your DB logic\n        const user = await findOrCreateUser({ githubId: profile.id });\n        return done(null, user);\n      } catch (error) {\n        return done(error);\n      }\n    }\n  )\n);\n",[122,186,184],{"__ignoreMap":124},[105,188,190],{"id":189},"local-strategy",[78,191,192],{},"Local Strategy",[70,194,195],{},"For applications that require traditional username and password authentication, Passport.js provides the Local Strategy:",[115,197,200],{"className":198,"code":199,"language":120},[118],"import { Strategy as LocalStrategy } from \"passport-local\";\n\npassport.use(\n  new LocalStrategy((username, password, done) => {\n    \u002F\u002F Replace with your user retrieval and password verification logic\n    const user = getUserByUsername(username);\n    if (!user || !verifyPassword(user, password)) {\n      return done(null, false, { message: \"Invalid credentials\" });\n    }\n    return done(null, user);\n  })\n);\n",[122,201,199],{"__ignoreMap":124},[70,203,204],{},"By utilizing the Local Strategy, you can manage authentication within your application without relying on external providers. This approach is beneficial when you prefer to handle user credentials directly.",[96,206],{},[105,208,210],{"id":209},"serialization-and-deserialization",[78,211,212],{},"Serialization and Deserialization",[70,214,215],{},"Handle session serialization and deserialization to maintain user sessions.",[135,217,219],{"id":218},"code-implementation-1",[78,220,140],{},[115,222,225],{"className":223,"code":224,"language":120},[118],"passport.serializeUser((user: any, done: Function) => {\n  done(null, user.id);\n});\n\npassport.deserializeUser(async (id: string, done: Function) => {\n  try {\n    const user = await findUserById(id); \u002F\u002F Replace with your DB logic\n    done(null, user);\n  } catch (error) {\n    done(error);\n  }\n});\n",[122,226,224],{"__ignoreMap":124},[96,228],{},[105,230,232],{"id":231},"define-routes",[78,233,234],{},"Define Routes",[70,236,237],{},"Set up routes for initiating authentication and handling callbacks.",[135,239,241],{"id":240},"google-authentication-routes",[78,242,243],{},"Google Authentication Routes:",[115,245,248],{"className":246,"code":247,"language":120},[118],"app.get(\n  \"\u002Fauth\u002Fgoogle\",\n  passport.authenticate(\"google\", { scope: [\"profile\", \"email\"] })\n);\n\napp.get(\n  \"\u002Fauth\u002Fgoogle\u002Fcallback\",\n  passport.authenticate(\"google\", { failureRedirect: \"\u002F\" }),\n  (req: Request, res: Response) => {\n    res.redirect(\"\u002Fdashboard\");\n  }\n);\n",[122,249,247],{"__ignoreMap":124},[96,251],{},[135,253,255],{"id":254},"github-authentication-routes",[78,256,257],{},"GitHub Authentication Routes:",[115,259,262],{"className":260,"code":261,"language":120},[118],"app.get(\n  \"\u002Fauth\u002Fgithub\",\n  passport.authenticate(\"github\", { scope: [\"user:email\"] })\n);\n\napp.get(\n  \"\u002Fauth\u002Fgithub\u002Fcallback\",\n  passport.authenticate(\"github\", { failureRedirect: \"\u002F\" }),\n  (req: Request, res: Response) => {\n    res.redirect(\"\u002Fdashboard\");\n  }\n);\n",[122,263,261],{"__ignoreMap":124},[105,265,267],{"id":266},"local-authentication-routes",[78,268,269],{},"Local Authentication Routes:",[115,271,274],{"className":272,"code":273,"language":120},[118],"app.post(\n  \"\u002Flogin\",\n  passport.authenticate(\"local\", { failureRedirect: \"\u002F\" }),\n  (req: Request, res: Response) => {\n    res.redirect(\"\u002Fdashboard\");\n  }\n);\n",[122,275,273],{"__ignoreMap":124},[96,277],{},[105,279,281],{"id":280},"handle-user-logout",[78,282,283],{},"Handle User Logout",[70,285,286],{},"Allow users to log out and securely end their sessions.",[135,288,290],{"id":289},"code-implementation-2",[78,291,140],{},[115,293,296],{"className":294,"code":295,"language":120},[118],"app.get(\"\u002Flogout\", (req: Request, res: Response, next: NextFunction) => {\n  req.logout((err) => {\n    if (err) {\n      return next(err);\n    }\n    res.redirect(\"\u002F\");\n  });\n});\n",[122,297,295],{"__ignoreMap":124},[96,299],{},[105,301,303],{"id":302},"handling-user-authentication",[78,304,305],{},"Handling User Authentication",[70,307,308],{},"Protect routes that require authentication by checking if the user is authenticated, implementing a middleware function.",[135,310,312],{"id":311},"code-implementation-3",[78,313,140],{},[115,315,318],{"className":316,"code":317,"language":120},[118],"function isAuthenticated(req: Request, res: Response, next: NextFunction) {\n  if (req.isAuthenticated()) {\n    return next();\n  }\n  res.redirect(\"\u002F\");\n}\n",[122,319,317],{"__ignoreMap":124},[70,321,322,323,326],{},"Now, you can use the ",[122,324,325],{},"isAuthenticated"," middleware to protect routes that require authentication:",[115,328,331],{"className":329,"code":330,"language":120},[118],"app.get(\"\u002Fdashboard\", isAuthenticated, (req: Request, res: Response) => {\n  res.send(\"Dashboard\", { user: req.user });\n});\n",[122,332,330],{"__ignoreMap":124},[96,334],{},[105,336,338],{"id":337},"environment-variables",[78,339,340],{},"Environment Variables",[70,342,343,344,347],{},"Store sensitive credentials in an ",[122,345,346],{},".env"," file:",[115,349,352],{"className":350,"code":351,"language":120},[118],"GOOGLE_CLIENT_ID=your_google_client_id\nGOOGLE_CLIENT_SECRET=your_google_client_secret\nGITHUB_CLIENT_ID=your_github_client_id\nGITHUB_CLIENT_SECRET=your_github_client_secret\n",[122,353,351],{"__ignoreMap":124},[70,355,356,357,360],{},"Use a library like ",[122,358,359],{},"dotenv"," to load them:",[115,362,365],{"className":363,"code":364,"language":120},[118],"import dotenv from \"dotenv\";\ndotenv.config();\n",[122,366,364],{"__ignoreMap":124},[96,368],{},[105,370,372],{"id":371},"replace-placeholder-functions",[78,373,374],{},"Replace Placeholder Functions",[70,376,377,378,381,382,385],{},"Replace the placeholder functions ",[122,379,380],{},"findOrCreateUser"," and ",[122,383,384],{},"findUserById"," with actual implementations for interacting with your database:",[115,387,390],{"className":388,"code":389,"language":120},[118],"async function findOrCreateUser(query: object): Promise\u003Cany> {\n  \u002F\u002F Example: Interact with database to find or create user\n  return {};\n}\n\nasync function findUserById(id: string): Promise\u003Cany> {\n  \u002F\u002F Example: Fetch user by ID from database\n  return {};\n}\n",[122,391,389],{"__ignoreMap":124},[96,393],{},[74,395,397],{"id":396},"conclusion",[78,398,399],{},"Conclusion",[70,401,402,403,94],{},"By leveraging Passport.js in TypeScript, you can create a robust SSO system with type safety, flexibility, and support for multiple authentication providers like Google and GitHub. For additional configurations, refer to the ",[88,404,93],{"href":405,"rel":406},"https:\u002F\u002Fwww.passportjs.org\u002Fdocs\u002F",[92],[70,408,409],{},[410,411,412],"em",{},"Implementing SSO not only enhances user convenience but also strengthens security by centralizing authentication processes.",{"title":124,"searchDepth":414,"depth":414,"links":415},2,[416,417,431],{"id":76,"depth":414,"text":80},{"id":100,"depth":414,"text":103,"children":418},[419,421,422,423,424,425,426,427,428,429,430],{"id":107,"depth":420,"text":110},3,{"id":127,"depth":420,"text":130},{"id":151,"depth":420,"text":154},{"id":189,"depth":420,"text":192},{"id":209,"depth":420,"text":212},{"id":231,"depth":420,"text":234},{"id":266,"depth":420,"text":269},{"id":280,"depth":420,"text":283},{"id":302,"depth":420,"text":305},{"id":337,"depth":420,"text":340},{"id":371,"depth":420,"text":374},{"id":396,"depth":414,"text":399},"2025-01-17","Learn how to implement Single Sign-On (SSO) in Node.js using Passport.js and TypeScript for enhanced user experience and secure authentication","md","https:\u002F\u002Fcdn.hashnode.com\u002Fres\u002Fhashnode\u002Fimage\u002Fupload\u002Fv1737137497543\u002F4c9f6a01-d26c-439c-a276-50251cdae746.png",{},true,{"title":50,"description":433},"30Q9zQwLo0epE_0Phzum5kAUmTiIT_EtEkC2H2zFZ_0",[441,443],{"title":46,"path":47,"stem":48,"description":442,"children":-1},"Explore an e-learning platform empowering creators and enhancing student engagement with interactive, monetizable educational experiences",{"title":54,"path":55,"stem":56,"description":444,"children":-1},"Multer offers benefits like easy debugging and processing flexibility but has trade-offs when transferring files to the cloud after local uploads"]