토큰으로 로그인 유지하기

앱과 웹이 같은 계정을 쓰게 하는 방식이에요. 로그인한 증거를 서버가 아니라 손님 쪽에 도장 찍어 들려 보내요. 그래서 편하고, 그래서 토큰이 새면 계정이 통째로 넘어가요.

쉽게 말하면

지점이 여러 개인 가게를 생각해 보세요. 본점 계산대에서 회원 확인을 마치면 도장 찍힌 입장권을 한 장 줘요. 입장권에는 손님 번호와 "오늘 저녁 6시까지"라는 유효 시간이 적혀 있고, 가게만 가진 도장이 찍혀 있어요. 이제 손님은 2호점에 가도, 배달 앱 창구에 가도 입장권만 내밀면 돼요. 직원은 도장이 진짜인지만 보면 되고, 본점에 전화해서 명단을 확인할 필요가 없어요. 토큰(JWT) 이 바로 이 입장권이에요.

핵심은 증거가 손님 손에 있다는 점이에요. 세션 방식은 카운터 명단에 "이 번호표 손님은 로그인 됨"이라고 적어 두고 번호표만 손님에게 줘요. 토큰 방식은 명단 없이, 입장권 자체가 로그인의 증거예요.

번호표 방식(세션)
손님은 번호표만 들고 있고, 누구인지는 카운터 명단을 봐야 앎

지점이 늘면 모든 지점이 같은 명단을 봐야 해요. 명단 하나를 여러 곳에서 나눠 보는 장치가 따로 필요해요. 대신 명단에서 줄 하나만 지우면 그 손님을 바로 내보낼 수 있어요.

도장 입장권 방식(토큰)
입장권에 손님 번호·유효 시간이 적혀 있고 가게 도장으로 위조를 막음

어느 지점이든 도장만 확인하면 돼서 앱·웹·다른 서버가 같은 계정을 쉽게 알아봐요. 대신 한번 나간 입장권은 시간이 다할 때까지 유효해요. 이게 편리함과 위험의 출처예요.

앱과 웹이 같은 계정을 쓰게 되는 원리

손님이 로그인 버튼을 누른 뒤 안에서는 다섯 단계가 지나가요. 이 순서를 알면 "앱에서는 되는데 웹에서는 왜 풀리나" 같은 문의가 어디서 갈리는지 보여요.

  1. 1손님이 아이디와 비밀번호를 보내요. 여기까지는 로그인과 인증과 같아요.
  2. 2서버가 비밀번호를 확인하고, 손님 번호·유효 시간을 적은 입장권을 만들어요.
  3. 3서버만 가진 비밀 도장(서명 키) 으로 입장권에 도장을 찍어 손님에게 돌려줘요.
  4. 4손님의 앱이나 브라우저는 이 입장권을 보관해 두고, 이후 모든 요청에 함께 붙여 보내요. 요청 머리에 Bearer 라는 말과 함께 실려 가요.
  5. 5서버는 요청이 올 때마다 도장이 진짜인지, 시간이 안 지났는지만 확인해요. 명단을 뒤지지 않아요.

앱과 웹이 같은 계정을 쓰는 비밀은 3번에 있어요. 같은 비밀 도장을 쓰는 서버라면 어디서 만든 입장권이든 알아봐요. 웹에서 받은 입장권을 앱이 내밀어도 통하고, 서버를 두 대 세 대로 늘려도 명단을 나눠 볼 장치가 필요 없어요.

비밀 도장은 딱 하나가 전부예요

이 방식의 안전은 통째로 서명 키 하나에 걸려 있어요. 이 키가 코드에 그대로 적혀 있거나 깃허브에 올라가면, 누구든 진짜와 똑같은 입장권을 마음대로 찍어 낼 수 있어요. 키는 반드시 환경변수 금고에 두고, 새 나갔다고 의심되면 즉시 바꿔요. 키를 바꾸면 기존 입장권이 전부 무효가 되니 손님은 다시 로그인하게 돼요.

