Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/iDevRanjan/lws-ra-b4-assignment-five/llms.txt

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

LWS Job Portal uses JSON Web Tokens (JWT) for stateless authentication. Every account belongs to one of two roles — USER (job seekers) and COMPANY (employers) — and each role unlocks different API capabilities. After registering or logging in, you receive a signed 30-day token that must accompany every request to a protected endpoint via the Authorization: Bearer <token> header. The frontend stores this token in localStorage and attaches it automatically. Server-side, the protect middleware validates the token and populates req.user or req.company, while authorize(role) enforces role-level access control.
Tokens expire after 30 days. When a token expires, the client must call POST /api/auth/login again to obtain a fresh one. No refresh token flow exists in the current implementation.

How JWT Auth Works

1

Register or Log in

Call POST /api/auth/register or POST /api/auth/login. Both endpoints return a token string and a data object with the account details.
2

Store the token

Persist the token in localStorage (or a secure cookie). The official frontend stores it under the key token.
3

Attach to every protected request

Add the Authorization header to every request that requires authentication:
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
4

Token is verified server-side

The protect middleware decodes the JWT, reads the embedded id and role, then fetches the matching User or Company record from the database and attaches it to the request context.

Roles

RoleDescription
USERJob seekers who search and apply for positions
COMPANYEmployers who post jobs and manage applications

Middleware Reference

Reads the Authorization header, extracts the token, verifies it with JWT_SECRET, and populates either req.user (for USER tokens) or req.company (for COMPANY tokens). Also sets req.userRole.Failure responses:
  • 401 Not authorized, no token — header missing
  • 401 Not authorized, token failed — token invalid or expired
  • 401 Not authorized, user not found — token valid but user account deleted
  • 401 Not authorized, company not found — token valid but company account deleted
Wraps one or more allowed role strings. Returns 403 Forbidden if req.userRole does not match.
router.post('/jobs', protect, authorize('COMPANY'), createJob);

Endpoints

POST /api/auth/register

Register a new user or company account. On success the server creates the record, generates a signed JWT, and returns both immediately — no separate login step required. Auth: None

Request

name
string
required
Full name for a user, or company display name for a company account.
email
string
required
Must be a valid email address. Checked for uniqueness across both User and Company tables.
password
string
required
Plain-text password — hashed with bcrypt (salt rounds: 10) before storage.
role
string
required
Must be exactly USER or COMPANY. Any other value returns 400 Invalid role.
...otherData
object
Any additional fields passed alongside the required four are spread directly onto the created record. Useful for providing optional profile data at registration time (e.g. title, industry).

Response

success
boolean
true on a successful registration.
token
string
Signed JWT valid for 30 days. Include this in the Authorization: Bearer header on all subsequent requests.
data
object

Example

curl -X POST https://api.example.com/api/auth/register \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Jane Doe",
    "email": "jane@example.com",
    "password": "secret123",
    "role": "USER"
  }'
{
  "success": true,
  "data": {
    "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "name": "Jane Doe",
    "email": "jane@example.com",
    "role": "USER"
  },
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}

POST /api/auth/login

Authenticate an existing user or company and receive a fresh JWT. Auth: None

Request

email
string
required
The registered email address.
password
string
required
Plain-text password. Compared against the bcrypt hash stored in the database.
role
string
required
Must be USER or COMPANY. This tells the server which table to look up the account in.

Response

success
boolean
true on successful authentication.
token
string
Signed JWT valid for 30 days.
data
object

Example

curl -X POST https://api.example.com/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{
    "email": "jane@example.com",
    "password": "secret123",
    "role": "USER"
  }'
Response
{
  "success": true,
  "data": {
    "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "name": "Jane Doe",
    "email": "jane@example.com",
    "role": "USER"
  },
  "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
}
If the email is not found in the target role’s table, or the password does not match, the server returns 400 Invalid credentials. No distinction is made between “account not found” and “wrong password” to prevent user enumeration.

GET /api/auth/me

Return the full profile of the currently authenticated account. The response shape differs based on whether the token belongs to a USER or a COMPANY — both password fields are excluded from the response. Auth: Required — Bearer token (USER or COMPANY)

Request

No request body. Authentication is handled entirely by the Authorization header.

Response

success
boolean
true when the profile is found.
data
object
The full User or Company record from the database, with password excluded. See the Users API or Companies API for the complete list of fields on each model.

Example

curl https://api.example.com/api/auth/me \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
Response (USER)
{
  "success": true,
  "data": {
    "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
    "name": "Jane Doe",
    "email": "jane@example.com",
    "role": "USER",
    "title": "Frontend Developer",
    "bio": "Passionate about building great UX.",
    "city": "Dhaka",
    "country": "Bangladesh",
    "experienceLevel": "Mid",
    "skills": ["React", "TypeScript", "CSS"],
    "createdAt": "2024-01-15T10:30:00.000Z",
    "updatedAt": "2024-06-01T08:00:00.000Z"
  }
}

Error Reference

StatusMessageCause
400Please add all required fieldsMissing name, email, password, or role on register
400User already existsEmail is already registered in User or Company table
400Invalid rolerole is not USER or COMPANY
400Invalid credentialsEmail not found or password mismatch on login
401Not authorized, no tokenAuthorization header missing
401Not authorized, token failedToken is malformed, expired, or signed with wrong secret
401Not authorized, user not foundToken valid but the USER account has been deleted
401Not authorized, company not foundToken valid but the COMPANY account has been deleted
403User role X is not authorized…Token role does not match the route’s authorize() guard

Build docs developers (and LLMs) love