인증을 직접 구현하며 정한 것들

인증은 라이브러리를 얹지 않고 지금 스택 위에 직접 올렸다. drizzle 로 테이블을 만들고, Nest tRPC 로 프로시저를 열고, React Router 가 쿠키를 굽는다. 스키마와 쿠키 정책을 우리가 들고 있으려고 한 선택이다.

세션은 해시만 저장한다

토큰은 32바이트 난수를 base64url 로 만들고, DB 에는 SHA-256 해시만 넣는다. sessions 테이블이 통째로 새어 나가도 그 값으로 쿠키를 되만들 수는 없다.

export function newToken(): string {
  return randomBytes(32).toString('base64url');
}

/** DB 에는 이것만 둔다. */
export function hashToken(token: string): string {
  return createHash('sha256').update(token).digest('hex');
}

세션 쿠키는 vl_session 하나, 만료는 30일이다. 남은 기간이 15일 아래로 내려간 세션은 me 를 부를 때 30일로 다시 늘린다. 쿠키는 프론트가 굽고 백엔드가 검증한다 — 브라우저는 프론트 서버만 만난다.

없는 계정에도 해시를 한 번 돌린다

로그인에서 사용자를 못 찾으면 바로 끝내는 편이 빠르다. 그런데 그러면 응답이 돌아오는 시간만 재도 가입 여부를 알 수 있다. 그래서 미리 박아 둔 더미 해시로 verify 를 한 번 돌린 뒤 실패를 돌려준다. 실패 이유도 나누지 않고 UNAUTHORIZED 하나로 답하고, 비밀번호 재설정 요청은 계정이 있든 없든 ok 로 답한다.

arctic 을 걷어내고 직접 불렀다

Google 로그인은 처음에 arctic 으로 붙였다가 걷어냈다. npm 이 그 패키지를 deprecated 로 표시했기 때문이다. 지금은 google-oauth-client.ts 가 인가 URL 을 만들고 토큰 엔드포인트를 fetch 로 부르는 PKCE(S256) 흐름을 직접 들고 있다. 의존성이 하나 줄었고, 주고받는 값이 전부 코드에 보인다.

한 것과 미룬 것

  • 세션 쿠키와 만료, 남은 기간이 짧아지면 늘리는 연장
  • Google 로그인(PKCE)과, 이메일이 같은 기존 계정 자동 연결
  • 1시간짜리 1회용 재설정 토큰, 재설정하면 그 사용자의 세션 전부 삭제
  • 이메일 소유 확인
  • 2FA
  • 결제와 수강 권한 부여 화면

새 글이 올라오면 메일로

영상을 글로 정리해 올릴 때마다 알려드립니다.

강의·스킬 소식에만 씁니다. 수신 거부는 메일 맨 아래에서 한 번에 됩니다.