입장권 한 장에 적힌 것

토큰을 열어 보면 점으로 나뉜 세 덩어리예요. 겉보기엔 알아볼 수 없는 긴 글자열이지만, 실제로는 누구나 풀어 읽을 수 있는 메모 두 장도장 한 개예요.

부분적힌 것가게로 치면
머리(header)어떤 도장 방식을 썼는지입장권 종류 표시
본문(payload)손님 번호, 발급 시각, 만료 시각, 필요하면 역할(관리자·일반)손님 번호와 "저녁 6시까지"라는 글씨
서명(signature)머리와 본문을 비밀 키로 눌러 만든 도장. 본문이 한 글자라도 바뀌면 도장이 안 맞아요가게만 가진 도장 자국

본문은 잠겨 있지 않아요

가장 자주 하는 오해예요. 토큰의 본문은 암호화가 아니라 그냥 옮겨 적은 것이라 누구든 풀어서 읽을 수 있어요. 도장은 위조를 막을 뿐 내용을 가리지 않아요. 그래서 토큰 안에 전화번호·주소·비밀번호 같은 손님 정보를 넣으면 안 돼요. 손님 번호와 만료 시각, 역할 정도만 담는 게 원칙이에요.

짧은 입장권과 긴 입장권, 두 장을 쓰는 이유

입장권을 하루 종일 유효하게 만들면 편하지만, 새 나갔을 때 하루 종일 도둑이 손님 행세를 해요. 그래서 실제 서비스는 입장권을 두 장 줘요. 이름이 어렵게 들리지만 하는 일은 단순해요.

구분액세스 토큰리프레시 토큰
하는 일매 요청마다 내미는 입장권액세스 토큰이 만료되면 새 것을 받아 오는 교환권
유효 시간짧게. 몇 분에서 한 시간 안팎으로 정하는 경우가 많아요길게. 며칠에서 몇 주까지 두는 경우가 많아요
어디에 쓰나주문 조회, 글 쓰기 같은 평소 요청 전부새 액세스 토큰 발급 요청, 오직 그 한 가지
새면짧은 시간 동안만 피해. 만료되면 자동으로 끝나요긴 시간 동안 새 입장권을 계속 찍어 낼 수 있어요. 훨씬 위험해요
서버가 기억하나보통 기억하지 않아요. 도장만 확인해요발급 기록을 남겨 두고, 로그아웃·비밀번호 변경 때 지워요

손님이 "앱을 껐다 켜도 로그인이 유지된다"고 느끼는 건 리프레시 토큰 덕분이에요. 짧은 입장권이 만료되면 앱이 조용히 교환권을 내밀어 새 입장권을 받아요. 손님 눈에는 아무 일도 없어요. 이 교환이 실패하면 그때 로그인 화면이 다시 떠요.

교환권은 한 번 쓰면 새로 주는 게 안전해요

리프레시 토큰을 쓸 때마다 새 것으로 바꿔 주고 옛 것을 무효로 만드는 방식이 있어요. 개발자들은 이걸 회전(rotation) 이라고 불러요. 이렇게 하면 도둑이 훔친 교환권을 쓰는 순간, 진짜 손님의 교환권과 충돌이 나서 서버가 이상을 눈치챌 수 있어요.

토큰이 새면 무슨 일이 생기나

입장권을 주운 사람은 비밀번호를 몰라도 손님이 돼요. 서버는 도장만 보니까 누가 내밀었는지 구분할 방법이 없어요. 사고는 대개 아래 순서로 번져요.

  1. 1손님 브라우저에 끼어든 악성 코드나 확장 프로그램이 보관된 토큰을 읽어 가요. 또는 토큰이 주소창·로그·화면 캡처에 찍혀 밖으로 나가요.
  2. 2훔친 사람이 자기 컴퓨터에서 그 토큰을 붙여 요청을 보내요. 서버는 도장이 맞으니 그대로 통과시켜요.
  3. 3주문 내역, 적립금, 저장된 배송지가 그대로 보여요. 결제 수단이 연결돼 있으면 주문까지 넣을 수 있어요.
  4. 4리프레시 토큰까지 함께 새 나갔다면 액세스 토큰이 만료돼도 새 것을 계속 받아요. 손님이 비밀번호를 바꿔도, 서버가 리프레시 토큰을 지우지 않으면 그대로 이어져요.
