From a5dd159fb068646b4784261c885a6e711803de70 Mon Sep 17 00:00:00 2001 From: maxmwang Date: Sat, 7 Oct 2023 20:10:48 -0700 Subject: [PATCH] Fix authentication routes --- backend/src/bootstrap/index.ts | 27 ++++----------------- backend/src/bootstrap/loaders/apollo.ts | 7 ++++-- backend/src/bootstrap/loaders/express.ts | 28 ++++++++++++++++++---- backend/src/bootstrap/loaders/index.ts | 29 ++++++++++++----------- backend/src/bootstrap/loaders/passport.ts | 17 +++++++------ backend/src/config.ts | 2 ++ backend/src/modules/user/typedefs/user.ts | 2 +- nginx.conf | 1 - 8 files changed, 62 insertions(+), 51 deletions(-) diff --git a/backend/src/bootstrap/index.ts b/backend/src/bootstrap/index.ts index 2453aebfc..bc55f54b9 100644 --- a/backend/src/bootstrap/index.ts +++ b/backend/src/bootstrap/index.ts @@ -1,5 +1,4 @@ import express from "express"; -import { expressMiddleware } from "@apollo/server/express4"; import loaders from "./loaders"; import { Config } from "../config"; import http from "http"; @@ -7,28 +6,12 @@ import http from "http"; export default async (config: Config) => { const app = express(); - const server = await loaders(app); - await server.start(); - - app.use( - "/graphql", - expressMiddleware(server, { - context: async ({ req }) => ({ - user: { - ...req.user, - isAuthenticated: req.isAuthenticated(), - logout: (callback: (err: any) => void) => req.logout(callback), - }, - }), - }) - ); + await loaders(app); const httpServer = http.createServer(app); - await new Promise((resolve) => - httpServer.listen({ port: config.port }, resolve) - ); - console.log( - `🚀 Server ready at http://localhost:${config.port}${config.graphqlPath}` - ); + await httpServer.listen(config.port) + + console.log(`🚀\tServer ready (in Docker network) at:\thttp://localhost:${config.port}${config.backendPath}`); + console.log(`\tServer ready (in Host network) at:\thttp://localhost:8080${config.backendPath}`) }; diff --git a/backend/src/bootstrap/loaders/apollo.ts b/backend/src/bootstrap/loaders/apollo.ts index 7fa3985c6..24323ac92 100644 --- a/backend/src/bootstrap/loaders/apollo.ts +++ b/backend/src/bootstrap/loaders/apollo.ts @@ -5,8 +5,11 @@ import { ApolloServerPluginLandingPageLocalDefault } from '@apollo/server/plugin export default async () => { const schema = buildSchema(); - return new ApolloServer({ + const server = new ApolloServer({ schema, - plugins: [ApolloServerPluginLandingPageLocalDefault({ includeCookies: true })] + plugins: [ApolloServerPluginLandingPageLocalDefault({ includeCookies: true })], }); + await server.start(); + + return server; }; diff --git a/backend/src/bootstrap/loaders/express.ts b/backend/src/bootstrap/loaders/express.ts index 0874e2def..6502f8d29 100644 --- a/backend/src/bootstrap/loaders/express.ts +++ b/backend/src/bootstrap/loaders/express.ts @@ -1,13 +1,17 @@ -import type { Application } from "express"; -import { json } from "express"; +import { type Application, json } from "express"; +import cookieParser from 'cookie-parser'; import cors from "cors"; import helmet from "helmet"; +import type { ApolloServer } from "@apollo/server"; +import { expressMiddleware } from "@apollo/server/express4"; +import passportLoader from "./passport"; import { config } from "../../config"; -export default async (app: Application) => { +export default async (app: Application, server: ApolloServer) => { // Body parser only needed during POST on the graphQL path - app.use(config.graphqlPath, json()); + app.use(json()); + app.use(cookieParser()); // Cors configuration app.use(cors({ @@ -17,4 +21,20 @@ export default async (app: Application) => { // Sets various HTTP headers to help protect our app app.use(helmet()); + + // load authentication + passportLoader(app); + + app.use( + config.graphqlPath, + expressMiddleware(server, { + context: async ({ req }) => ({ + user: { + ...req.user, + isAuthenticated: req.isAuthenticated(), + logout: (callback: (err: any) => void) => req.logout(callback), + }, + }), + }) + ); }; diff --git a/backend/src/bootstrap/loaders/index.ts b/backend/src/bootstrap/loaders/index.ts index 561f3a06e..91f009e36 100644 --- a/backend/src/bootstrap/loaders/index.ts +++ b/backend/src/bootstrap/loaders/index.ts @@ -1,25 +1,26 @@ -import type { Application } from "express"; -import type { ApolloServer } from "@apollo/server"; +import { type Application, Router } from "express"; +import { config } from "../../config"; // loaders import apolloLoader from "./apollo"; import expressLoader from "./express"; import mongooseLoader from "./mongoose"; -import passportLoader from './passport'; -export default async (app: Application): Promise => { - // Load everything related to express - console.log("Booting up express..."); - await expressLoader(app); +export default async (root: Application): Promise => { + const app = Router() as Application; - console.log("Booting up passport..."); - await passportLoader(app); - - // Connect to mongoose + // connect to mongoose console.log("Booting up mongo..."); await mongooseLoader(); - // load apollo server config - console.log("Booting up apollo..."); - return apolloLoader(); + // load apollo server config. must be loaded before express + console.log("Loading apollo..."); + const server = await apolloLoader(); + + // load everything related to express. depends on apollo + console.log("Loading express..."); + await expressLoader(app, server); + + // append backend path to all routes + root.use(config.backendPath, app); }; diff --git a/backend/src/bootstrap/loaders/passport.ts b/backend/src/bootstrap/loaders/passport.ts index d0d1bd9bc..2025b276c 100644 --- a/backend/src/bootstrap/loaders/passport.ts +++ b/backend/src/bootstrap/loaders/passport.ts @@ -12,13 +12,15 @@ import GoogleStrategy from "passport-google-oauth20"; import { UserModel } from "../../db/user"; import { config } from "../../config"; -// routes need to be added as authorized origins/redirect uris in google cloud console const LOGIN_ROUTE = "/login"; -const CALLBACK_ROUTE = "/login/callback"; +const LOGIN_REDIRECT_ROUTE = "/login/redirect"; const LOGOUT_ROUTE = "/logout"; -const SUCCESS_REDIRECT = "/graphql"; -const FAILURE_REDIRECT = "/fail"; +// route need to be added as authorized origins/redirect uris in google cloud console +const LOGIN_REDIRECT = config.backendPath + "/login/redirect"; + +const SUCCESS_REDIRECT = config.backendPath + config.graphqlPath; +const FAILURE_REDIRECT = config.backendPath + "/fail"; const SCOPE = ['profile', 'email'] @@ -32,7 +34,8 @@ export default async (app: Application) => { cookie: { secure: !config.isDev, httpOnly: true, - maxAge: 1000 * 60 * 60 // 1 hour + maxAge: 1000 * 60 * 60, // 1 hour + sameSite: 'lax', }, rolling: true, })); @@ -52,7 +55,7 @@ export default async (app: Application) => { accessType: 'offline', prompt: 'consent', })); - app.get(CALLBACK_ROUTE, passport.authenticate('google', { + app.get(LOGIN_REDIRECT_ROUTE, passport.authenticate('google', { failureRedirect: FAILURE_REDIRECT, // failureMessage: "failed", successRedirect: SUCCESS_REDIRECT, @@ -77,7 +80,7 @@ export default async (app: Application) => { passport.use(new GoogleStrategy.Strategy({ clientID: config.GOOGLE_CLIENT_ID, clientSecret: config.GOOGLE_CLIENT_SECRET, - callbackURL: CALLBACK_ROUTE, + callbackURL: LOGIN_REDIRECT, scope: SCOPE, state: true, }, async (accessToken, refreshToken, profile, done) => { diff --git a/backend/src/config.ts b/backend/src/config.ts index e66e436d6..5bb932f40 100644 --- a/backend/src/config.ts +++ b/backend/src/config.ts @@ -15,6 +15,7 @@ const env = (name: string): string => { export interface Config { port: number; url: string; + backendPath: string; graphqlPath: string; isDev: boolean; mongoDB: { @@ -29,6 +30,7 @@ export interface Config { export const config: Config = { port: +env("PORT"), url: env("URL"), + backendPath: env("BACKEND_PATH"), graphqlPath: env("GRAPHQL_PATH"), isDev: env("NODE_ENV") === "development", mongoDB: { diff --git a/backend/src/modules/user/typedefs/user.ts b/backend/src/modules/user/typedefs/user.ts index dafb558e4..61e31da44 100644 --- a/backend/src/modules/user/typedefs/user.ts +++ b/backend/src/modules/user/typedefs/user.ts @@ -2,7 +2,7 @@ import { gql } from "graphql-tag"; const typedef = gql` """ - User accout info. + User account info. """ type User { email: String! diff --git a/nginx.conf b/nginx.conf index a87bdf6c3..016c747ab 100644 --- a/nginx.conf +++ b/nginx.conf @@ -5,7 +5,6 @@ server { # Backend location /api { - rewrite ^/api(.*)$ $1 break; proxy_set_header Host $http_host; proxy_pass http://backend:5001; }