feat: refactoring auth & add email password login (#318)
* feat: wip * fix: issues * feat: clean controllers and services * fix: test * Fix auth --------- Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
30
server/src/core/auth/controllers/auth.controller.spec.ts
Normal file
30
server/src/core/auth/controllers/auth.controller.spec.ts
Normal file
@ -0,0 +1,30 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { AuthController } from './auth.controller';
|
||||
import { AuthService } from '../services/auth.service';
|
||||
import { TokenService } from '../services/token.service';
|
||||
|
||||
describe('AuthController', () => {
|
||||
let controller: AuthController;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
controllers: [AuthController],
|
||||
providers: [
|
||||
{
|
||||
provide: AuthService,
|
||||
useValue: {},
|
||||
},
|
||||
{
|
||||
provide: TokenService,
|
||||
useValue: {},
|
||||
},
|
||||
],
|
||||
}).compile();
|
||||
|
||||
controller = module.get<AuthController>(AuthController);
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(controller).toBeDefined();
|
||||
});
|
||||
});
|
||||
23
server/src/core/auth/controllers/auth.controller.ts
Normal file
23
server/src/core/auth/controllers/auth.controller.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import { Body, Controller, Post } from '@nestjs/common';
|
||||
import { AuthService } from '../services/auth.service';
|
||||
import { VerifyInput } from '../dto/verify.input';
|
||||
import { VerifyEntity } from '../dto/verify.entity';
|
||||
import { TokenService } from '../services/token.service';
|
||||
|
||||
@Controller('auth')
|
||||
export class AuthController {
|
||||
constructor(
|
||||
private readonly authService: AuthService,
|
||||
private readonly tokenService: TokenService,
|
||||
) {}
|
||||
|
||||
@Post('verify')
|
||||
async verify(@Body() verifyInput: VerifyInput): Promise<VerifyEntity> {
|
||||
const email = await this.tokenService.verifyLoginToken(
|
||||
verifyInput.loginToken,
|
||||
);
|
||||
const result = await this.authService.verify(email);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
54
server/src/core/auth/controllers/google-auth.controller.ts
Normal file
54
server/src/core/auth/controllers/google-auth.controller.ts
Normal file
@ -0,0 +1,54 @@
|
||||
import {
|
||||
Controller,
|
||||
Get,
|
||||
InternalServerErrorException,
|
||||
Req,
|
||||
Res,
|
||||
UseGuards,
|
||||
} from '@nestjs/common';
|
||||
import { AuthGuard } from '@nestjs/passport';
|
||||
import { Response } from 'express';
|
||||
import { GoogleRequest } from '../strategies/google.auth.strategy';
|
||||
import { UserService } from '../../user/user.service';
|
||||
import { assertNotNull } from 'src/utils/assert';
|
||||
import { TokenService } from '../services/token.service';
|
||||
|
||||
@Controller('auth/google')
|
||||
export class GoogleAuthController {
|
||||
constructor(
|
||||
private readonly tokenService: TokenService,
|
||||
private readonly userService: UserService,
|
||||
) {}
|
||||
|
||||
@Get()
|
||||
@UseGuards(AuthGuard('google'))
|
||||
async googleAuth() {
|
||||
// As this method is protected by Google Auth guard, it will trigger Google SSO flow
|
||||
return;
|
||||
}
|
||||
|
||||
@Get('redirect')
|
||||
@UseGuards(AuthGuard('google'))
|
||||
async googleAuthRedirect(@Req() req: GoogleRequest, @Res() res: Response) {
|
||||
const { firstName, lastName, email } = req.user;
|
||||
const displayName = [firstName, lastName].filter(assertNotNull).join(' ');
|
||||
|
||||
const user = await this.userService.createUser({
|
||||
data: {
|
||||
email,
|
||||
displayName,
|
||||
locale: 'en',
|
||||
},
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
throw new InternalServerErrorException(
|
||||
'User email domain does not match an existing workspace',
|
||||
);
|
||||
}
|
||||
|
||||
const loginToken = await this.tokenService.generateLoginToken(user.email);
|
||||
|
||||
return res.redirect(this.tokenService.computeRedirectURI(loginToken.token));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,30 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { PasswordAuthController } from './password-auth.controller';
|
||||
import { AuthService } from '../services/auth.service';
|
||||
import { TokenService } from '../services/token.service';
|
||||
|
||||
describe('PasswordAuthController', () => {
|
||||
let controller: PasswordAuthController;
|
||||
|
||||
beforeEach(async () => {
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
controllers: [PasswordAuthController],
|
||||
providers: [
|
||||
{
|
||||
provide: AuthService,
|
||||
useValue: {},
|
||||
},
|
||||
{
|
||||
provide: TokenService,
|
||||
useValue: {},
|
||||
},
|
||||
],
|
||||
}).compile();
|
||||
|
||||
controller = module.get<PasswordAuthController>(PasswordAuthController);
|
||||
});
|
||||
|
||||
it('should be defined', () => {
|
||||
expect(controller).toBeDefined();
|
||||
});
|
||||
});
|
||||
23
server/src/core/auth/controllers/password-auth.controller.ts
Normal file
23
server/src/core/auth/controllers/password-auth.controller.ts
Normal file
@ -0,0 +1,23 @@
|
||||
import { Body, Controller, Post } from '@nestjs/common';
|
||||
import { ChallengeInput } from '../dto/challenge.input';
|
||||
import { AuthService } from '../services/auth.service';
|
||||
import { LoginTokenEntity } from '../dto/login-token.entity';
|
||||
import { TokenService } from '../services/token.service';
|
||||
|
||||
@Controller('auth/password')
|
||||
export class PasswordAuthController {
|
||||
constructor(
|
||||
private readonly authService: AuthService,
|
||||
private readonly tokenService: TokenService,
|
||||
) {}
|
||||
|
||||
@Post()
|
||||
async challenge(
|
||||
@Body() challengeInput: ChallengeInput,
|
||||
): Promise<LoginTokenEntity> {
|
||||
const user = await this.authService.challenge(challengeInput);
|
||||
const loginToken = await this.tokenService.generateLoginToken(user.email);
|
||||
|
||||
return { loginToken };
|
||||
}
|
||||
}
|
||||
21
server/src/core/auth/controllers/token.controller.ts
Normal file
21
server/src/core/auth/controllers/token.controller.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import { BadRequestException, Body, Controller, Post } from '@nestjs/common';
|
||||
import { RefreshTokenInput } from '../dto/refresh-token.input';
|
||||
import { TokenService } from '../services/token.service';
|
||||
|
||||
@Controller('auth/token')
|
||||
export class TokenController {
|
||||
constructor(private tokenService: TokenService) {}
|
||||
|
||||
@Post()
|
||||
async generateAccessToken(@Body() body: RefreshTokenInput) {
|
||||
if (!body.refreshToken) {
|
||||
throw new BadRequestException('Refresh token is mendatory');
|
||||
}
|
||||
|
||||
const tokens = await this.tokenService.generateTokensFromRefreshToken(
|
||||
body.refreshToken,
|
||||
);
|
||||
|
||||
return { tokens: tokens };
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user