위험한 보관
웹에서 토큰을 브라우저의 일반 저장 공간(localStorage)에 넣어 둠

페이지에 끼어든 어떤 스크립트든 그 공간을 읽을 수 있어요. 외부 위젯 하나가 뚫리면 토큰이 통째로 나가요.

안전한 보관
웹은 스크립트가 못 읽는 쿠키(httpOnly)에, 앱은 운영체제가 잠가 주는 보관함에 둠

웹에서는 스크립트가 손댈 수 없는 쿠키에 담고 [[https|https]] 에서만 보내게 해요. 앱은 아이폰·안드로이드가 제공하는 잠긴 보관함을 써요. 어디에 두는지가 새는지 안 새는지를 갈라요.

장면 1 · 외주 개발자가 말했다

토큰 유효 시간을 30일로 잡았어요. 손님이 자꾸 로그인하면 불편하니까요.

불편함을 줄이려는 뜻은 맞지만 방법이 틀렸어요. 로그인을 오래 유지하는 일은 긴 교환권이 맡고, 매 요청에 실리는 입장권은 짧게 가야 해요. 되물을 말은 하나예요. "액세스 토큰과 리프레시 토큰이 따로 있나요, 각각 몇 분과 며칠인가요?" 둘이 구분돼 있지 않다면 그 30일은 도둑에게도 30일이에요.

장면 2 · 손님이 문의했다

비밀번호를 바꿨는데 예전 폰에서 아직도 제 계정이 열려 있어요.

토큰 방식의 약점이 그대로 드러난 문의예요. 서버가 명단을 안 보니 비밀번호를 바꿔도 이미 나간 입장권은 살아 있어요. 고치는 법은 정해져 있어요. 비밀번호 변경·로그아웃 때 그 손님의 리프레시 토큰을 서버에서 전부 지우기, 그리고 액세스 토큰은 짧게 두기. 이 두 가지가 없으면 "모든 기기에서 로그아웃" 버튼을 만들 수 없어요.

세션과 토큰, 우리 가게는 뭘 써야 하나

정답은 규모와 모양에 달려 있어요. 웹사이트 하나만 있고 서버가 한 대라면 세션 방식이 더 단순하고 더 안전해요. 토큰이 이기는 자리는 따로 있어요.

내 가게 모양권하는 쪽이유
웹사이트 하나, 서버 한 대세션명단 한 장이면 끝이에요. 손님을 즉시 내보낼 수 있고 챙길 게 적어요
웹과 앱이 같은 계정을 씀토큰앱은 브라우저 쿠키를 그대로 쓰기 어려워요. 입장권을 들려 보내는 쪽이 자연스러워요
서버가 여러 대이거나 다른 서비스가 내 계정을 확인해야 함토큰명단을 나눠 볼 필요 없이 도장만 공유하면 돼요
돈이 오가고 즉시 차단이 중요함세션, 또는 토큰 + 서버 기록토큰만 쓰면 한번 나간 입장권을 즉시 못 막아요. 차단 목록을 서버에 따로 두어야 해요

많은 서비스가 실제로는 섞어 써요. 웹 화면은 토큰을 httpOnly 쿠키에 담아 세션처럼 다루고, 앱은 같은 토큰을 잠긴 보관함에 두고 요청에 붙여 보내요. 서버 쪽 확인 방법은 하나로 통일되고, 손님 쪽 보관만 기기에 맞게 달라져요.

AI나 개발자에게 그대로 말할 문장

증상을 전문어로 바꾸려 애쓰지 마세요. 보이는 그대로 말하고 원하는 결과를 붙이면 가장 잘 통해요. 오른쪽 칸은 스튜디오 대화창이나 외주에게 그대로 붙여도 되는 문장이에요.

