Skip to content

Commit

Permalink
refactor(api): Migrated to cookie based authentication (#206)
Browse files Browse the repository at this point in the history
  • Loading branch information
rajdip-b authored May 11, 2024
1 parent ab37530 commit ad6911f
Show file tree
Hide file tree
Showing 7 changed files with 423 additions and 251 deletions.
2 changes: 2 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,5 @@ JWT_SECRET=secret

WEB_FRONTEND_URL=https://keyshade.xyz
WORKSPACE_FRONTEND_URL=https://app.keyshade.xyz

DOMAIN=localhost
2 changes: 2 additions & 0 deletions apps/api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
"chalk": "^4.1.2",
"class-transformer": "^0.5.1",
"class-validator": "^0.14.1",
"cookie-parser": "^1.4.6",
"eccrypto": "^1.1.6",
"moment": "^2.30.1",
"nodemailer": "^6.9.9",
Expand All @@ -48,6 +49,7 @@
"@nestjs/cli": "^10.0.0",
"@nestjs/schematics": "^10.0.0",
"@nestjs/testing": "^10.0.0",
"@types/cookie-parser": "^1.4.7",
"@types/eccrypto": "^1.1.6",
"@types/express": "^4.17.17",
"@types/jest": "^29.5.2",
Expand Down
26 changes: 16 additions & 10 deletions apps/api/src/auth/controller/auth.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import {
UseGuards
} from '@nestjs/common'
import { AuthService } from '../service/auth.service'
import { UserAuthenticatedResponse } from '../auth.types'
import { Public } from '../../decorators/public.decorator'
import {
ApiOperation,
Expand All @@ -24,6 +23,7 @@ import { AuthGuard } from '@nestjs/passport'
import { GithubOAuthStrategyFactory } from '../../config/factory/github/github-strategy.factory'
import { GoogleOAuthStrategyFactory } from '../../config/factory/google/google-strategy.factory'
import { GitlabOAuthStrategyFactory } from '../../config/factory/gitlab/gitlab-strategy.factory'
import { Response } from 'express'

@ApiTags('Auth Controller')
@Controller('auth')
Expand Down Expand Up @@ -94,9 +94,15 @@ export class AuthController {
})
async validateOtp(
@Query('email') email: string,
@Query('otp') otp: string
): Promise<UserAuthenticatedResponse> {
return await this.authService.validateOtp(email, otp)
@Query('otp') otp: string,
@Res({ passthrough: true }) response: Response
) {
const { token, ...user } = await this.authService.validateOtp(email, otp)
response.cookie('token', `Bearer ${token}`, {
domain: process.env.DOMAIN ?? 'localhost',
expires: new Date(Date.now() + 1000 * 60 * 60 * 24 * 7) // 7 days,
})
return user
}

/* istanbul ignore next */
Expand All @@ -107,7 +113,7 @@ export class AuthController {
description:
'This endpoint validates Github OAuth. If the OAuth is valid, it returns a valid token along with the user details'
})
async githubOAuthLogin(@Res() res) {
async githubOAuthLogin(@Res() res: Response) {
if (!this.githubOAuthStrategyFactory.isOAuthEnabled()) {
throw new HttpException(
'GitHub Auth is not enabled in this environment. Refer to the https://docs.keyshade.xyz/contributing-to-keyshade/environment-variables if you would like to set it up.',
Expand Down Expand Up @@ -136,7 +142,7 @@ export class AuthController {
status: HttpStatus.OK,
description: 'Logged in successfully'
})
async githubOAuthCallback(@Req() req) {
async githubOAuthCallback(@Req() req: any) {
const { emails, displayName: name, photos } = req.user
const email = emails[0].value
const profilePictureUrl = photos[0].value
Expand All @@ -155,7 +161,7 @@ export class AuthController {
description:
'This endpoint validates Gitlab OAuth. If the OAuth is valid, it returns a valid token along with the user details'
})
async gitlabOAuthLogin(@Res() res) {
async gitlabOAuthLogin(@Res() res: Response) {
if (!this.gitlabOAuthStrategyFactory.isOAuthEnabled()) {
throw new HttpException(
'GitLab Auth is not enabled in this environment. Refer to the https://docs.keyshade.xyz/contributing-to-keyshade/environment-variables if you would like to set it up.',
Expand Down Expand Up @@ -184,7 +190,7 @@ export class AuthController {
status: HttpStatus.OK,
description: 'Logged in successfully'
})
async gitlabOAuthCallback(@Req() req) {
async gitlabOAuthCallback(@Req() req: any) {
const { emails, displayName: name, avatarUrl: profilePictureUrl } = req.user
const email = emails[0].value
return await this.authService.handleOAuthLogin(
Expand All @@ -201,7 +207,7 @@ export class AuthController {
summary: 'Google OAuth',
description: 'Initiates Google OAuth'
})
async googleOAuthLogin(@Res() res) {
async googleOAuthLogin(@Res() res: Response) {
if (!this.googleOAuthStrategyFactory.isOAuthEnabled()) {
throw new HttpException(
'Google Auth is not enabled in this environment. Refer to the https://docs.keyshade.xyz/contributing-to-keyshade/environment-variables if you would like to set it up.',
Expand Down Expand Up @@ -229,7 +235,7 @@ export class AuthController {
status: HttpStatus.OK,
description: 'Logged in successfully'
})
async googleOAuthCallback(@Req() req) {
async googleOAuthCallback(@Req() req: any) {
const { emails, displayName: name, photos } = req.user
const email = emails[0].value
const profilePictureUrl = photos[0].value
Expand Down
16 changes: 10 additions & 6 deletions apps/api/src/auth/guard/auth/auth.guard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import { toSHA256 } from '../../../common/to-sha256'

const X_E2E_USER_EMAIL = 'x-e2e-user-email'
const X_KEYSHADE_TOKEN = 'x-keyshade-token'
const AUTHORIZATION = 'authorization'

@Injectable()
export class AuthGuard implements CanActivate {
Expand Down Expand Up @@ -84,7 +83,7 @@ export class AuthGuard implements CanActivate {
user.isAuthViaApiKey = true
user.apiKeyAuthorities = new Set(apiKey.authorities)
} else if (authType === 'JWT') {
const token = this.extractTokenFromHeader(request)
const token = this.extractTokenFromCookies(request)
if (!token) {
throw new ForbiddenException()
}
Expand Down Expand Up @@ -134,18 +133,19 @@ export class AuthGuard implements CanActivate {

private getAuthType(request: any): 'JWT' | 'API_KEY' | 'NONE' {
const headers = this.getHeaders(request)
const cookies = request.cookies
if (headers[X_KEYSHADE_TOKEN]) {
return 'API_KEY'
}
if (headers[AUTHORIZATION]) {
if (cookies && cookies['token']) {
return 'JWT'
}
return 'NONE'
}

private extractTokenFromHeader(request: any): string | undefined {
const headers = this.getHeaders(request)
const [type, token] = headers.authorization?.split(' ') ?? []
private extractTokenFromCookies(request: any): string | undefined {
const headers = this.getCookies(request)
const [type, token] = headers.token?.split(' ') ?? []
return type === 'Bearer' ? token : undefined
}

Expand All @@ -160,4 +160,8 @@ export class AuthGuard implements CanActivate {
private getHeaders(request: any): any {
return request.headers || request.handshake.headers // For websockets
}

private getCookies(request: any): any {
return request.cookies
}
}
10 changes: 10 additions & 0 deletions apps/api/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import * as Sentry from '@sentry/node'
import { ProfilingIntegration } from '@sentry/profiling-node'
import { RedisIoAdapter } from './socket/redis.adapter'
import { CustomLoggerService } from './common/logger.service'
import * as cookieParser from 'cookie-parser'

export const sentryEnv = process.env.SENTRY_ENV || 'production'

Expand Down Expand Up @@ -74,6 +75,15 @@ async function initializeNestApp() {
}),
new QueryTransformPipe()
)
app.enableCors({
credentials: true,
origin: [
'http://localhost:3000',
'https://keyshade.xyz',
'https://dashboard.keyshade.xyz'
]
})
app.use(cookieParser())
const port = process.env.API_PORT || 4200
const swaggerConfig = new DocumentBuilder()
.setTitle('keyshade')
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"version": "1.2.0",
"license": "MPL-2.0",
"private": true,
"engineStrict": false,
"release": {
"branches": [
"main"
Expand Down Expand Up @@ -121,7 +122,7 @@
"prepare": "husky",
"sourcemaps:api": "turbo run sourcemaps --filter=api"
},
"packageManager": "pnpm@9.0.5",
"packageManager": "pnpm@9.1.0",
"devDependencies": {
"@sentry/cli": "^2.28.6",
"@sentry/webpack-plugin": "^2.14.2",
Expand Down
Loading

0 comments on commit ad6911f

Please sign in to comment.