Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/tech-dipesh/yeti-Jobs/llms.txt

Use this file to discover all available pages before exploring further.

Yeti Jobs uses a stateless JWT-based authentication system. On a successful login or signup, the server signs a token with JSON_SECRET_KEY and delivers it in an HTTP-only cookie — it never touches the client’s JavaScript. Every subsequent request to a protected route is validated by the isLoggedIn middleware, which reads and verifies that cookie automatically. New accounts are issued an unverified JWT immediately after signup; email verification upgrades it to a verified one before the user can access any protected endpoint.

Full Authentication Flow

1

Sign Up

Send a POST request to /api/v1/users/signup with the user’s details. The server validates the payload with a Zod schema, checks that the email domain resolves via DNS MX lookup, hashes the password with bcrypt (12 salt rounds), and inserts the new record into the users table.A 6-digit verification code is immediately generated and emailed via Nodemailer. An unverified JWT cookie is set so the client can proceed to the verification step without a separate login.Required body fields
FieldTypeNotes
fnamestringFirst name
lnamestringLast name
emailstringMust pass DNS MX validation
passwordstringHashed with bcrypt before storage
educationstringOptional education level
curl -X POST https://api.yetijobs.com/api/v1/users/signup \
  -H "Content-Type: application/json" \
  -c cookies.txt \
  -d '{
    "fname": "Jane",
    "lname": "Doe",
    "email": "jane@example.com",
    "password": "Sup3rS3cure!",
    "education": "Bachelors"
  }'
{
  "message": "Succssfully Signed Up, Verification Code have been sent to your mail"
}
The alreadyLoggedIn middleware guards this route. If a valid JWT cookie is already present, the server returns 409 Conflict before the signup logic runs.
2

Verify Email

After signup, the user receives a 6-digit code by email. Submit it to /api/v1/users/verify. The isAuthButUnverified middleware ensures only holders of an unverified JWT can reach this endpoint.The server looks up the most recent email_verified row for the user, checks the code matches, confirms it has not expired, and if valid:
  1. Marks the email_verified row as is_verified = true
  2. Issues a new JWT cookie with verify: true — this is the token that unlocks all protected routes
curl -X POST https://api.yetijobs.com/api/v1/users/verify \
  -H "Content-Type: application/json" \
  -b cookies.txt -c cookies.txt \
  -d '{ "code": 482910 }'
{
  "message": "Verification Code Have Been Succssfully Verified"
}
If the code is expired or already used, the server returns 403 Forbidden. To get a fresh code, call POST /api/v1/users/verify/resend.
The /verify, /verify/resend, /forget-password, and /forget-password/verify routes all share a strict rate limit of 2 requests per minute per IP. See Rate Limiting for details.
3

Log In

Existing users (with a verified account) call POST /api/v1/users/login. The controller validates the body with the loginUserSchema Zod schema, fetches the hashed password from the database, and runs a bcrypt comparison. On success it issues a fresh JWT cookie.The JWT payload contains:
ClaimDescription
uidUser’s UUID primary key
roleguest, recruiter, or admin
company_idUUID of the associated company, or null
verifyBoolean — true once email has been confirmed
curl -X POST https://api.yetijobs.com/api/v1/users/login \
  -H "Content-Type: application/json" \
  -c cookies.txt \
  -d '{
    "email": "jane@example.com",
    "password": "Sup3rS3cure!"
  }'
{ "message": "Succssfully Logged In" }
The token is signed with JSON_SECRET_KEY and expires in 7 days. The cookie is set with httpOnly: true, secure: true, and sameSite: "none" so it works across the separate front-end and back-end origins.
If the account exists but the email has not been verified, the login still issues a cookie but verify will be false. The isLoggedIn middleware will reject all protected requests with 403 until verification is complete.
4

Check Auth Status