내가 보는 상황그대로 말할 문장
앱에서 로그인하면 웹에서는 안 돼요앱과 웹이 같은 계정으로 로그인 상태를 공유하게 해 주세요. 서버가 같은 서명 키로 토큰을 확인하는지, 웹은 쿠키로 앱은 요청 머리로 보내는지 정리해 주세요
로그인이 자꾸 풀려요액세스 토큰 만료 시간과 리프레시 토큰 만료 시간이 각각 얼마인지 알려 주세요. 액세스 토큰이 만료되면 리프레시 토큰으로 자동 갱신되는지 확인해 주세요
비밀번호를 바꿔도 다른 폰에서 로그인이 안 풀려요비밀번호 변경과 로그아웃 시 그 계정의 리프레시 토큰을 서버에서 모두 삭제하게 해 주세요. 모든 기기에서 로그아웃 버튼도 추가해 주세요
토큰을 어디에 저장하는지 모르겠어요웹에서 토큰을 localStorage 에 넣고 있는지 확인해 주세요. 그렇다면 httpOnly 쿠키로 옮기고 https 에서만 전송되게 바꿔 주세요
서명 키가 코드에 적혀 있는 것 같아요토큰 서명 키가 코드나 저장소에 직접 적혀 있는지 검사해 주세요. 있다면 환경변수로 옮기고 새 키로 교체해 주세요
관리자만 쓰는 기능이 있어요토큰에 역할 정보를 넣고, 관리자 기능은 서버에서 역할을 확인한 뒤에만 실행되게 해 주세요. 화면에서만 숨기는 방식은 안 돼요

역할 확인은 서버에서

토큰 본문에 "관리자"라고 적혀 있다고 해서 화면에서 버튼만 보여주고 끝내면 안 돼요. 본문은 누구나 읽고 흉내 낼 수 있어요. 서버가 도장을 확인한 뒤 그 안의 역할을 읽고 권한을 따져야 진짜 잠금이에요.

자주 묻는 것

Q. AI 요금에 나오는 토큰과 같은 말인가요?
글자만 같고 전혀 다른 말이에요. AI 이야기의 토큰은 글을 세는 단위이고, 로그인 이야기의 토큰은 입장권이에요. 문맥에 로그인·인증·만료가 있으면 이 문서 쪽이에요.
Q. 카카오·구글 로그인을 붙이면 이것도 같이 알아야 하나요?
소셜 로그인은 손님이 누구인지 카카오나 구글이 대신 확인해 주는 절차예요. 확인이 끝난 뒤 우리 서버가 우리 입장권을 발급하는 부분은 이 문서 그대로예요. 소셜 로그인 절차는 소셜 로그인 연결 방식에서 따로 다뤄요.
Q. 토큰을 만료시키지 않고 무한히 쓰면 안 되나요?
기술적으로는 되지만 하면 안 돼요. 만료가 없으면 한 번 새 나간 입장권을 영원히 막을 수 없어요. 서버가 도장만 보는 구조라 그래요. 유효 시간은 이 방식의 유일한 자동 안전장치예요.
Q. 바이브캠퍼스로 만들면 이걸 제가 직접 정해야 하나요?
처음 만들 때는 로그인이 필요하다고 말하면 스튜디오가 알아서 붙여 줘요. 이 문서가 필요한 순간은 그 다음이에요. 앱을 추가로 만들 때, 로그인이 풀린다는 문의가 올 때, 외주 견적에 토큰이라는 말이 보일 때 여기로 돌아오면 돼요.
Q. 토큰이 새 나간 것 같으면 지금 당장 뭘 하나요?
순서가 있어요. 먼저 서명 키를 새것으로 교체해요. 그러면 지금까지 나간 입장권이 전부 무효가 되고 모든 손님이 다시 로그인하게 돼요. 그다음 서버에 남은 리프레시 토큰 기록을 지우고, 활동 기록에서 이상한 접속이 있었는지 확인해요. 손님 정보가 실제로 읽혔다면 개인정보 문서의 신고 절차를 따라요.
Q. API 키와는 뭐가 다른가요?
API 키우리 가게가 다른 회사 창고에 들어갈 때 쓰는 출입증이고, 이 토큰은 손님이 우리 가게에 들어올 때 쓰는 입장권이에요. 방향이 반대예요. 둘 다 새면 돈이나 계정이 넘어간다는 점은 같아요.

