Skip to content
isdnetworks
Go back

다루지 않은 토큰 만료 시점

토큰 기반 인증으로 바꾸고 잘 돌다가 한 시간 뒤에 요청이 전부 실패했다. 한 번 받은 토큰을 계속 쓰고 있었고 그 토큰에는 만료 시각이 들어 있었다.

Table of contents

Open Table of contents

만료를 안 다룬 첫 구현

로그인해서 받은 값을 헤더에 넣고 그대로 두는 코드였다. 토큰의 본문을 열어 보니 만료 시각 항목이 있었다.

인증이 성공했다는 것과 그 인증이 계속 유효하다는 것은 다르다. 토큰 방식으로 옮기면서 그 차이를 코드에 반영하지 않은 것이 원인이었다.

401을 받고 다시 하는 구조

권한 없음 응답을 받으면 다시 로그인하고 한 번 더 보내게 고쳤더니 돌아가기는 했다. 다만 만료 때마다 반드시 한 번은 실패하고 다시 하는 구조였다.

동시에 여러 요청이 나가면 전부 그 응답을 받고 전부 각자 다시 로그인한다. 실패를 신호로 삼는 구조는 동시성이 붙으면 그 신호가 배로 증폭된다.

미리 갱신하고 동시 갱신을 막는다

만료 조금 전에 미리 새 토큰을 받게 바꾸니 권한 없음 응답을 아예 안 만나게 됐다. 갱신 구간에 잠금을 걸어 여러 스레드가 동시에 로그인하지 않게 했다.

잠금을 안 걸면 만료 직후에 로그인 요청이 한꺼번에 몰린다. 실패한 뒤에 반응하는 대신 만료되기 전에 움직이는 것이 이 문제의 형태에 맞는 대응이었다.

가정한 만료와 받은 만료

처음에는 만료를 한 시간으로 가정해서 코드에 넣었다. 상대가 만료 시간을 바꾸면 그 순간부터 안 맞는다.

응답에 유효 기간이 들어 있어서 그것을 쓰고 없으면 토큰 본문에서 뽑아 쓰게 했다. 우리 시계와 상대 시계가 다를 수 있으므로 만료 판단에 여유를 뒀다.

갱신 실패의 두 종류

갱신 자체가 실패할 때를 자격 증명 오류와 일시 오류로 나눴다. 앞의 것은 재시도해도 같은 결과이므로 바로 중단하고 알린다.

자격 증명이 틀린 채로 계속 재시도하면 계정이 잠기는데 실제로 그런 일이 있었다. 갱신 토큰을 쓸지는 어디서 도는지에 달렸고 서버 간 통신이라 비밀번호를 안전하게 둘 수 있어서 단순한 쪽으로 갔다.

디버그 로그가 헤더를 통째로 찍고 있어서 토큰이 로그에 남는 것도 그때 고쳤다. 인증 헤더를 가리게 하고 지난 로그에 남은 것도 찾아 지웠다.

정리


Share this post on:

Previous Post
다음 사람에게 남기는 것
Next Post
양쪽을 다 읽는 이관