사전 토큰
용어함정

토큰

gabury1고친 사람 github-actions[bot]

토큰은 손에 쥘 수 없는 것을 한 장씩 셀 수 있는 표로 바꿔 줍니다. 그런데 무엇을 표로 바꾸느냐에 따라 전혀 다른 물건을 가리킵니다. 인증에서는 비밀번호 대신 내미는 문자열입니다. 분산 저장소에서는 한 서버가 맡을 데이터 구간을 정하는 숫자입니다.

쉽고 빠른 이해

무슨 일을 하는 물건인가 — 이름은 하나인데 분야마다 다른 물건을 가리킵니다. 로그인한 뒤 요청마다 들고 다니는 문자열도 토큰입니다. 여러 서버에 데이터를 나눠 담을 때 각 서버가 맡을 구간을 정하는 숫자도 토큰입니다. 소스 코드를 쪼갠 낱말 한 개도 토큰입니다.

왜 이렇게 하나 — 인증에서는 비밀번호를 요청마다 보내면 흘릴 위험이 커집니다. 분산 저장소에서는 서버가 늘고 줄 때마다 데이터를 전부 옮기면 서비스가 멈춥니다. 어느 쪽이든 원래 것을 그대로 쓰지 않고 작은 표 하나로 갈음합니다.

어떻게 도나

  1. 인증 토큰은 한 번 발급받고, 그 뒤로 요청마다 함께 보냅니다
  2. 분산 저장소의 토큰은 숫자 하나로 담당 구간의 경계를 긋습니다
  3. 어휘 분석의 토큰은 문자열을 쪼갠 조각이라 발급도 폐기도 없습니다

대가 — 인증 토큰은 남이 훔치면 그 사람이 나처럼 행세합니다. 분산 저장소의 토큰은 잘못 놓으면 한 서버에만 데이터가 몰립니다. 대화에서 두 뜻을 섞어 부르면 서로 다른 이야기를 하게 됩니다. 옆에 붙은 말이 로그인 이야기인지 데이터를 나눠 담는 이야기인지를 보면 어느 뜻인지 갈립니다.

상세

이 절은 「토큰」이 가리키는 물건들을 나란히 놓고 봅니다. 먼저 뜻들을 표 하나로 가릅니다. 그다음 백엔드 개발자가 가장 자주 만나는 두 뜻인 인증의 토큰과 분산 저장소의 토큰을 차례로 따라갑니다.

그 뒤에 소스 코드를 쪼갠 토큰을 짚고, 나머지 뜻들을 짧게 모읍니다. 끝에서는 대화에서 어느 뜻인지 알아채는 단서를 정리합니다.

토큰이 가리키는 물건들

뜻마다 가리키는 물건과 쓰는 분야가 다릅니다. 굳이 공통점을 찾자면 한 개씩 셀 수 있는 조각이라는 느낌뿐이고, 그 너머로는 서로 이어지지 않습니다.

맥락 토큰 한 개가 가리키는 것 예
인증과 인가 권한을 담아 비밀번호 대신 내미는 문자열 액세스 토큰 · 위조 방지 토큰
분산 저장소 한 서버가 맡을 데이터 구간을 정하는 숫자 담당 구간의 경계가 되는 값
어휘 분석 소스 코드를 쪼갠 낱말 한 개 변수 이름 · 숫자 · 연산자
흐름 조절 일을 한 번 할 수 있는 허가 한 장 토큰 버킷의 토큰
옛 근거리 통신망 보낼 차례를 넘겨주는 짧은 신호 토큰 링의 토큰
언어 모델 글을 쪼갠 조각 하나 길이와 요금을 세는 단위
결제 카드 번호를 대신하는 값 토큰화한 카드 번호

앞의 둘은 서비스를 짜다 보면 거의 반드시 마주칩니다. 아래 두 소절이 그 둘입니다.

인증의 토큰

HTTP(HyperText Transfer Protocol, 하이퍼텍스트 전송 프로토콜)로 도는 서버는 앞 요청을 기억하지 않습니다. 이렇게 앞뒤 요청이 서로 무관하게 처리되는 성질을 무상태라고 합니다. 그래서 로그인한 사람이라는 것을 요청마다 다시 알려야 합니다.

비밀번호를 요청마다 보내는 방법도 있기는 합니다. 다만 그러면 비밀번호가 오갈 때마다 흘릴 틈이 늘고, 비밀번호를 바꾸는 순간 모든 곳이 한꺼번에 막힙니다.

토큰은 그 대신 내미는 문자열입니다. 한 번만 비밀번호로 로그인하고, 그때 받은 문자열을 그 뒤 요청마다 함께 보냅니다. 극장 입구에서 표를 보이는 것과 비슷합니다. 표는 내가 누구인지까지는 말하지 않고, 어느 상영관에 언제까지 들어갈 수 있는지만 말합니다.

