initial setup for google signin signup integration

This commit is contained in:
Sheen Capadngan
2023-04-25 23:47:46 +08:00
parent 3b00df6662
commit 007e8c4442
19 changed files with 455 additions and 16 deletions
+3
View File
@@ -12,6 +12,8 @@ export const getJwtRefreshSecret = () => infisical.get('JWT_REFRESH_SECRET')!;
export const getJwtServiceSecret = () => infisical.get('JWT_SERVICE_SECRET')!;
export const getJwtSignupLifetime = () => infisical.get('JWT_SIGNUP_LIFETIME')! || '15m';
export const getJwtSignupSecret = () => infisical.get('JWT_SIGNUP_SECRET')!;
export const getJwtProviderAuthSecret = () => infisical.get('JWT_PROVIDER_AUTH_SECRET')!;
export const getJwtProviderAuthLifetime = () => infisical.get('JWT_PROVIDER_AUTH_LIFETIME')! || '15m';
export const getMongoURL = () => infisical.get('MONGO_URL')!;
export const getNodeEnv = () => infisical.get('NODE_ENV')! || 'production';
export const getVerboseErrorOutput = () => infisical.get('VERBOSE_ERROR_OUTPUT')! === 'true' && true;
@@ -32,6 +34,7 @@ export const getClientSlugVercel = () => infisical.get('CLIENT_SLUG_VERCEL')!;
export const getPostHogHost = () => infisical.get('POSTHOG_HOST')! || 'https://app.posthog.com';
export const getPostHogProjectApiKey = () => infisical.get('POSTHOG_PROJECT_API_KEY')! || 'phc_nSin8j5q2zdhpFDI1ETmFNUIuTG4DwKVyIigrY10XiE';
export const getSentryDSN = () => infisical.get('SENTRY_DSN')!;
export const getSessionSecret = () => infisical.get('SESSION_SECRET')!;
export const getSiteURL = () => infisical.get('SITE_URL')!;
export const getSmtpHost = () => infisical.get('SMTP_HOST')!;
export const getSmtpSecure = () => infisical.get('SMTP_SECURE')! === 'true' || false;
@@ -267,3 +267,7 @@ export const getNewToken = async (req: Request, res: Response) => {
});
}
};
export const handleGoogleCallback = (req: Request, res: Response) => {
res.redirect(`/login/provider/success?token=${encodeURIComponent(req.providerAuthToken)}`);
}
+7 -1
View File
@@ -5,6 +5,7 @@ import infisical from 'infisical-node';
import express from 'express';
import helmet from 'helmet';
import cors from 'cors';
import session from 'express-session';
import * as Sentry from '@sentry/node';
import { DatabaseService } from './services';
import { setUpHealthEndpoint } from './services/health';
@@ -75,7 +76,7 @@ import {
getPort,
getSentryDSN,
getSiteURL,
getSmtpHost
getSessionSecret,
} from './config';
const main = async () => {
@@ -111,6 +112,11 @@ const main = async () => {
);
app.use(requestIp.mw());
app.use(session({
secret: getSessionSecret(),
resave: false, // don't save session if unmodified
saveUninitialized: false, // don't create session until something stored
}));
if (getNodeEnv() === 'production') {
// enable app-wide rate-limiting + helmet security
@@ -21,7 +21,7 @@ export const requestErrorHandler: ErrorRequestHandler = (error: RequestError | E
//* Set Sentry user identification if req.user is populated
if (req.user !== undefined && req.user !== null) {
Sentry.setUser({ email: req.user.email })
Sentry.setUser({ email: (req.user as any).email })
}
//* Only sent error to Sentry if LogLevel is one of the following level 'ERROR', 'EMERGENCY' or 'CRITICAL'
//* with this we will eliminate false-positive errors like 'BadRequestError', 'UnauthorizedRequestError' and so on
+9 -1
View File
@@ -2,6 +2,8 @@ import { Schema, model, Types, Document } from 'mongoose';
export interface IUser extends Document {
_id: Types.ObjectId;
authId?: string;
authProvider?: string;
email: string;
firstName?: string;
lastName?: string;
@@ -26,9 +28,15 @@ export interface IUser extends Document {
const userSchema = new Schema<IUser>(
{
authId: {
type: String,
},
authProvider: {
type: String,
},
email: {
type: String,
required: true
required: true,
},
firstName: {
type: String
+58 -4
View File
@@ -1,10 +1,50 @@
import express from 'express';
const router = express.Router();
import { body } from 'express-validator';
import passport from 'passport';
import { requireAuth, validateRequest } from '../../middleware';
import { authController } from '../../controllers/v1';
import { authLimiter } from '../../helpers/rateLimiter';
import { AUTH_MODE_JWT } from '../../variables';
import { User } from '../../models';
import { createToken } from '../../helpers/auth';
import { getJwtProviderAuthLifetime, getJwtProviderAuthSecret } from '../../config';
// eslint-disable-next-line @typescript-eslint/no-var-requires
const GoogleStrategy = require('passport-google-oidc');
passport.use(new GoogleStrategy({
passReqToCallback: true,
clientID: process.env['GOOGLE_CLIENT_ID'],
clientSecret: process.env['GOOGLE_CLIENT_SECRET'],
callbackURL: '/api/v1/auth/google/callback',
}, async (req: express.Request, issuer: any, profile: any, cb: any) => {
const email = profile.emails[0].value;
let user = await User.findOne({
authProvider: issuer,
authId: profile.id,
})
if (!user) {
user = await new User({
email,
authProvider: issuer,
authId: profile.id,
}).save();
}
const providerAuthToken = createToken({
payload: {
userId: user._id.toString(),
email: user.email,
},
expiresIn: getJwtProviderAuthLifetime(),
secret: getJwtProviderAuthSecret(),
});
req.providerAuthToken = providerAuthToken;
cb(null, profile);
}));
router.post('/token', validateRequest, authController.getNewToken);
@@ -27,20 +67,34 @@ router.post( // deprecated (moved to api/v2/auth/login2)
);
router.post(
'/logout',
'/logout',
authLimiter,
requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT]
}),
}),
authController.logout
);
router.post(
'/checkAuth',
'/checkAuth',
requireAuth({
acceptedAuthModes: [AUTH_MODE_JWT]
}),
}),
authController.checkAuth
);
router.get(
'/login/federated/google',
authLimiter,
passport.authenticate('google', {
scope: ['profile', 'email'],
}),
)
router.get(
'/google/callback',
passport.authenticate('google', { failureRedirect: '/error', session: false }),
authController.handleGoogleCallback,
)
export default router;
+7
View File
@@ -9,6 +9,12 @@ import {
AuthData
} from '../../interfaces/middleware';
declare module 'express' {
interface Request {
user?: any;
}
}
// TODO: fix (any) types
declare global {
namespace Express {
@@ -18,6 +24,7 @@ declare global {
workspace: any;
membership: any;
targetMembership: any;
providerAuthToken: any;
organization: any;
membershipOrg: any;
integration: any;