hotfix: adding dynamic redirection in self-host auth system (HBE-173) (#40)

* chore: completed base auth implementation with redirectUrl

* chore: completed base auth fix with redirect_uri

* chore: added whitelist based redirection

* chore: added a env variable for session secret in main.ts

* chore: removed migrations folder from prisma directory
This commit is contained in:
Balu Babu
2023-03-14 19:19:22 +05:30
committed by GitHub
parent be46ed2686
commit a779ba5c0e
13 changed files with 139 additions and 20 deletions

View File

@@ -20,7 +20,9 @@ import { AuthUser } from 'src/types/AuthUser';
import { RTCookie } from 'src/decorators/rt-cookie.decorator';
import { AuthGuard } from '@nestjs/passport';
import { authCookieHandler, throwHTTPErr } from './helper';
import { GoogleSSOGuard } from './guards/google-sso.guard';
import { GithubSSOGuard } from './guards/github-sso.guard';
import { MicrosoftSSOGuard } from './guards/microsoft-sso-.guard';
@Controller({ path: 'auth', version: '1' })
export class AuthController {
constructor(private authService: AuthService) {}
@@ -44,7 +46,7 @@ export class AuthController {
async verify(@Body() data: VerifyMagicDto, @Res() res: Response) {
const authTokens = await this.authService.verifyMagicLinkTokens(data);
if (E.isLeft(authTokens)) throwHTTPErr(authTokens.left);
authCookieHandler(res, authTokens.right, false);
authCookieHandler(res, authTokens.right, false, null);
}
/**
@@ -63,14 +65,14 @@ export class AuthController {
user,
);
if (E.isLeft(newTokenPair)) throwHTTPErr(newTokenPair.left);
authCookieHandler(res, newTokenPair.right, false);
authCookieHandler(res, newTokenPair.right, false, null);
}
/**
** Route to initiate SSO auth via Google
*/
@Get('google')
@UseGuards(AuthGuard('google'))
@UseGuards(GoogleSSOGuard)
async googleAuth(@Request() req) {}
/**
@@ -78,18 +80,23 @@ export class AuthController {
* @see https://auth0.com/docs/get-started/authentication-and-authorization-flow/authorization-code-flow#how-it-works
*/
@Get('google/callback')
@UseGuards(AuthGuard('google'))
@UseGuards(GoogleSSOGuard)
async googleAuthRedirect(@Request() req, @Res() res) {
const authTokens = await this.authService.generateAuthTokens(req.user.uid);
if (E.isLeft(authTokens)) throwHTTPErr(authTokens.left);
authCookieHandler(res, authTokens.right, true);
authCookieHandler(
res,
authTokens.right,
true,
req.authInfo.state.redirect_uri,
);
}
/**
** Route to initiate SSO auth via Github
*/
@Get('github')
@UseGuards(AuthGuard('github'))
@UseGuards(GithubSSOGuard)
async githubAuth(@Request() req) {}
/**
@@ -97,18 +104,23 @@ export class AuthController {
* @see https://auth0.com/docs/get-started/authentication-and-authorization-flow/authorization-code-flow#how-it-works
*/
@Get('github/callback')
@UseGuards(AuthGuard('github'))
@UseGuards(GithubSSOGuard)
async githubAuthRedirect(@Request() req, @Res() res) {
const authTokens = await this.authService.generateAuthTokens(req.user.uid);
if (E.isLeft(authTokens)) throwHTTPErr(authTokens.left);
authCookieHandler(res, authTokens.right, true);
authCookieHandler(
res,
authTokens.right,
true,
req.authInfo.state.redirect_uri,
);
}
/**
** Route to initiate SSO auth via Microsoft
*/
@Get('microsoft')
@UseGuards(AuthGuard('microsoft'))
@UseGuards(MicrosoftSSOGuard)
async microsoftAuth(@Request() req) {}
/**
@@ -116,11 +128,16 @@ export class AuthController {
* @see https://auth0.com/docs/get-started/authentication-and-authorization-flow/authorization-code-flow#how-it-works
*/
@Get('microsoft/callback')
@UseGuards(AuthGuard('microsoft'))
@UseGuards(MicrosoftSSOGuard)
async microsoftAuthRedirect(@Request() req, @Res() res) {
const authTokens = await this.authService.generateAuthTokens(req.user.uid);
if (E.isLeft(authTokens)) throwHTTPErr(authTokens.left);
authCookieHandler(res, authTokens.right, true);
authCookieHandler(
res,
authTokens.right,
true,
req.authInfo.state.redirect_uri,
);
}
/**

View File

@@ -0,0 +1,15 @@
import { ExecutionContext, Injectable } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
@Injectable()
export class GithubSSOGuard extends AuthGuard('github') {
getAuthenticateOptions(context: ExecutionContext) {
const req = context.switchToHttp().getRequest();
return {
state: {
redirect_uri: req.query.redirect_uri,
},
};
}
}

View File

@@ -0,0 +1,15 @@
import { ExecutionContext, Injectable } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
@Injectable()
export class GoogleSSOGuard extends AuthGuard('google') {
getAuthenticateOptions(context: ExecutionContext) {
const req = context.switchToHttp().getRequest();
return {
state: {
redirect_uri: req.query.redirect_uri,
},
};
}
}

View File

@@ -0,0 +1,15 @@
import { ExecutionContext, Injectable } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
@Injectable()
export class MicrosoftSSOGuard extends AuthGuard('microsoft') {
getAuthenticateOptions(context: ExecutionContext) {
const req = context.switchToHttp().getRequest();
return {
state: {
redirect_uri: req.query.redirect_uri,
},
};
}
}

View File

@@ -1,5 +0,0 @@
import { Injectable } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
@Injectable()
export class MultiAuthGuard extends AuthGuard(['google1', 'google2']) {}

View File

@@ -30,6 +30,7 @@ export const authCookieHandler = (
res: Response,
authTokens: AuthTokens,
redirect: boolean,
redirectUrl: string | null,
) => {
const currentTime = DateTime.now();
const accessTokenValidity = currentTime
@@ -55,9 +56,18 @@ export const authCookieHandler = (
sameSite: 'lax',
maxAge: refreshTokenValidity,
});
if (redirect) {
res.status(HttpStatus.OK).redirect(process.env.REDIRECT_URL);
} else res.status(HttpStatus.OK).send();
if (!redirect) {
res.status(HttpStatus.OK).send();
}
// check to see if redirectUrl is a whitelisted url
const whitelistedOrigins = process.env.WHITELISTED_ORIGINS.split(',');
if (!whitelistedOrigins.includes(redirectUrl))
// if it is not redirect by default to REDIRECT_URL
redirectUrl = process.env.REDIRECT_URL;
res.status(HttpStatus.OK).redirect(redirectUrl);
};
/**

View File

@@ -17,6 +17,7 @@ export class GithubStrategy extends PassportStrategy(Strategy) {
clientSecret: process.env.GITHUB_CLIENT_SECRET,
callbackURL: process.env.GITHUB_CALLBACK_URL,
scope: [process.env.GITHUB_SCOPE],
store: true,
});
}

View File

@@ -18,6 +18,7 @@ export class GoogleStrategy extends PassportStrategy(Strategy) {
callbackURL: process.env.GOOGLE_CALLBACK_URL,
scope: process.env.GOOGLE_SCOPE.split(','),
passReqToCallback: true,
store: true,
});
}

View File

@@ -17,6 +17,7 @@ export class MicrosoftStrategy extends PassportStrategy(Strategy) {
clientSecret: process.env.MICROSOFT_CLIENT_SECRET,
callbackURL: process.env.MICROSOFT_CALLBACK_URL,
scope: [process.env.MICROSOFT_SCOPE],
store: true,
});
}