토큰이 권한을 담는 방법은 두 갈래입니다. 하나는 무의미해 보이는 문자열을 주고, 서버가 그 문자열로 저장소를 뒤져 누구의 어떤 권한인지 찾는 방법입니다. 다른 하나는 권한 내용을 토큰 안에 적어 넣고 서명을 붙이는 방법입니다.

서명은 그 내용을 발급한 쪽이 썼다는 것을 확인하게 해 주는 값입니다. 서명이 붙어 있으면 받는 쪽은 저장소를 안 뒤지고도 내용을 믿을 수 있습니다. 대신 한 번 나간 토큰의 내용은 만료될 때까지 그대로 남습니다.

토큰을 주고받는 한 왕복

로그인부터 자원을 받아 오기까지를 따라갑니다. 토큰을 내주는 쪽을 인가 서버, 토큰을 보고 자원을 내주는 쪽을 자원 서버라고 부릅니다.

sequenceDiagram
    participant 앱 as 클라이언트
    participant 인가 as 인가 서버
    participant 자원 as 자원 서버
    앱->>인가: 아이디와 비밀번호를 한 번 보낸다
    인가-->>앱: 토큰을 내준다
    앱->>자원: 요청마다 토큰을 함께 보낸다
    Note over 자원: 서명이 맞고 기한이 안 지났으면 받아 준다
    자원-->>앱: 요청한 자원을 돌려준다

비밀번호가 오가는 것은 맨 위 한 번뿐입니다. 그 아래 요청들은 토큰만 싣습니다. 자원 서버는 토큰만 보고 판단하므로 비밀번호를 알 필요가 없습니다.

토큰을 실어 보내는 곳은 대개 요청 헤더입니다. 토큰을 가진 사람이면 누구든 쓸 수 있다는 뜻으로 베어러 토큰이라고 부르는 방식이 흔합니다.

가진 사람이면 누구든 쓸 수 있다는 것은 훔친 사람도 쓸 수 있다는 뜻입니다. 그래서 토큰에는 짧은 기한을 둡니다. 기한이 지나면 새 토큰을 받아야 하고, 그 새 토큰을 받아 오는 데 쓰는 것이 리프레시 토큰입니다.

분산 저장소의 토큰

데이터가 한 서버에 안 들어가면 여러 서버에 나눠 담습니다. 이때 「어느 키가 어느 서버로 가는가」를 정하는 규칙이 필요합니다.

가장 단순한 규칙은 서버 수로 나눈 나머지를 쓰는 것입니다. 이 방법은 서버가 하나 늘거나 빠지는 순간 나머지 값이 전부 달라져서 거의 모든 키가 옮겨 다닙니다.

일관성 해싱은 그 옮김을 줄이려고 나온 방법입니다. 해시 함수가 낼 수 있는 값의 범위를 원으로 놓고, 키도 서버도 그 원 위의 한 점에 앉힙니다. 이 원이 해시 링입니다.

이때 서버가 원 위에서 차지하는 점을 토큰이라고 부릅니다. 토큰은 값 하나짜리 숫자이고, 담당 구간의 경계를 긋는 것이 그 숫자가 하는 일입니다.

flowchart TD
    subgraph 링["해시 링 · 0 에서 한 바퀴 돌아 다시 0"]
        A["토큰 10 · 서버 A"]
        B["토큰 40 · 서버 B"]
        C["토큰 70 · 서버 C"]
        A --> B --> C --> A
    end
    K["키를 해시하니 25 가 나왔다"] --> B

키가 어디로 갈지는 원을 한 방향으로 돌면서 처음 만나는 토큰이 정합니다. 그림에서 25 는 40 을 먼저 만나므로 서버 B 로 갑니다. 그러니 서버 B 는 10 다음부터 40 까지의 키를 맡습니다.

서버 B 가 빠지면 B 가 맡던 구간만 다음 토큰의 주인인 서버 C 로 넘어갑니다. 서버 A 가 맡던 구간은 손대지 않습니다. 이것이 나머지 연산과 갈리는 대목입니다.

토큰이 서버마다 하나뿐이면 구간 길이가 들쭉날쭉해집니다. 한 서버가 남보다 훨씬 긴 구간을 맡으면 그 서버만 바빠집니다. 그래서 서버 하나에 토큰을 여러 개 주어 구간을 잘게 흩뜨립니다. 이렇게 흩뜨린 각각을 가상 노드라고 부릅니다.

어휘 분석의 토큰

컴파일러는 소스 코드를 글자 하나하나로 읽습니다. 글자만으로는 문법을 따질 수 없으니 먼저 낱말 단위로 쪼갭니다. 이 쪼개기가 어휘 분석이고, 쪼개진 낱말 한 개가 토큰입니다.

쪼개는 쪽을 렉서, 그 결과를 받아 문법 구조를 세우는 쪽을 파서라고 합니다. 파서는 글자가 아니라 토큰 열을 받습니다.

