PASSPORT LOCAL

Nest Passport Strategy와 Guard

Passport를 붙였다고 인증이 끝나는 것은 아니다. LocalStrategy의 validate에서 사용자 없음, 비밀번호 불일치, 비활성 계정, 세션 저장 여부를 분기하고, Guard가 실패를 어떤 응답으로 바꿀지 정해야 실제 로그인 흐름이 안정된다.

자격 증명 DTO에서 들어온 username, password, 컨텍스트를 최소 정보로 정리한다
전략 검증 LocalStrategy가 사용자 조회와 비밀번호 비교 실패 이유를 분기한다
Guard 응답 request.user 생성 여부와 예외 응답을 같은 정책으로 맞춘다
01

자격 증명 수신

username/email과 password를 DTO로 받고 빈 값과 형식을 먼저 거른다.

전략에 도달하기 전 요청 모양을 안정화한다
02

사용자 조회

LocalStrategy.validate에서 계정을 찾고 삭제, 잠금, 미인증 상태를 나눈다.

없는 사용자와 잠긴 사용자는 같은 메시지로 숨길 수 있다
03

비밀번호 비교

저장된 해시와 입력값을 timing-safe한 방식으로 비교한다.

평문 비교나 hash 재사용 실수를 막는다
04

Guard 결과 처리

성공하면 request.user를 채우고 실패하면 Unauthorized 흐름으로 응답을 정리한다.

validate가 null을 반환하는지 예외를 던지는지 정책을 맞춘다
05

상태 발급

세션이면 serializeUser, JWT면 토큰 발급과 만료 정책으로 이어간다.

둘을 섞으면 로그아웃과 재인증 흐름이 꼬인다
사용자 없음
조회 실패 이메일 존재 여부를 노출하지 않도록 응답 문구와 지연을 맞춘다.
로그에는 내부 사유를 남긴다
비밀번호 오류
해시 불일치 시도 횟수, 잠금, 알림 정책을 인증 서비스에서 같이 처리한다.
성공 경로와 같은 DTO를 반환하지 않는다
Guard 실패
라우트 차단 request.user가 비어 있으면 컨트롤러에 들어가기 전에 401로 닫는다.
컨트롤러에서 다시 검사하지 않게 만든다
세션/JWT
상태 보관 방식 서버 저장이 필요한지, stateless API가 필요한지에 따라 선택한다.
로그아웃 처리 방식이 달라진다

로그인 확인

실패 케이스 없는 사용자, 틀린 비밀번호, 잠긴 계정, 비활성 계정을 각각 호출한다.
request.user Guard 통과 뒤 컨트롤러에서 필요한 사용자 필드만 존재하는지 확인한다.
상태 정책 세션 또는 JWT 중 하나의 로그아웃과 재로그인 흐름이 일관되는지 본다.