feat: Add refresh token endpoint and remember me support
- Add POST /auth/refresh endpoint for token renewal - Only set refresh token cookie when rememberMe is true - Add rememberMe field to login validator schema Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -6,13 +6,15 @@ import {
|
||||
logLogin,
|
||||
logLogout,
|
||||
} from '../services/audit.service.js';
|
||||
import { verifyRefreshToken, generateAccessToken } from '../utils/jwt.js';
|
||||
import { getUserById } from '../services/auth.service.js';
|
||||
|
||||
/**
|
||||
* KROK 1: Login s temporary password
|
||||
* POST /api/auth/login
|
||||
*/
|
||||
export const login = async (req, res, next) => {
|
||||
const { username, password } = req.body;
|
||||
const { username, password, rememberMe } = req.body;
|
||||
const ipAddress = req.ip || req.connection.remoteAddress;
|
||||
const userAgent = req.headers['user-agent'];
|
||||
|
||||
@@ -37,12 +39,15 @@ export const login = async (req, res, next) => {
|
||||
maxAge: 60 * 60 * 1000, // 1 hodina
|
||||
});
|
||||
|
||||
res.cookie('refreshToken', result.tokens.refreshToken, {
|
||||
httpOnly: true,
|
||||
secure: isProduction,
|
||||
sameSite: isProduction ? 'strict' : 'lax',
|
||||
maxAge: 7 * 24 * 60 * 60 * 1000, // 7 dní
|
||||
});
|
||||
// Refresh token iba ak user chce zostať prihlásený
|
||||
if (rememberMe) {
|
||||
res.cookie('refreshToken', result.tokens.refreshToken, {
|
||||
httpOnly: true,
|
||||
secure: isProduction,
|
||||
sameSite: isProduction ? 'strict' : 'lax',
|
||||
maxAge: 7 * 24 * 60 * 60 * 1000, // 7 dní
|
||||
});
|
||||
}
|
||||
|
||||
res.status(200).json({
|
||||
success: true,
|
||||
@@ -62,6 +67,68 @@ export const login = async (req, res, next) => {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Refresh access token using refresh token
|
||||
* POST /api/auth/refresh
|
||||
*/
|
||||
export const refreshToken = async (req, res, next) => {
|
||||
try {
|
||||
const token = req.cookies?.refreshToken;
|
||||
|
||||
if (!token) {
|
||||
return res.status(401).json({
|
||||
success: false,
|
||||
error: {
|
||||
message: 'Refresh token nie je k dispozícii',
|
||||
statusCode: 401,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// Verify refresh token
|
||||
const decoded = verifyRefreshToken(token);
|
||||
|
||||
// Get user from DB
|
||||
const user = await getUserById(decoded.id);
|
||||
|
||||
// Generate new access token
|
||||
const newAccessToken = generateAccessToken({
|
||||
id: user.id,
|
||||
username: user.username,
|
||||
role: user.role,
|
||||
});
|
||||
|
||||
// Set new access token cookie
|
||||
const isProduction = process.env.NODE_ENV === 'production';
|
||||
res.cookie('accessToken', newAccessToken, {
|
||||
httpOnly: true,
|
||||
secure: isProduction,
|
||||
sameSite: isProduction ? 'strict' : 'lax',
|
||||
maxAge: 60 * 60 * 1000, // 1 hodina
|
||||
});
|
||||
|
||||
res.status(200).json({
|
||||
success: true,
|
||||
data: {
|
||||
accessToken: newAccessToken,
|
||||
},
|
||||
message: 'Token obnovený',
|
||||
});
|
||||
} catch (error) {
|
||||
// Clear invalid cookies
|
||||
res.clearCookie('accessToken');
|
||||
res.clearCookie('refreshToken');
|
||||
|
||||
return res.status(401).json({
|
||||
success: false,
|
||||
error: {
|
||||
message: 'Refresh token expiroval alebo je neplatný',
|
||||
statusCode: 401,
|
||||
},
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* KROK 2: Nastavenie nového hesla
|
||||
* POST /api/auth/set-password
|
||||
|
||||
@@ -25,6 +25,9 @@ router.post(
|
||||
authController.login
|
||||
);
|
||||
|
||||
// Refresh access token (public - uses refresh token from cookie)
|
||||
router.post('/refresh', authController.refreshToken);
|
||||
|
||||
/**
|
||||
* Protected routes (vyžadujú autentifikáciu)
|
||||
*/
|
||||
|
||||
@@ -15,6 +15,7 @@ export const loginSchema = z.object({
|
||||
invalid_type_error: 'Heslo musí byť text',
|
||||
})
|
||||
.min(1, 'Heslo nemôže byť prázdne'),
|
||||
rememberMe: z.boolean().optional().default(false),
|
||||
});
|
||||
|
||||
// Set new password schema (krok 2)
|
||||
|
||||
Reference in New Issue
Block a user