Login
curl --request POST \
--url https://api.example.com/api/v1/auth/login \
--header 'Content-Type: application/json' \
--data '
{
"email": "<string>",
"password": "<string>"
}
'import requests
url = "https://api.example.com/api/v1/auth/login"
payload = {
"email": "<string>",
"password": "<string>"
}
headers = {"Content-Type": "application/json"}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({email: '<string>', password: '<string>'})
};
fetch('https://api.example.com/api/v1/auth/login', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.example.com/api/v1/auth/login",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'email' => '<string>',
'password' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.example.com/api/v1/auth/login"
payload := strings.NewReader("{\n \"email\": \"<string>\",\n \"password\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.example.com/api/v1/auth/login")
.header("Content-Type", "application/json")
.body("{\n \"email\": \"<string>\",\n \"password\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/api/v1/auth/login")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n \"email\": \"<string>\",\n \"password\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"success": true,
"data": {
"id": "<string>",
"email": "<string>",
"firstName": "<string>",
"lastName": "<string>",
"profileImageUrl": {},
"isActive": true,
"isVerified": true,
"lastLoginAt": "<string>",
"createdAt": "<string>",
"updatedAt": "<string>",
"role": "<string>",
"accessToken": "<string>",
"name": "<string>",
"description": {},
"logoUrl": {},
"industry": "<string>",
"size": "<string>",
"type": "<string>",
"headquartersLocation": {},
"foundedYear": {},
"websiteUrl": {},
"benefits": {},
"linkedIn": {},
"facebook": {},
"twitter": {}
},
"message": "<string>",
"meta": {}
}Authentication
Login
Authenticate existing users and receive tokens
POST
/
api
/
v1
/
auth
/
login
Login
curl --request POST \
--url https://api.example.com/api/v1/auth/login \
--header 'Content-Type: application/json' \
--data '
{
"email": "<string>",
"password": "<string>"
}
'import requests
url = "https://api.example.com/api/v1/auth/login"
payload = {
"email": "<string>",
"password": "<string>"
}
headers = {"Content-Type": "application/json"}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({email: '<string>', password: '<string>'})
};
fetch('https://api.example.com/api/v1/auth/login', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.example.com/api/v1/auth/login",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'email' => '<string>',
'password' => '<string>'
]),
CURLOPT_HTTPHEADER => [
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.example.com/api/v1/auth/login"
payload := strings.NewReader("{\n \"email\": \"<string>\",\n \"password\": \"<string>\"\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.example.com/api/v1/auth/login")
.header("Content-Type", "application/json")
.body("{\n \"email\": \"<string>\",\n \"password\": \"<string>\"\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/api/v1/auth/login")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Content-Type"] = 'application/json'
request.body = "{\n \"email\": \"<string>\",\n \"password\": \"<string>\"\n}"
response = http.request(request)
puts response.read_body{
"success": true,
"data": {
"id": "<string>",
"email": "<string>",
"firstName": "<string>",
"lastName": "<string>",
"profileImageUrl": {},
"isActive": true,
"isVerified": true,
"lastLoginAt": "<string>",
"createdAt": "<string>",
"updatedAt": "<string>",
"role": "<string>",
"accessToken": "<string>",
"name": "<string>",
"description": {},
"logoUrl": {},
"industry": "<string>",
"size": "<string>",
"type": "<string>",
"headquartersLocation": {},
"foundedYear": {},
"websiteUrl": {},
"benefits": {},
"linkedIn": {},
"facebook": {},
"twitter": {}
},
"message": "<string>",
"meta": {}
}Endpoint
POST /api/v1/auth/login
http://localhost:3000/api/v1
This endpoint is public and does not require authentication.
Request Body
string
required
User’s registered email address (works for both job seekers and companies).
string
required
User’s password. Minimum 6 characters.
Request Shape
interface LoginDto {
email: string;
password: string;
}
Response
Success Response (200 OK)
TypeScript Types
interface JobSeekerLoginResponse {
success: boolean;
data: {
id: string;
email: string;
firstName: string;
lastName: string;
profileImageUrl: string | null;
isActive: boolean;
isVerified: boolean;
lastLoginAt: string;
createdAt: string;
updatedAt: string;
role: 'job-seeker';
accessToken: string;
};
message: string;
meta: {
timestamp: string;
path: string;
method: string;
};
}
interface CompanyLoginResponse {
success: boolean;
data: {
id: string;
email: string;
name: string;
description: string | null;
logoUrl: string | null;
industry: string;
size: 'SIZE_1_50' | 'SIZE_51_200' | 'SIZE_201_1000' | 'SIZE_1000_PLUS';
type: 'STARTUP' | 'SCALE_UP' | 'ENTERPRISE' | 'NON_PROFIT' | 'GOVERNMENT';
headquartersLocation: string | null;
foundedYear: number | null;
websiteUrl: string | null;
benefits: string | null;
linkedIn: string | null;
facebook: string | null;
twitter: string | null;
isActive: boolean;
isVerified: boolean;
createdAt: string;
updatedAt: string;
role: 'company';
accessToken: string;
};
message: string;
meta: {
timestamp: string;
path: string;
method: string;
};
}
For Job Seeker
{
"success": true,
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"email": "john.doe@example.com",
"firstName": "John",
"lastName": "Doe",
"profileImageUrl": null,
"isActive": true,
"isVerified": true,
"lastLoginAt": "2024-01-15T10:30:00.000Z",
"createdAt": "2024-01-15T10:00:00.000Z",
"updatedAt": "2024-01-15T10:30:00.000Z",
"role": "job-seeker",
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI1NTBlODQwMC1lMjliLTQxZDQtYTcxNi00NDY2NTU0NDAwMDAiLCJlbWFpbCI6ImpvaG4uZG9lQGV4YW1wbGUuY29tIiwidHlwZSI6IkpPQl9TRUVLRVIiLCJ0b2tlblR5cGUiOiJBQ0NFU1MiLCJpYXQiOjE3MDUzMTU4MDAsImV4cCI6MTcwNTMxOTQwMCwiYXVkIjoibG9jYWxob3N0OjMwMDAiLCJpc3MiOiJsb2NhbGhvc3Q6MzAwMCJ9.signature"
},
"meta": {
"timestamp": "2024-01-15T10:30:00.000Z",
"path": "/auth/login",
"method": "POST"
},
"message": "Login successfully"
}
For Company
{
"success": true,
"data": {
"id": "660f9500-f39c-52e5-b827-557766551111",
"email": "hr@techcorp.com",
"name": "TechCorp Inc.",
"description": null,
"logoUrl": null,
"industry": "Technology",
"size": "SIZE_51_200",
"type": "STARTUP",
"headquartersLocation": null,
"foundedYear": null,
"websiteUrl": null,
"benefits": null,
"linkedIn": null,
"facebook": null,
"twitter": null,
"isActive": true,
"isVerified": true,
"createdAt": "2024-01-15T10:00:00.000Z",
"updatedAt": "2024-01-15T10:30:00.000Z",
"role": "company",
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI2NjBmOTUwMC1mMzljLTUyZTUtYjgyNy01NTc3NjY1NTExMTEiLCJlbWFpbCI6ImhyQHRlY2hjb3JwLmNvbSIsInR5cGUiOiJDT01QQU5ZIiwidG9rZW5UeXBlIjoiQUNDRVNTIiwiaWF0IjoxNzA1MzE1ODAwLCJleHAiOjE3MDUzMTk0MDAsImF1ZCI6ImxvY2FsaG9zdDozMDAwIiwiaXNzIjoibG9jYWxob3N0OjMwMDAifQ.signature"
},
"meta": {
"timestamp": "2024-01-15T10:30:00.000Z",
"path": "/auth/login",
"method": "POST"
},
"message": "Login successfully"
}
boolean
Indicates if the login was successful.
object
Contains the user/company data and access token.
Show Job Seeker Properties
Show Job Seeker Properties
string
Unique user identifier (UUID).
string
User’s email address.
string
User’s first name.
string
User’s last name.
string | null
URL to user’s profile image.
boolean
Whether the account is active.
boolean
Whether the email is verified.
string
ISO 8601 timestamp of last login.
string
ISO 8601 timestamp of account creation.
string
ISO 8601 timestamp of last update.
string
User role. Always returns “job-seeker”.
string
JWT access token for authenticating API requests. Valid for 1 hour.
Show Company Properties
Show Company Properties
string
Unique company identifier (UUID).
string
Company’s email address.
string
Company name.
string | null
Company description.
string | null
URL to company logo.
string
Company industry.
string
Company size (SIZE_1_50, SIZE_51_200, SIZE_201_1000, SIZE_1000_PLUS).
string
Company type (STARTUP, SCALE_UP, ENTERPRISE, NON_PROFIT, GOVERNMENT).
string | null
Company headquarters location.
number | null
Year the company was founded.
string | null
Company website URL.
string | null
Company benefits description.
string | null
LinkedIn profile URL.
string | null
Facebook page URL.
string | null
Twitter profile URL.
boolean
Whether the account is active.
boolean
Whether the email is verified.
string
ISO 8601 timestamp of account creation.
string
ISO 8601 timestamp of last update.
string
User role. Always returns “company”.
string
JWT access token for authenticating API requests. Valid for 1 hour.
string
Human-readable success message.
object
Request metadata from global response interceptor.
Important: Refresh Token Cookie
The refresh token is automatically set as an HTTP-only cookie named
refreshToken. You must use
credentials: 'include' in your fetch requests to enable cookie handling.- Name:
refreshToken - HttpOnly: true (cannot be accessed via JavaScript)
- Secure: true (in production, requires HTTPS)
- SameSite: Strict
- Max-Age: 24 hours (86400 seconds)
What Happens on Login
1
User Lookup
System searches for user in both JobSeeker and Company tables
2
Email Verification Check
Verifies that the user’s email has been verified
3
Password Validation
Compares provided password with hashed password using bcrypt
4
Token Generation
Generates new JWT access and refresh tokens
5
Refresh Token Storage
Stores refresh token in Redis and sets HTTP-only cookie
6
Response
Returns user data with access token
Error Responses
400 Bad Request - Validation Error
Returned when request validation fails.{
"success": false,
"error": {
"message": ["email must be an email", "password must be longer than or equal to 6 characters"],
"statusCode": 400,
"timestamp": "2026-04-23T20:00:00.000Z",
"path": "/auth/login",
"method": "POST",
"details": "Bad Request"
}
}
401 Unauthorized - Invalid Credentials
Returned when email or password is incorrect.{
"success": false,
"error": {
"message": "Invalid credentials",
"statusCode": 401,
"timestamp": "2026-04-23T20:00:00.000Z",
"path": "/auth/login",
"method": "POST",
"details": "Unauthorized"
}
}
- Email doesn’t exist
- Password is incorrect
- Typo in email or password
401 Unauthorized - Email Not Verified
Returned when user hasn’t verified their email yet.{
"success": false,
"error": {
"message": "Please verify your email before logging in",
"statusCode": 401,
"timestamp": "2026-04-23T20:00:00.000Z",
"path": "/auth/login",
"method": "POST",
"details": "Unauthorized"
}
}
500 Internal Server Error
Returned when an unexpected error occurs.{
"success": false,
"error": {
"message": "Login failed",
"statusCode": 500,
"timestamp": "2026-04-23T20:00:00.000Z",
"path": "/auth/login",
"method": "POST",
"details": "Internal Server Error"
}
}
Validation Rules
| Field | Rules |
|---|---|
| Must be valid email format | |
| password | Minimum 6 characters |
Security Notes
Automatic User Type Detection: The API automatically detects whether you’re logging in as a
job seeker or company based on the email. You don’t need to specify the user type.
Cookie Credentials: Always use
credentials: 'include' in your fetch requests to enable
cookie handling for the refresh token.Response Types
// Request
interface LoginDto {
email: string;
password: string;
}
// Response - Job Seeker
interface JobSeekerLoginResponse {
success: boolean;
data: {
id: string;
email: string;
firstName: string;
lastName: string;
profileImageUrl: string | null;
isActive: boolean;
isVerified: boolean;
lastLoginAt: string;
createdAt: string;
updatedAt: string;
role: 'job-seeker';
accessToken: string;
};
message: string;
meta: {
timestamp: string;
path: string;
method: string;
};
}
// Response - Company
interface CompanyLoginResponse {
success: boolean;
data: {
id: string;
email: string;
name: string;
description: string | null;
logoUrl: string | null;
industry: string;
size: 'SIZE_1_50' | 'SIZE_51_200' | 'SIZE_201_1000' | 'SIZE_1000_PLUS';
type: 'STARTUP' | 'SCALE_UP' | 'ENTERPRISE' | 'NON_PROFIT' | 'GOVERNMENT';
headquartersLocation: string | null;
foundedYear: number | null;
websiteUrl: string | null;
benefits: string | null;
linkedIn: string | null;
facebook: string | null;
twitter: string | null;
isActive: boolean;
isVerified: boolean;
createdAt: string;
role: 'company';
updatedAt: string;
accessToken: string;
};
message: string;
meta: {
timestamp: string;
path: string;
method: string;
};
}
Related Endpoints
- Register Job Seeker - Create new job seeker account
- Register Company - Create new company account
- Verify Email - Verify email after registration
- Refresh Token - Get new access token when expired