아래 한 줄이 토큰으로 어떻게 갈리는지 봅니다.

Java
int sum = count + 1;

렉서를 지나면 이 줄은 토큰 일곱 개가 됩니다. 오른쪽 주석은 그 토큰의 갈래입니다.

int      // 예약어
sum      // 이름
=        // 연산자
count    // 이름
+        // 연산자
1        // 숫자
;        // 구분자

공백은 토큰이 되지 않고 사라집니다. 토큰마다 갈래가 붙으므로 파서는 「이름 다음에 연산자」 같은 규칙으로 문법을 따질 수 있습니다.

여기서 토큰은 누가 내주는 것도 아니고 기한도 없습니다. 인증의 토큰과 이름만 같을 뿐 하는 일이 겹치지 않습니다.

그 밖의 토큰

토큰 버킷 — 요청을 초당 몇 건까지만 받으려 할 때 쓰는 방식입니다. 통에 허가를 일정한 속도로 채워 두고, 요청이 올 때마다 하나를 꺼내 씁니다. 통이 비면 그 요청은 기다리거나 거절됩니다. 여기서 토큰은 일을 한 번 할 수 있는 허가 한 장입니다.

토큰 링 — 옛 근거리 통신망에서 쓰던 방식입니다. 짧은 신호 하나를 참여자들이 돌려 가며 넘기고, 그 신호를 쥔 참여자만 데이터를 보냅니다. 발언권을 표 하나로 만들어 돌린 셈입니다.

결제 토큰화 — 카드 번호를 그대로 저장하지 않고 아무 뜻 없는 값으로 바꿔 두는 방법입니다. 원래 번호는 따로 지킨 곳에 두고, 평소에는 바꿔 둔 값만 오갑니다. 이 값이 새어도 카드 번호 자체는 안 드러납니다.

언어 모델의 토큰 — 글을 모델이 다루는 조각으로 쪼갠 단위입니다. 글자 하나보다 크고 낱말 하나보다 작은 경우가 많습니다. 입력 길이와 요금을 이 단위로 셉니다.

어느 뜻인지 가르는 단서

문서나 대화에서 「토큰」이 나오면 함께 붙은 낱말을 봅니다. 대개 그것만으로 어느 뜻인지 갈립니다.

함께 나오는 말 뜻
로그인 · 발급 · 만료 · 서명 · 헤더에 싣는다 인증과 인가
링 · 서버를 늘린다 · 키가 어느 서버로 가나 · 데이터가 한쪽에 몰린다 분산 저장소
렉서 · 파서 · 예약어 · 문법 · 소스 코드를 쪼갠다 어휘 분석
초당 몇 건 · 통에 채운다 · 요청을 거절한다 흐름 조절
글자 수 대신 센다 · 입력 길이 · 요금 언어 모델
카드 번호 · 원래 값을 따로 둔다 결제

「토큰화」는 두 분야에서 쓰이는데 뜻이 다릅니다. 결제에서는 민감한 값을 다른 값으로 바꾸는 일이고, 글을 다루는 쪽에서는 글을 토큰으로 쪼개는 일입니다.

관련 항목

인증 토큰의 하위 종류

액세스 토큰 · 리프레시 토큰 · ID 토큰 · 베어러 토큰 · CSRF 토큰 · 세션 토큰 · API 키 · 불투명 토큰

인증 토큰을 정의하는 표준·문서

JWT · OAuth · OpenID Connect · SAML · JWS · JWK

인증 토큰이 오갈 때 관여하는 역할

클라이언트 · 인가 서버 · 자원 서버 · 자원 소유자 · 인가 · 인증 · 스코프

인증 토큰이 안전하려면 기대는 기술

서명 · 해시 함수 · 공개 키 암호 · 대칭 키 · TLS · 논스 · 클레임

인증 토큰을 못 쓰게 만드는 수단

만료 · TTL · 토큰 폐기 · 폐기 목록 · 토큰 회전 · 토큰 탈취 · 재생 공격

해시 링 위의 토큰과 함께 도는 구성 요소

일관성 해싱 · 해시 링 · 가상 노드 · 물리 노드 · 파티션 · 샤딩 · 코디네이터 · 선호 목록 · 리밸런싱

소스 코드를 토큰으로 쪼개는 처리 단계

어휘 분석 · 렉서 · 파서 · 구문 분석 · 추상 구문 트리 · 컴파일러 · 예약어 · 식별자 · 정규 표현식

허가 한 장으로 흐름을 조절하는 방식

토큰 버킷 · 누출 버킷 · 처리율 제한 · 백프레셔 · 세마포어 · 스로틀링

이름이 겹치는 다른 토큰

토큰 링 · 토큰화 · 언어 모델 · 컨텍스트 창 · 서브워드

다른 이름: token