The front end can call GET /api/v1/users/login-status at startup to determine the current session state without requiring the user to log in again. This endpoint does not use the isLoggedIn middleware — it handles its own token inspection and returns structured status flags.
curl https://api.yetijobs.com/api/v1/users/login-status \
  -b cookies.txt
Possible responses
ScenarioStatusBody
No cookie401{ "message": { "login": false, "verify": false } }
Cookie present, unverified403{ "message": { "login": true, "verify": false } }
Fully authenticated200JWT payload + { "url": "<profile_pic_url>" }
5

Log Out

GET /api/v1/users/logout clears the token cookie by calling res.clearCookie with the same httpOnly, secure, and sameSite options used when it was set. No database writes are needed since the system is stateless.
curl https://api.yetijobs.com/api/v1/users/logout \
  -b cookies.txt -c cookies.txt
{ "message": "Logged Out Succssfully" }
6

Password Reset

Password reset is a two-step flow, both steps protected by the 2 req/min rate limit.Step 1 — Request a reset code
curl -X POST https://api.yetijobs.com/api/v1/users/forget-password \
  -H "Content-Type: application/json" \
  -d '{ "email": "jane@example.com" }'
The server verifies the email exists, then calls sendMail with type = 'forget'. A new row is inserted into email_verified with verified_type = 'forget_password'.Step 2 — Submit code and new password
curl -X POST https://api.yetijobs.com/api/v1/users/forget-password/verify \
  -H "Content-Type: application/json" \
  -d '{
    "email": "jane@example.com",
    "code": 739201,
    "newpassword": "NewS3cure!Pass"
  }'
The controller checks the code against the email_verified table (joined with users for the email match), confirms it has not expired or been used, prevents reuse of the existing password via bcrypt compare, then updates users.password and marks the code as used inside a single database transaction (BEGIN / COMMIT / ROLLBACK).
The VerifyJwt service (src/services/verifyJwt.js) handles all token creation:
const VerifyJwt = (res, content) => {
  const storeJwt = jwt.sign(content, process.env.JSON_SECRET_KEY, {
    expiresIn: "7d",
  });
  const allCookiesOptinos = {
    httpOnly: true,
    secure: true,
    sameSite: "none",
    maxAge: process.env.MAXAGE,
  };
  res.cookie("token", storeJwt, allCookiesOptinos);
};
OptionValueWhy
httpOnlytrueCookie is inaccessible to JavaScript — blocks XSS theft
securetrueCookie only sent over HTTPS
sameSite"none"Required for cross-origin front-end / back-end deployments
maxAgeprocess.env.MAXAGEConfigurable lifetime; token itself expires in 7 days
expiresIn"7d"JWT hard expiry, enforced on every jwt.verify call

The isLoggedIn Middleware

Every protected route (companies, applications, admin, notifications) is guarded by authUserMiddleware (src/Middleware/isLoggedIn.js):
const authUserMiddleware = async (req, res, next) => {
  const { token } = req.cookies;
  if (!token) return res.status(401).json({ message: 'No token Please Logged in First' });
  try {
    req.user = jwt.verify(token, process.env.JSON_SECRET_KEY);
    if (req.user.verify === false) {
      return res.status(403).json({ message: "Please Verify Your verification code." });
    }
    next();
  } catch (err) {
    return res.status(403).json({ message: 'Invalid token Please Logged in First' });
  }
};
After a successful jwt.verify, the decoded payload is attached to req.user. All downstream middleware (isAdmin, isJobSeeker, isCompanyEmployee, isOwner) read role and identity data from req.user — they never query the database for basic identity checks.

Required Environment Variables

VariableDescription
JSON_SECRET_KEYHMAC secret used to sign and verify all JWTs
MAXAGECookie maxAge in milliseconds
NODEMAILER_MY_EMAILSender email address for verification codes
NODEMAILER_MY_HOSTSMTP host (e.g. smtp.gmail.com)
NODEMAILER_MY_PASSWORDSMTP authentication password / app password

Build docs developers (and LLMs) love