Skip to content

Commit

Permalink
Fix login, confirm code (#146)
Browse files Browse the repository at this point in the history
* Fix login, confirm code

* Refresh token

* Refresh token

* Fix unit test

* Add api logout

* Add logic that check password reset period

* Fix reset password

* Change api endpoint

* Fix unit test

* Fix axios run refresh when access token expired

* Fix router

* Fix unit test

* Lint code

* User service unit test

* Lint file

* Fix login and add confirm code view

* Lint code

* Fix navigate to verify code

* Remove console

* Update logout feature

* Fix hook

* Lint code

* Fix request reset password

* Lint code

* Fix login

* Lint code

* Fix logout and link to email

* Lint code

* Fix unit test

* Remove yarn lock

* lint

* Fix router

* Lint code

* Fix build

* Lint code

---------

Co-authored-by: HoangPham <[email protected]>
  • Loading branch information
PhamAnhHoang and padi-dev-hoangpa authored Dec 23, 2023
1 parent af742c0 commit 5021ec0
Show file tree
Hide file tree
Showing 66 changed files with 1,794 additions and 804 deletions.
6 changes: 6 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ APP_SECRET="such secret wow"
SESSION_SECRET="even more secretIER! :D"

API_URL=http://localhost:3000
PLATFORM_URL=http://localhost:4200

MAIL_HOST=localhost
MAIL_USER=
Expand All @@ -28,3 +29,8 @@ PUBLIC_KEY="-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
# API
ALLOWED_ORIGINS=http://localhost:3000,http://localhost:4200
PORT=3000

JWT_ACCESS_TOKEN_EXPIRATION_TIME=60
JWT_REFRESH_TOKEN_EXPIRATION_TIME=28800

RESET_PASSWORD_PERIOD=15
4 changes: 0 additions & 4 deletions apps/api/src/auth/auth.controller.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { createMock } from '@golevelup/ts-jest'

import { AuthController } from './auth.controller'
import { AuthService } from './auth.service'
import { ConfirmCodeService } from '../user/confirm-code.service'
import { UserEntity } from '../entities/user.entity'
import { SignUpWithEmailCredentialsDto } from '@isomera/dtos'
import { Pure } from '@isomera/interfaces'
Expand All @@ -26,9 +25,6 @@ describe('Auth Controller', () => {
if (Object.is(token, AuthService)) {
return createMock<AuthService>()
}
if (Object.is(token, ConfirmCodeService)) {
return createMock<ConfirmCodeService>()
}
})
.compile()

Expand Down
46 changes: 36 additions & 10 deletions apps/api/src/auth/auth.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,20 +24,20 @@ import { JWTAuthGuard } from './guards/jwt-auth.guard'
import { LocalAuthGuard } from './guards/local-auth.guard'
import { SessionAuthGuard } from './guards/session-auth.guard'
import { TokenInterceptor } from './interceptors/token.interceptor'
import { ConfirmCodeService } from '../user/confirm-code.service'
import {
ConfirmCodeResponseInterface,
LogoutResponseInterface,
PasswordResetPerformInterface,
PasswordResetRequestInterface,
Pure,
RefreshTokenResponseInterface,
StatusType
} from '@isomera/interfaces'
import { JwtRefreshTokenGuard } from './guards/jwt-refresh-token'

@Controller('auth')
export class AuthController {
constructor(
private readonly authService: AuthService,
private readonly confirmCodeService: ConfirmCodeService
) {}
constructor(private readonly authService: AuthService) {}

@Post('register')
@HttpCode(HttpStatus.CREATED)
Expand Down Expand Up @@ -68,12 +68,10 @@ export class AuthController {
@HttpCode(HttpStatus.OK)
async confirmCode(
@Body() body: Pure<ConfirmationCodeDto>
): Promise<UserEntity> {
const user = await this.confirmCodeService.verifyCode(body.code, body.email)

await this.authService.sendGreetings(user)
): Promise<ConfirmCodeResponseInterface> {
const user = await this.authService.verifyCode(body)

return user
return { status: user ? StatusType.OK : StatusType.FAIL }
}

@Get('/me')
Expand All @@ -99,4 +97,32 @@ export class AuthController {
const result = await this.authService.setNewPassword(body)
return { status: result ? StatusType.OK : StatusType.FAIL }
}

@UseGuards(JwtRefreshTokenGuard)
@Post('/refresh')
@HttpCode(HttpStatus.OK)
async refreshToken(
@AuthUser() user: Pure<UserEntity>
): Promise<RefreshTokenResponseInterface> {
const { refresh_token, access_token } = this.authService.signToken(user)

await this.authService.storeRefreshToken(user, refresh_token)
return {
access_token,
refresh_token,
status: StatusType.OK
}
}

@Post('/logout')
@UseGuards(SessionAuthGuard, JWTAuthGuard)
@HttpCode(HttpStatus.OK)
async logout(
@AuthUser() user: Pure<UserEntity>
): Promise<LogoutResponseInterface> {
await this.authService.logout(user)
return {
status: StatusType.OK
}
}
}
13 changes: 11 additions & 2 deletions apps/api/src/auth/auth.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import { JwtStrategy } from './strategies/jwt.strategy'
import { LocalStrategy } from './strategies/local.strategy'
import { MailerModule } from '../mailer/mailer.module'
import { ConfirmCodeModule } from '../user/confirm-code.module'
import { OrganizationModule } from '../organization/organization.module'
import { JwtRefreshTokenStrategy } from './strategies/jwt-refresh-token.strategy'

@Module({
imports: [
Expand All @@ -26,9 +28,16 @@ import { ConfirmCodeModule } from '../user/confirm-code.module'
algorithms: ['HS384']
}
}),
ConfirmCodeModule
ConfirmCodeModule,
OrganizationModule
],
controllers: [AuthController],
providers: [AuthService, LocalStrategy, JwtStrategy, SessionSerializer]
providers: [
AuthService,
LocalStrategy,
JwtStrategy,
SessionSerializer,
JwtRefreshTokenStrategy
]
})
export class AuthModule {}
37 changes: 33 additions & 4 deletions apps/api/src/auth/auth.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import { ConfirmCodeService } from '../user/confirm-code.service'
import { UserEntity } from '../entities/user.entity'
import { SignUpWithEmailCredentialsDto } from '@isomera/dtos'
import { Pure } from '@isomera/interfaces'
import { OrganizationService } from '../organization/organization.service'
import { ConfigService } from '@nestjs/config'

