Skip to content

Commit 173ef68

Browse files
feat cookie set response
1 parent 9ed6350 commit 173ef68

File tree

12 files changed

+184
-7
lines changed

12 files changed

+184
-7
lines changed

src/auth/auth.controller.spec.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { Test, TestingModule } from "@nestjs/testing";
22
import { AuthController } from "./auth.controller";
33
import { AuthService } from "./auth.service";
4+
import { MockResponse, createResponse } from "node-mocks-http";
5+
import { Response } from "express";
46

57

68
describe("User Controller", () => {
@@ -33,11 +35,14 @@ describe("User Controller", () => {
3335
describe("auth controller ()", () => {
3436

3537
it("should create access token", async () => {
38+
let response1: MockResponse<Response> = createResponse();
39+
response1.json = jest.fn();
40+
response1.cookie = jest.fn();
3641
let response = { access_token: "s" };
3742
const createSpy = jest
3843
.spyOn(service, "signIn")
3944
.mockResolvedValueOnce(response);
40-
await controller.signIn(mockUserRequest);
45+
await controller.signIn(mockUserRequest,response1);
4146
expect(createSpy).toHaveBeenCalled();
4247
});
4348

src/auth/auth.controller.ts

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
import {
22
Body,
33
Controller,
4-
Get,
54
HttpCode,
65
HttpStatus,
76
Post,
8-
Request,
7+
Res,
8+
UseFilters,
99
} from '@nestjs/common';
10+
import { Response } from 'express';
1011
import { AuthService } from './auth.service';
1112
import { Public } from './decorators/public.decorator';
13+
import { GetCurrentUser, GetCurrentUserId } from '../common/decorators';
14+
import { HttpExceptionFilter } from '../utils/http-exception.filter';
1215

1316
@Controller('auth')
1417
export class AuthController {
@@ -17,7 +20,28 @@ export class AuthController {
1720
@Public()
1821
@HttpCode(HttpStatus.OK)
1922
@Post('login')
20-
signIn(@Body() signInDto: Record<string, any>) {
21-
return this.authService.signIn(signInDto.email, signInDto.password);
23+
signIn(@Body() signInDto: Record<string, any>, @Res({ passthrough: true }) res: Response) {
24+
const access_token = this.authService.signIn(signInDto.email, signInDto.password);
25+
res.cookie('access_cookies', access_token, {
26+
httpOnly: true,
27+
expires: new Date(Date.now() + 1 * 24 * 60 * 60 * 1000),
28+
path: '/',
29+
sameSite: 'none',
30+
secure: true,
31+
});
32+
return access_token;
2233
}
34+
35+
@Public()
36+
@Post('/refresh')
37+
@UseFilters(new HttpExceptionFilter())
38+
@HttpCode(HttpStatus.OK)
39+
async refreshTokens(
40+
@GetCurrentUser('refreshToken') refreshToken: string,
41+
@GetCurrentUserId() userId: string,
42+
) {
43+
return await this.authService.refreshTokens(userId, refreshToken);
44+
}
45+
46+
2347
}

src/auth/auth.service.ts

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Injectable, UnauthorizedException } from '@nestjs/common';
1+
import { ForbiddenException, Injectable, UnauthorizedException } from '@nestjs/common';
22
import { UserService } from '../users/users.service';
33
import { JwtService } from '@nestjs/jwt';
44
import * as bcrypt from 'bcrypt';
@@ -24,4 +24,57 @@ export class AuthService {
2424
}
2525
throw new UnauthorizedException();
2626
}
27+
28+
29+
async refreshTokens(userId: string, rt: string) {
30+
const user = await this.usersService.findOne(userId);
31+
32+
if (!user || !user.hashdRt) throw new ForbiddenException('Access Denied.');
33+
34+
const rtMatches = await bcrypt.compare(rt, user.hashdRt);
35+
36+
if (!rtMatches) throw new ForbiddenException('Access Denied.');
37+
38+
const tokens = await this.getTokens(user);
39+
40+
const rtHash = await this.hashPassword(tokens.refresh_token);
41+
42+
await this.usersService.updateOne(user._id, { hashdRt: rtHash });
43+
return tokens;
44+
}
45+
46+
async getTokens(user: any) {
47+
const [at, rt] = await Promise.all([
48+
this.jwtService.signAsync(
49+
{
50+
sub: user._id,
51+
email: user.email,
52+
},
53+
{
54+
secret: 'at-secret',
55+
expiresIn: '24h',
56+
},
57+
),
58+
this.jwtService.signAsync(
59+
{
60+
sub: user._id,
61+
email: user.email,
62+
},
63+
{
64+
secret: 'rt-secret',
65+
expiresIn: '30d',
66+
},
67+
),
68+
]);
69+
70+
return {
71+
access_token: at,
72+
refresh_token: rt,
73+
};
74+
}
75+
76+
//Encriptación de la copntraseña
77+
async hashPassword(data: string) {
78+
return bcrypt.hash(data, 10);
79+
}
2780
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { createParamDecorator, ExecutionContext } from '@nestjs/common';
2+
3+
export const CookiesDecorator = createParamDecorator(
4+
(data: string, ctx: ExecutionContext) => {
5+
const request = ctx.switchToHttp().getRequest();
6+
return data ? request.cookies?.[data] : request.cookies;
7+
},
8+
);
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { createParamDecorator, ExecutionContext } from '@nestjs/common';
2+
3+
export const GetCurrentUserId = createParamDecorator(
4+
(data: undefined, context: ExecutionContext): string => {
5+
const request = context.switchToHttp().getRequest();
6+
console.log(request)
7+
return request.user['sub'];
8+
},
9+
);
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { createParamDecorator, ExecutionContext } from '@nestjs/common';
2+
3+
export const GetCurrentUser = createParamDecorator(
4+
(data: string, context: ExecutionContext) => {
5+
const request = context.switchToHttp().getRequest();
6+
if (!data) return request.user;
7+
return request.user[data];
8+
},
9+
);

src/common/decorators/index.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export * from './get-current-user.decorator';
2+
export * from './get-current-user-id.decorator';
3+
export * from './cookies.decorator';

src/common/guards/at.guard.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import {
2+
CanActivate,
3+
ExecutionContext,
4+
Injectable,
5+
UnauthorizedException,
6+
} from '@nestjs/common';
7+
import { Reflector } from '@nestjs/core';
8+
import { JwtService } from '@nestjs/jwt';
9+
import { Request } from 'express';
10+
import { jwtConstants } from '../../auth/constants';
11+
import { IS_PUBLIC_KEY } from '../../auth/decorators/public.decorator';
12+
13+
@Injectable()
14+
export class AuthGuard implements CanActivate {
15+
constructor(
16+
private jwtService: JwtService,
17+
private reflector: Reflector,
18+
) {}
19+
20+
async canActivate(context: ExecutionContext): Promise<boolean> {
21+
const isPublic = this.reflector.getAllAndOverride<boolean>(IS_PUBLIC_KEY, [
22+
context.getHandler(),
23+
context.getClass(),
24+
]);
25+
if (isPublic) {
26+
// 💡 See this condition
27+
return true;
28+
}
29+
30+
const request = context.switchToHttp().getRequest();
31+
const token = this.extractTokenFromHeader(request);
32+
if (!token) {
33+
throw new UnauthorizedException();
34+
}
35+
try {
36+
const payload = await this.jwtService.verifyAsync(token, {
37+
secret: jwtConstants.secret,
38+
});
39+
// 💡 We're assigning the payload to the request object here
40+
// so that we can access it in our route handlers
41+
request['user'] = payload;
42+
} catch {
43+
throw new UnauthorizedException();
44+
}
45+
return true;
46+
}
47+
48+
private extractTokenFromHeader(request: Request): string | undefined {
49+
const [type, token] = request.headers.authorization?.split(' ') ?? [];
50+
return type === 'Bearer' ? token : undefined;
51+
}
52+
}

src/common/guards/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export * from './at.guard';
2+
// export * from './rt.guard';

src/common/guards/rt.guard.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// import { AuthGuard } from '@nestjs/passport';
2+
3+
// export class RtGuard extends AuthGuard('jwt-refresh') {
4+
// constructor() {
5+
// super();
6+
// }
7+
// }

0 commit comments

Comments
 (0)