feat: NextAuth credentials + JWT 8h + rate limiting

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-07 00:05:14 +02:00
parent 2acf899465
commit f9a14b009a
5 changed files with 156 additions and 0 deletions
+68
View File
@@ -0,0 +1,68 @@
import { authOptions } from '@/lib/auth'
// Mock Prisma
jest.mock('@/lib/prisma', () => ({
prisma: {
user: {
findUnique: jest.fn(),
},
},
}))
// Mock rate-limit
jest.mock('@/lib/rate-limit', () => ({
checkRateLimit: jest.fn(() => true),
recordFailedAttempt: jest.fn(),
clearAttempts: jest.fn(),
}))
import { prisma } from '@/lib/prisma'
import { checkRateLimit, recordFailedAttempt, clearAttempts } from '@/lib/rate-limit'
const mockFindUnique = prisma.user.findUnique as jest.Mock
describe('NextAuth authorize', () => {
const authorize = (authOptions.providers[0] as any).options.authorize
beforeEach(() => jest.clearAllMocks())
it('retourne null si credentials manquants', async () => {
const result = await authorize({ email: '', password: '' }, {})
expect(result).toBeNull()
})
it('retourne null si utilisateur introuvable', async () => {
mockFindUnique.mockResolvedValue(null)
const result = await authorize(
{ email: 'a@b.com', password: 'wrong' },
{ headers: {} }
)
expect(result).toBeNull()
expect(recordFailedAttempt).toHaveBeenCalled()
})
it('retourne l\'utilisateur si mot de passe correct', async () => {
const { hash } = await import('bcryptjs')
const hashedPwd = await hash('correct', 12)
mockFindUnique.mockResolvedValue({
id: 'user1',
email: 'a@b.com',
name: 'Alice',
role: 'gestionnaire',
password: hashedPwd,
})
const result = await authorize(
{ email: 'a@b.com', password: 'correct' },
{ headers: {} }
)
expect(result).toEqual({ id: 'user1', email: 'a@b.com', name: 'Alice', role: 'gestionnaire' })
expect(clearAttempts).toHaveBeenCalled()
})
it('lève RATE_LIMITED si bloqué', async () => {
;(checkRateLimit as jest.Mock).mockReturnValue(false)
await expect(
authorize({ email: 'a@b.com', password: 'x' }, { headers: {} })
).rejects.toThrow('RATE_LIMITED')
})
})