describe('AuthService', () => {
let service: AuthService
Expand All @@ -20,7 +22,24 @@ describe('AuthService', () => {

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [AuthService]
providers: [
AuthService,
{
provide: ConfigService,
useValue: {
get: jest.fn((key: string) => {
// this is being super extra, in the case that you need multiple keys with the `get` method
if (key === 'JWT_ACCESS_TOKEN_EXPIRATION_TIME') {
return 123
}
if (key === 'JWT_REFRESH_TOKEN_EXPIRATION_TIME') {
return 123
}
return null
})
}
}
]
})
.useMocker(token => {
if (Object.is(token, UserService)) {
Expand All @@ -35,6 +54,14 @@ describe('AuthService', () => {
if (Object.is(token, ConfirmCodeService)) {
return createMock<ConfirmCodeService>()
}

if (Object.is(token, OrganizationService)) {
return createMock<OrganizationService>()
}

if (Object.is(token, ConfigService)) {
return createMock<ConfigService>()
}
})
.compile()

Expand Down Expand Up @@ -90,6 +117,7 @@ describe('AuthService', () => {
checkPassword: jest.fn().mockResolvedValue(true)
})
)
mockedJwtService.sign.mockReturnValue('j.w.t')
const user = await service.login(email, password)

expect(user).toHaveProperty('email', email)
Expand Down Expand Up @@ -164,9 +192,10 @@ describe('AuthService', () => {
it('should sign a new JWT', () => {
const user = createMock<UserEntity>({ email: '[email protected]' })

mockedJwtService.sign.mockReturnValueOnce('j.w.t')
const token = service.signToken(user)
mockedJwtService.sign.mockReturnValue('j.w.t')
const { refresh_token, access_token } = service.signToken(user)

expect(token).toEqual(expect.any(String))
expect(access_token).toEqual(expect.any(String))
expect(refresh_token).toEqual(expect.any(String))
})
})
Loading

2 comments on commit 5021ec0

@vercel
Copy link

@vercel vercel bot commented on 5021ec0 Dec 23, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Successfully deployed to the following URLs:

isomera-platform – ./

app.isomera.org
isomera-platform-cortip.vercel.app
isomera.vercel.app
isomera-platform-git-main-cortip.vercel.app

@vercel
Copy link

@vercel vercel bot commented on 5021ec0 Dec 23, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.