Overview
The Sessions API handles user authentication in the Adoptme system. It provides endpoints for user registration, login with JWT token generation, and retrieving the current authenticated user.
Base Path: /api/sessions
Source Files:
Routes: src/routes/sessions.router.js
Controller: src/controllers/sessions.controller.js
Authentication Method
The API uses JWT (JSON Web Tokens) stored in HTTP cookies for authentication:
Cookie Name: coderCookie (protected) or unprotectedCookie (unprotected)
Token Expiration: 1 hour
JWT Secret: tokenSecretJWT (hardcoded in source)
Cookie Max Age: 3600000ms (1 hour)
The JWT secret tokenSecretJWT is hardcoded in the controller. For production, move this to environment variables.
Register User
curl -X POST http://localhost:8080/api/sessions/register \
-H "Content-Type: application/json" \
-d '{
"first_name": "John",
"last_name": "Doe",
"email": "[email protected] ",
"password": "securePassword123"
}'
Endpoint
POST /api/sessions/register
Registers a new user in the system. Passwords are hashed using bcrypt before storage.
Request Body
User’s email address (must be unique)
User’s password (will be hashed with bcrypt before storage)
Example Request Body
{
"first_name" : "John" ,
"last_name" : "Doe" ,
"email" : "[email protected] " ,
"password" : "securePassword123"
}
Response
The newly created user’s ObjectId
Example Response
{
"status" : "success" ,
"payload" : "6893eaba2ac0b16fa177be7c"
}
Implementation Details
Password hashing (from src/controllers/sessions.controller.js:12):
const hashedPassword = await createHash ( password );
const user = {
first_name ,
last_name ,
email ,
password: hashedPassword
}
let result = await usersService . create ( user );
Error Responses
Show 400 Incomplete Values
{
"status" : "error" ,
"error" : "Incomplete values"
}
Returned when any required field is missing.
Show 400 User Already Exists
{
"status" : "error" ,
"error" : "User already exists"
}
Returned when trying to register with an email that’s already in use.
Show 500 Internal Server Error
Ha ocurrido un error en la petición, por favor ver detalle: [error]
Login
curl -X POST http://localhost:8080/api/sessions/login \
-H "Content-Type: application/json" \
-c cookies.txt \
-d '{
"email": "[email protected] ",
"password": "securePassword123"
}'
Endpoint
Authenticates a user and returns a JWT token in a cookie.
Request Body
User’s password (plain text - will be validated against hashed password)
Example Request Body
Response
The response includes a Set-Cookie header with the JWT token:
Set-Cookie: coderCookie=<jwt_token>; Max-Age=3600000; Path=/; HttpOnly
Example Response
{
"status" : "success" ,
"message" : "Logged in"
}
JWT Token Payload
The JWT token contains a UserDTO with the following fields (from src/controllers/sessions.controller.js:35-36):
const userDto = UserDTO . getUserTokenFrom ( user );
const token = jwt . sign ( userDto , 'tokenSecretJWT' , { expiresIn: "1h" });
The UserDTO typically includes:
User ID
Email
Role
Other non-sensitive user information
Error Responses
Show 400 Incomplete Values
{
"status" : "error" ,
"error" : "Incomplete values"
}
Returned when email or password is missing.
Show 404 User Doesn't Exist
{
"status" : "error" ,
"error" : "User doesn't exist"
}
Returned when no user with the provided email exists.
Show 400 Incorrect Password
{
"status" : "error" ,
"error" : "Incorrect password"
}
Returned when the password doesn’t match the stored hash.
Show 500 Internal Server Error
Ha ocurrido un error en la petición, por favor ver detalle: [error]
Get Current User
curl -X GET http://localhost:8080/api/sessions/current \
-b cookies.txt
Endpoint
GET /api/sessions/current
Retrieves the currently authenticated user’s information from the JWT token stored in the coderCookie cookie.
Cookie: coderCookie=<jwt_token>
The cookie is automatically sent by the browser if you’re using credentials: 'include' in fetch or similar options in other HTTP clients.
Response
Decoded JWT token payload containing user information
Example Response
{
"status" : "success" ,
"payload" : {
"_id" : "6893eaba2ac0b16fa177be7c" ,
"email" : "[email protected] " ,
"role" : "user"
}
}
Implementation Details
From src/controllers/sessions.controller.js:43-51:
const current = async ( req , res ) => {
try {
const cookie = req . cookies [ 'coderCookie' ]
const user = jwt . verify ( cookie , 'tokenSecretJWT' );
if ( user )
return res . send ({ status: "success" , payload:user })
} catch ( error ) {
res . status ( 500 ). send ( "Ha ocurrido un error en la petición, por favor ver detalle: " , error )
}
}
Error Responses
Show 500 Invalid/Expired Token
Ha ocurrido un error en la petición, por favor ver detalle: [error]
Returned when:
No cookie is present
Token is invalid or malformed
Token has expired (after 1 hour)
Token signature is invalid
Unprotected Login
Endpoint
GET /api/sessions/unprotectedLogin
An alternative login endpoint that uses query parameters instead of request body and stores the full user object (not just a DTO) in the JWT token.
This endpoint is called “unprotected” because it stores the complete user object (including hashed password) in the JWT token, which is a security risk. Use the regular /login endpoint in production.
Query Parameters
Response
Sets cookie unprotectedCookie and returns:
{
"status" : "success" ,
"message" : "Unprotected Logged in"
}
Implementation Note
From src/controllers/sessions.controller.js:62:
const token = jwt . sign ( user , 'tokenSecretJWT' , { expiresIn: "1h" });
res . cookie ( 'unprotectedCookie' , token , { maxAge: 3600000 })
Notice it signs the entire user object, not a sanitized DTO.
Unprotected Current User
curl -X GET http://localhost:8080/api/sessions/unprotectedCurrent \
-b cookies.txt
Endpoint
GET /api/sessions/unprotectedCurrent
Retrieves the current user from the unprotectedCookie cookie.
Response
{
"status" : "success" ,
"payload" : {
"_id" : "6893eaba2ac0b16fa177be7c" ,
"first_name" : "John" ,
"last_name" : "Doe" ,
"email" : "[email protected] " ,
"password" : "$2b$10$hashedpassword..." ,
"role" : "user" ,
"pets" : []
}
}
The response includes the hashed password, which should never be exposed. This is why this endpoint is “unprotected” - it’s less secure.
Complete Authentication Flow
1. Register
curl -X POST http://localhost:8080/api/sessions/register \
-H "Content-Type: application/json" \
-d '{
"first_name": "Jane",
"last_name": "Smith",
"email": "[email protected] ",
"password": "mypassword"
}'
Response:
{
"status" : "success" ,
"payload" : "6893eaba2ac0b16fa177be7d"
}
2. Login
curl -X POST http://localhost:8080/api/sessions/login \
-H "Content-Type: application/json" \
-c cookies.txt \
-d '{
"email": "[email protected] ",
"password": "mypassword"
}'
Response:
{
"status" : "success" ,
"message" : "Logged in"
}
3. Access Protected Resources
curl -X GET http://localhost:8080/api/sessions/current \
-b cookies.txt
Response:
{
"status" : "success" ,
"payload" : {
"_id" : "6893eaba2ac0b16fa177be7d" ,
"email" : "[email protected] " ,
"role" : "user"
}
}
Implementation Details
Password Hashing
Passwords are hashed using bcrypt via the createHash utility function from src/utils/index.js.
Password Validation
Password validation uses the passwordValidation utility function (from src/controllers/sessions.controller.js:33):
const isValidPassword = await passwordValidation ( user , password );
if ( ! isValidPassword ) return res . status ( 400 ). send ({ status: "error" , error: "Incorrect password" });
Router Configuration
Routes are defined in src/routes/sessions.router.js:
router . post ( '/register' , sessionsController . register );
router . post ( '/login' , sessionsController . login );
router . get ( '/current' , sessionsController . current );
router . get ( '/unprotectedLogin' , sessionsController . unprotectedLogin );
router . get ( '/unprotectedCurrent' , sessionsController . unprotectedCurrent );
Security Considerations
Hardcoded JWT Secret: The JWT secret tokenSecretJWT is hardcoded in the controller. Move this to environment variables:const token = jwt . sign ( userDto , process . env . JWT_SECRET , { expiresIn: "1h" });
Unprotected Endpoints: The /unprotectedLogin and /unprotectedCurrent endpoints store/expose the full user object including the hashed password. These should not be used in production.
Cookie Security: Consider adding httpOnly, secure, and sameSite flags to cookies:res . cookie ( 'coderCookie' , token , {
maxAge: 3600000 ,
httpOnly: true ,
secure: true , // HTTPS only
sameSite: 'strict'
})
Token Expiration: Tokens expire after 1 hour. After expiration, users must log in again. Consider implementing refresh tokens for better UX.
Users API Manage user profiles after authentication
Adoptions API Create adoptions as an authenticated user