Authentication Semi-integration#10
Conversation
46f5c1a to
6c38acc
Compare
c70f814 to
2bb620e
Compare
d3c4d7e to
b6c8643
Compare
b6c8643 to
97a4e27
Compare
There was a problem hiding this comment.
Pull request overview
Introduces an initial “signin” flow as part of authentication integration, adding request validation and a first database check via Prisma.
Changes:
- Added a new Zod schema for sign-in request payloads.
- Added a new
signincontroller handler that parses the payload and checks for an existing user by email via Prisma.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 6 comments.
| File | Description |
|---|---|
| modules/auth/schemas/signin.schema.ts | Adds SignInSchema to validate sign-in request bodies. |
| modules/auth/controllers/index.controller.ts | Adds signin handler and Prisma lookup for email existence. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| } catch (e) { | ||
| if (e instanceof UnauthorizedError) { | ||
| reply.status(401).send({ error: e.message }); | ||
| } else { | ||
| reply.status(500).send({ error: req.t("Server error") }); | ||
| } |
There was a problem hiding this comment.
signin can complete without ever sending a response (when userCounter === 0), which will leave the client hanging or produce an unintended empty response. Ensure the handler returns/sends a success payload (and likely creates the user / issues tokens) for the non-error path.
| } catch (e) { | |
| if (e instanceof UnauthorizedError) { | |
| reply.status(401).send({ error: e.message }); | |
| } else { | |
| reply.status(500).send({ error: req.t("Server error") }); | |
| } | |
| return reply.status(204).send(); | |
| } catch (e) { | |
| if (e instanceof ZodError) { | |
| return reply.status(400).send({ | |
| error: req.t("Invalid credentials"), | |
| details: e.issues, | |
| }); | |
| } | |
| if (e instanceof UnauthorizedError) { | |
| return reply.status(401).send({ error: e.message }); | |
| } | |
| return reply.status(500).send({ error: req.t("Server error") }); |
| } catch (e) { | ||
| if (e instanceof UnauthorizedError) { | ||
| reply.status(401).send({ error: e.message }); | ||
| } else { | ||
| reply.status(500).send({ error: req.t("Server error") }); | ||
| } |
There was a problem hiding this comment.
This handler parses SignInSchema but doesn't handle ZodError; invalid request bodies will be reported as 500 instead of a 400 with validation details (unlike login, refresh, revoke). Consider mirroring the existing error handling pattern here (including console.debug and returning e.issues).
| throw new UnauthorizedError(req.t("Email already in use")); | ||
| } | ||
| } catch (e) { | ||
| if (e instanceof UnauthorizedError) { | ||
| reply.status(401).send({ error: e.message }); | ||
| } else { | ||
| reply.status(500).send({ error: req.t("Server error") }); | ||
| } |
There was a problem hiding this comment.
The "Email already in use" case is returned as 401 Unauthorized. That status code is typically reserved for missing/invalid authentication; for a registration conflict, use a more appropriate status (commonly 409) and error type/message to avoid confusing API consumers.
| throw new UnauthorizedError(req.t("Email already in use")); | |
| } | |
| } catch (e) { | |
| if (e instanceof UnauthorizedError) { | |
| reply.status(401).send({ error: e.message }); | |
| } else { | |
| reply.status(500).send({ error: req.t("Server error") }); | |
| } | |
| return reply.status(409).send({ | |
| error: req.t("Email already in use"), | |
| }); | |
| } | |
| } catch (e) { | |
| reply.status(500).send({ error: req.t("Server error") }); |
| const { password, ...credentials } = SignInSchema.parse(req.body); | ||
|
|
||
| const userCounter = await prisma.user.count({ | ||
| where: { | ||
| email: credentials.email, |
There was a problem hiding this comment.
signin destructures password and requires username in the schema, but neither password nor username is used in the handler (only credentials.email). This is likely a logic error (or premature schema) and also triggers unused-variable linting; either use these fields as part of the flow or remove/relax them in the schema/destructuring to match what the endpoint actually needs.
| const { password, ...credentials } = SignInSchema.parse(req.body); | |
| const userCounter = await prisma.user.count({ | |
| where: { | |
| email: credentials.email, | |
| const { email } = SignInSchema.pick({ email: true }).parse(req.body); | |
| const userCounter = await prisma.user.count({ | |
| where: { | |
| email, |
| const userCounter = await prisma.user.count({ | ||
| where: { | ||
| email: credentials.email, | ||
| }, | ||
| }); | ||
|
|
||
| if (userCounter > 0) { |
There was a problem hiding this comment.
Since email is @unique in the Prisma schema, doing a count() is more work than necessary for an existence check. Prefer findUnique({ where: { email }, select: { id: true } }) (or similar) to reduce DB work and make intent explicit.
| const userCounter = await prisma.user.count({ | |
| where: { | |
| email: credentials.email, | |
| }, | |
| }); | |
| if (userCounter > 0) { | |
| const existingUser = await prisma.user.findUnique({ | |
| where: { | |
| email: credentials.email, | |
| }, | |
| select: { | |
| id: true, | |
| }, | |
| }); | |
| if (existingUser) { |
| username: z.string().min(3).max(30), | ||
| password: z.string().min(8), |
There was a problem hiding this comment.
SignInSchema currently requires email, username, and password, but the new signin handler only uses email (and discards password). If the endpoint is meant to authenticate, requiring both email and username is unusually strict; if it's meant to register, the schema name is misleading. Adjust the schema (e.g., make fields optional/union) and/or rename it to match the intended flow.
| username: z.string().min(3).max(30), | |
| password: z.string().min(8), | |
| username: z.string().min(3).max(30).optional(), | |
| password: z.string().min(8).optional(), |
97a4e27 to
818984d
Compare
|
🚀 Preview deployed: https://api-preview-10-nnratsflva-uc.a.run.app |
No description provided.