확인해 보세요

외주 개발자가 "편의를 위해 토큰을 30일짜리 한 장으로 발급했다"고 해요. 어떻게 하는 게 맞을까요?

하나 더

토큰 본문에 손님 전화번호와 배송지를 넣어 두면 화면에 빨리 띄울 수 있다는 제안을 받았어요.

직접 해보기

내 서비스의 로그인 유지 방식을 물어보세요

스튜디오 대화창에 이렇게 그대로 붙여 넣어 보세요. "지금 로그인 상태를 세션으로 유지하나요, 토큰으로 유지하나요? 토큰이라면 액세스와 리프레시 만료 시간, 토큰을 어디에 저장하는지, 서명 키가 환경변수에 있는지 표로 정리해 주세요." 이 네 가지 답이 한 장에 나오면 이 문서의 내용을 내 가게에 적용한 거예요.

스튜디오 열기

더 깊이 (안 읽어도 괜찮아요)

비유가 어디까지 맞고 어디부터 다른가 · 도장 입장권 비유는 "어느 지점이든 도장만 확인한다"까지 정확해요. 다른 점은 종이 입장권은 한 장뿐이라 훔치면 원래 손님이 잃어버리지만, 토큰은 복사해도 원본이 그대로 남는다는 거예요. 손님은 아무 이상을 못 느끼는 채로 도둑이 같은 입장권을 나란히 쓰게 돼요. 그래서 리프레시 토큰 회전처럼 "같은 교환권이 두 번 쓰이면 이상"으로 잡아내는 장치가 따로 있어요.

서버가 아무것도 기억하지 않는다는 말의 진짜 뜻 · 토큰 방식의 자랑은 서버가 명단을 안 들고 있어도 된다는 점이에요. 그런데 즉시 차단·모든 기기 로그아웃·교환권 회전은 전부 서버가 무언가를 기억해야 가능해요. 그래서 실무에서는 액세스 토큰만 기억 없이 확인하고, 리프레시 토큰은 발급 기록을 남겨요. "완전히 기억 없는 구조"는 교과서에 있고, 손님 계정을 지키는 서비스는 대부분 절충해요.

도장 방식 자체가 뚫렸던 사고 · 토큰의 머리 부분에는 어떤 도장 방식을 썼는지 적혀 있어요. 오래전 일부 확인 코드가 "도장 없음"이라고 적힌 토큰을 그대로 믿어 버린 사고가 있었어요. 지금의 정상적인 라이브러리는 이걸 막지만, 교훈은 남아요. 확인 코드는 허용할 도장 방식을 서버가 정해 두고 토큰이 뭐라고 적었든 그 방식으로만 검사해야 해요. 로그인 관련 부품은 오래 방치하지 말고 업데이트해 두는 게 이래서 중요해요.

이것만 기억하세요

  • ·토큰은 서버가 도장 찍어 손님에게 들려 보내는 입장권이에요. 명단 없이 도장만 확인해요
  • ·같은 서명 키를 쓰는 서버는 어디서든 알아봐요. 그래서 앱과 웹이 같은 계정을 써요
  • ·본문은 누구나 읽어요. 손님 번호와 만료 시각만 담고, 서명 키는 환경변수에만 둬요
  • ·입장권은 짧게, 교환권은 길게. 두 장으로 나눠야 편리함과 안전이 같이 가요
  • ·새 나갔으면 서명 키 교체, 리프레시 토큰 삭제, 활동 기록 확인 순서예요
VibeCampus새 빌드