Skip to content

Commit 0d4ccd8

Browse files
Merge pull request #4 from MuriloMorandi/feat/jwt
Autenticação JWT
2 parents 19e3984 + 527f46d commit 0d4ccd8

16 files changed

Lines changed: 355 additions & 770 deletions

.env.example

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
NODE_ENV=
2+
PORT=
3+
4+
JWT_SECRET=""
5+
6+
DATABASE_URL=""

.gitignore

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ pnpm-debug.log*
44

55
# Environment variables
66
.env
7-
.env.*
87

98
# Logs
109
logs/

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,19 +22,21 @@
2222
"author": "",
2323
"license": "ISC",
2424
"dependencies": {
25+
"@fastify/cookie": "^11.0.2",
2526
"@fastify/cors": "^11.0.1",
27+
"@fastify/jwt": "^9.1.0",
2628
"@prisma/client": "6.10.1",
2729
"@types/bcryptjs": "^3.0.0",
2830
"bcryptjs": "^3.0.2",
2931
"fastify": "^5.4.0",
3032
"zod": "^3.25.67"
3133
},
3234
"devDependencies": {
35+
"@biomejs/biome": "2.1.1",
3336
"@faker-js/faker": "^9.9.0",
3437
"@types/node": "^24.0.4",
3538
"@vitest/coverage-v8": "3.2.4",
3639
"@vitest/ui": "3.2.4",
37-
"biome": "^0.3.3",
3840
"prisma": "^6.10.1",
3941
"tsup": "^8.5.0",
4042
"tsx": "^4.20.3",

pnpm-lock.yaml

Lines changed: 197 additions & 708 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/@types/fastify-jwt.d.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import "@fastify/jwt"
2+
3+
declare module "@fastify/jwt" {
4+
interface FastifyJWT {
5+
user: {
6+
sub: string,
7+
}
8+
}
9+
}

src/env.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ import { z } from 'zod/v4';
33
const envSchema = z.object({
44
PORT: z.coerce.number().default(3000),
55
NODE_ENV: z.enum(['dev', 'test', 'prod']).default('prod'),
6-
DATABASE_URL: z.string()
6+
DATABASE_URL: z.string(),
7+
JWT_SECRET: z.string(),
78
});
89

910
const _env = envSchema.safeParse(process.env)

src/http/controllers/orgs/authOrgsController.ts

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,30 @@ export const authOrgsController = async (
1717
try
1818
{
1919
const authOrgsUseCase = makeAuthOrgsUseCase();
20-
await authOrgsUseCase.execute(bodyData);
20+
const { org } = await authOrgsUseCase.execute(bodyData);
2121

22+
const token = await reply.jwtSign({}, {
23+
sign: {
24+
sub: org.id
25+
}
26+
})
27+
28+
const refreshToken = await reply.jwtSign({}, {
29+
sign: {
30+
sub: org.id,
31+
expiresIn: '7d'
32+
}
33+
})
34+
35+
reply
36+
.setCookie('refreshToken', refreshToken, {
37+
path: '/',
38+
secure: true,
39+
sameSite: true,
40+
httpOnly: true,
41+
})
42+
.status(200)
43+
.send({ token });
2244
} catch (error)
2345
{
2446
if (error instanceof InvalidCredentialsError)
@@ -28,6 +50,4 @@ export const authOrgsController = async (
2850

2951
throw error;
3052
}
31-
32-
reply.status(200).send();
3353
}

src/http/controllers/orgs/getOrgsProfileController.ts

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,22 @@
11
import { ResourceNotFoundError } from '@/use-cases/errors/resourceNotFound';
2-
import { makeAuthOrgsUseCase } from "@/use-cases/factories/makeAuthOrgsUseCase";
32
import { makeGetOrgsProfileUseCase } from "@/use-cases/factories/makeGetProfileOrgsUseCase";
43
import { FastifyReply, FastifyRequest } from "fastify";
5-
import { z } from "zod/v4";
64

75
export const getOrgsProfileController = async (
86
request: FastifyRequest,
97
reply: FastifyReply,
108
) => {
11-
const getOrgsProfileBodySchema = z.object({
12-
orgId: z.string()
13-
});
14-
15-
const paramsData = getOrgsProfileBodySchema.parse(request.params);
9+
const orgId = request.user.sub;
1610

1711
try
1812
{
1913
const getOrgsProfileUseCase = makeGetOrgsProfileUseCase();
20-
const { org } = await getOrgsProfileUseCase.execute(paramsData);
14+
const { org } = await getOrgsProfileUseCase.execute({ orgId });
2115

22-
reply.status(200).send(org);
16+
reply.status(200).send({
17+
...org,
18+
password: undefined
19+
});
2320
} catch (error)
2421
{
2522
if (error instanceof ResourceNotFoundError)

src/http/controllers/orgs/orgsRoutes.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,14 @@ import { FastifyInstance } from "fastify";
22
import { createOrgsController } from "./createOrgsController";
33
import { authOrgsController } from "./authOrgsController";
44
import { getOrgsProfileController } from "./getOrgsProfileController";
5+
import { authMiddleware } from "@/http/middlewares/authMiddleware";
6+
import { RefreshOrgsController } from "./refreshOrgsController";
57

68
export const orgsRoutes = async (app: FastifyInstance) => {
79
app.post('/orgs', createOrgsController);
10+
811
app.post('/orgs/auth', authOrgsController);
9-
app.get('/orgs/:orgId', getOrgsProfileController);
12+
app.patch('/orgs/refresh', RefreshOrgsController);
13+
14+
app.get('/orgs/profile', { onRequest: [authMiddleware] }, getOrgsProfileController);
1015
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { InvalidCredentialsError } from "@/use-cases/errors/invalidCredentialsError";
2+
import type { FastifyReply, FastifyRequest } from "fastify";
3+
4+
export const RefreshOrgsController = async (
5+
request: FastifyRequest,
6+
reply: FastifyReply,
7+
) => {
8+
await request.jwtVerify({ onlyCookie: true });
9+
10+
try
11+
{
12+
const token = await reply.jwtSign({}, {
13+
sign: {
14+
sub: request.user.sub
15+
}
16+
})
17+
18+
const refreshToken = await reply.jwtSign({}, {
19+
sign: {
20+
sub: request.user.sub,
21+
expiresIn: '7d'
22+
}
23+
})
24+
25+
reply
26+
.setCookie('refreshToken', refreshToken, {
27+
path: '/',
28+
secure: true,
29+
sameSite: true,
30+
httpOnly: true,
31+
})
32+
.status(200)
33+
.send({ token });
34+
} catch (error)
35+
{
36+
if (error instanceof InvalidCredentialsError)
37+
{
38+
return reply.status(400).send(error.message);
39+
}
40+
41+
throw error;
42+
}
43+
}

0 commit comments

Comments
 (0)