Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(auth): centralize SSO error handling logic #9832

Open
wants to merge 7 commits into
base: main
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import { EnvironmentService } from 'src/engine/core-modules/environment/environm
import { OnboardingService } from 'src/engine/core-modules/onboarding/onboarding.service';
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
import { DomainManagerService } from 'src/engine/core-modules/domain-manager/services/domain-manager.service';
import { GuardRedirectService } from 'src/engine/core-modules/guard-redirect/services/guard-redirect.service';

@Controller('auth/google-apis')
@UseFilters(AuthRestApiExceptionFilter)
Expand All @@ -35,6 +36,7 @@ export class GoogleAPIsAuthController {
private readonly environmentService: EnvironmentService,
private readonly onboardingService: OnboardingService,
private readonly domainManagerService: DomainManagerService,
private readonly guardRedirectService: GuardRedirectService,
@InjectRepository(Workspace, 'core')
private readonly workspaceRepository: Repository<Workspace>,
) {}
Expand All @@ -52,75 +54,89 @@ export class GoogleAPIsAuthController {
@Req() req: GoogleAPIsRequest,
@Res() res: Response,
) {
const { user } = req;

const {
emails,
accessToken,
refreshToken,
transientToken,
redirectLocation,
calendarVisibility,
messageVisibility,
} = user;

const { workspaceMemberId, userId, workspaceId } =
await this.transientTokenService.verifyTransientToken(transientToken);

const demoWorkspaceIds = this.environmentService.get('DEMO_WORKSPACE_IDS');

if (demoWorkspaceIds.includes(workspaceId)) {
throw new AuthException(
'Cannot connect Google account to demo workspace',
AuthExceptionCode.FORBIDDEN_EXCEPTION,
);
}
let workspace: Workspace | null = null;

try {
const { user } = req;

const {
emails,
accessToken,
refreshToken,
transientToken,
redirectLocation,
calendarVisibility,
messageVisibility,
} = user;

const { workspaceMemberId, userId, workspaceId } =
await this.transientTokenService.verifyTransientToken(transientToken);

const demoWorkspaceIds =
this.environmentService.get('DEMO_WORKSPACE_IDS');

if (demoWorkspaceIds.includes(workspaceId)) {
throw new AuthException(
'Cannot connect Google account to demo workspace',
AuthExceptionCode.FORBIDDEN_EXCEPTION,
);
}

if (!workspaceId) {
throw new AuthException(
'Workspace not found',
AuthExceptionCode.WORKSPACE_NOT_FOUND,
);
}
AMoreaux marked this conversation as resolved.
Show resolved Hide resolved

workspace = await this.workspaceRepository.findOneBy({
id: workspaceId,
});

if (!workspaceId) {
throw new AuthException(
'Workspace not found',
AuthExceptionCode.WORKSPACE_NOT_FOUND,
);
}
const handle = emails[0].value;

const handle = emails[0].value;

await this.googleAPIsService.refreshGoogleRefreshToken({
handle,
workspaceMemberId: workspaceMemberId,
workspaceId: workspaceId,
accessToken,
refreshToken,
calendarVisibility,
messageVisibility,
});

if (userId) {
await this.onboardingService.setOnboardingConnectAccountPending({
userId,
workspaceId,
value: false,
await this.googleAPIsService.refreshGoogleRefreshToken({
handle,
workspaceMemberId: workspaceMemberId,
workspaceId: workspaceId,
accessToken,
refreshToken,
calendarVisibility,
messageVisibility,
});
}

const workspace = await this.workspaceRepository.findOneBy({
id: workspaceId,
});

if (!workspace) {
throw new AuthException(
'Workspace not found',
AuthExceptionCode.WORKSPACE_NOT_FOUND,
if (userId) {
await this.onboardingService.setOnboardingConnectAccountPending({
userId,
workspaceId,
value: false,
});
}

if (!workspace) {
throw new AuthException(
'Workspace not found',
AuthExceptionCode.WORKSPACE_NOT_FOUND,
);
}

return res.redirect(
this.domainManagerService
.buildWorkspaceURL({
subdomain: workspace.subdomain,
pathname: redirectLocation || '/settings/accounts',
})
.toString(),
);
} catch (err) {
return res.redirect(
this.guardRedirectService.getRedirectErrorUrlAndCaptureExceptions(
err,
workspace ?? {
subdomain: this.environmentService.get('DEFAULT_SUBDOMAIN'),
},
),
);
}

return res.redirect(
this.domainManagerService
.buildWorkspaceURL({
subdomain: workspace.subdomain,
pathname: redirectLocation || '/settings/accounts',
})
.toString(),
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,29 +11,25 @@ import { InjectRepository } from '@nestjs/typeorm';
import { Response } from 'express';
import { Repository } from 'typeorm';

import {
AuthException,
AuthExceptionCode,
} from 'src/engine/core-modules/auth/auth.exception';
import { AuthOAuthExceptionFilter } from 'src/engine/core-modules/auth/filters/auth-oauth-exception.filter';
import { AuthRestApiExceptionFilter } from 'src/engine/core-modules/auth/filters/auth-rest-api-exception.filter';
import { GoogleOauthGuard } from 'src/engine/core-modules/auth/guards/google-oauth.guard';
import { GoogleProviderEnabledGuard } from 'src/engine/core-modules/auth/guards/google-provider-enabled.guard';
import { AuthService } from 'src/engine/core-modules/auth/services/auth.service';
import { GoogleRequest } from 'src/engine/core-modules/auth/strategies/google.auth.strategy';
import { LoginTokenService } from 'src/engine/core-modules/auth/token/services/login-token.service';
import { DomainManagerService } from 'src/engine/core-modules/domain-manager/services/domain-manager.service';
import { User } from 'src/engine/core-modules/user/user.entity';
import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service';
import { GuardRedirectService } from 'src/engine/core-modules/guard-redirect/services/guard-redirect.service';

@Controller('auth/google')
@UseFilters(AuthRestApiExceptionFilter)
export class GoogleAuthController {
constructor(
private readonly loginTokenService: LoginTokenService,
private readonly authService: AuthService,
private readonly domainManagerService: DomainManagerService,
private readonly environmentService: EnvironmentService,
private readonly guardRedirectService: GuardRedirectService,
@InjectRepository(User, 'core')
private readonly userRepository: Repository<User>,
) {}
Expand Down Expand Up @@ -120,16 +116,14 @@ export class GoogleAuthController {
}),
);
} catch (err) {
if (err instanceof AuthException) {
return res.redirect(
this.domainManagerService.computeRedirectErrorUrl(
err.message,
currentWorkspace?.subdomain ??
this.environmentService.get('DEFAULT_SUBDOMAIN'),
),
);
}
throw new AuthException(err, AuthExceptionCode.INTERNAL_SERVER_ERROR);
return res.redirect(
this.guardRedirectService.getRedirectErrorUrlAndCaptureExceptions(
err,
currentWorkspace ?? {
subdomain: this.environmentService.get('DEFAULT_SUBDOMAIN'),
},
),
);
AMoreaux marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
Loading
Loading