← 기술 지식

기술 지식 / 보안 / 인증·계정

입력이 불편한 기기의 승인과 토큰 발급

기기 코드와 사용자 코드를 구분하고 별도 승인·poll pacing·원자 발급·응답 유실·기기 자격 보관을 연결합니다.

보안 · 원리·구현·운영
기술 지식 트리

이 노트는 입력이 불편한 기기와 브라우저 사용자의 승인을 안전하게 결합하는 device authorization 흐름을 상태 머신으로 설명합니다. 기기 코드·사용자 코드·승인 상태·토큰 결과를 서로 다른 비밀과 상태로 취급하고, polling·응답 유실·자격 보관의 경계를 실제 시간 순서로 추적합니다.

콘솔 로그인 시작과 별도 화면 사용자 승인

TV나 CLI에서 긴 비밀번호를 입력하기 어렵다면 기기가 짧은 코드와 승인 주소를 표시하고, 사용자가 이미 익숙한 브라우저에서 로그인해 승인할 수 있습니다. 이것이 device authorization 흐름의 출발점입니다. 기기가 이미 사용자로 인증됐다는 가정은 필요하지 않습니다. 대신 기기를 위한 요청과 사용자의 승인을 안전하게 결합해야 합니다.

기기는 authorization 서버에서 device_code, user_code, 승인 URI, 만료와 polling 간격을 받습니다. 화면에 보여 주는 user_code는 사용자가 승인할 요청을 찾는 값이고, device_code는 기기가 token endpoint에서 진행 상태를 확인하는 비밀입니다. user_code가 보인다는 사실만으로 토큰을 발급하거나 device_code를 사용자 안내 로그에 출력하면 안 됩니다.

승인 화면의 앱·기기 권한 범위

단계 기기 사용자 브라우저 서버 상태
시작 비밀 device_code 보관 아직 없음 pending
안내 승인 URI·user_code 표시 정식 주소에서 로그인 pending
확인 지정 간격으로 polling 앱·요청 범위를 보고 승인 approved 또는 denied
발급 토큰 결과 수신 승인 결과 표시 issued
기한 초과 새 흐름 필요 오래된 코드 거절 expired

악의적인 사람이 자기 기기의 코드를 피해자에게 입력하라고 유도할 수 있습니다. 승인 페이지는 “코드가 맞다”만 보여 주지 말고 어떤 앱·기기 요청에 어떤 계정 권한을 주는지 확인하게 합니다. 기기 이름은 요청자가 적은 문자열일 수 있으므로 강한 기기 소유 증거로 쓰지 않습니다. 예상하지 못한 코드 입력 요청을 승인하지 않도록 안내합니다. 사용자는 화면에 표시된 앱·기기·권한 범위를 확인한 뒤 승인해야 하며, user_code만 맞는다는 사실은 기기 소유권 증명이 아닙니다. 구현자는 승인 페이지에 요청의 출처와 범위를 표시하되 device_code나 장기 토큰을 화면·URL·진단 로그에 노출하지 않습니다.

승인과 발급은 별도의 상태 전이입니다pending: device_code는 비밀. approved: 사용자·범위 확정. issued: 하나의 발급 결과. 기기가 결과 수신: 응답 유실은 별도 복구인증 후 명시적 승인원자적 발급 전환네트워크 전달pendingdevice_code는 비밀approved사용자·범위 확정issued하나의 발급 결과기기가 결과 수신응답 유실은 별도 복구
승인과 발급은 별도의 상태 전이입니다 화살표는 서버의 상태 전이입니다. 승인됐다는 사실은 토큰 응답이 기기에 도착했다는 뜻이 아니며, polling마다 새 토큰을 만들면 안 됩니다.
그림을 글로 읽기
  • pending: device_code는 비밀
  • approved: 사용자·범위 확정
  • issued: 하나의 발급 결과
  • 기기가 결과 수신: 응답 유실은 별도 복구
  1. pending → approved: 인증 후 명시적 승인
  2. approved → issued: 원자적 발급 전환
  3. issued → 기기가 결과 수신: 네트워크 전달

Polling 간격과 재시도·만료 한도

기기는 서버가 정한 interval이 지나기 전에는 다시 묻지 않고, authorization_pending이면 그만큼 기다립니다. slow_down이 오면 RFC 8628에 따라 이후 polling 간격을 5초 늘리고, 네트워크 오류에는 backoff를 적용하되 전체 만료 기한은 연장하지 않습니다. 시간 추적 예는 pending poll → authorization_pending → interval 대기, slow_down → 이후 간격 +5초, expired/denied → terminal stop입니다. 네트워크 오류 재시도는 이 상태 머신의 시간을 소비하며, backoff가 만료 시각을 뒤로 미루지 않도록 합니다. denied나 expired처럼 종결 상태를 받으면 polling을 멈춥니다.

서버는 짧은 user_code 대입에 계정·요청·출처별 제한을 두고, device_code도 충분히 예측하기 어렵게 만듭니다. 두 기기 요청이 우연히 같은 코드에 매칭되거나 만료된 코드가 새 요청에 잘못 붙지 않도록 유일성·수명 계약이 필요합니다. 승인·거절·만료가 경쟁할 때 한 최종 상태만 확정되어야 합니다.

토큰 발급과 응답 수신 사이의 복구 공백

서버가 approved 상태를 소비하고 refresh token R을 발급한 직후 응답이 유실되면, 기기는 발급 결과를 받지 못할 수 있습니다. 서버에 R의 검증용 해시만 남겼다면 그 해시에서 R 원문을 되살릴 수 없으므로, 다음 polling에 같은 원문을 다시 보내려면 암호화된 짧은 결과 보관 같은 별도 설계가 필요합니다. 요청 ID를 알고 있다는 사실만으로 그 결과를 받을 권한이 생기는 것은 아닙니다.

특정 공급자의 device flow가 토큰 결과 재전달을 보장한다고 가정하지 않습니다. 재전달을 지원하지 않으면 기기가 새 승인 흐름을 시작하게 하는 복구 UX가 필요하고, 직접 서버를 구현한다면 발급 상태·기기 세션·결과 보관을 원자적으로 연결한 뒤 재전달 자격·횟수·TTL을 좁혀야 합니다. 재전달은 정상 응답 유실을 돕지만, 복제된 bearer 토큰(원문을 가진 것만으로 사용하는 자격)을 가진 주체와 정상 기기를 완벽히 구별해 주지는 않습니다.

Access·Refresh 자격의 저장소와 수명

짧은 access token은 가능하면 메모리에만 두고, 장기 로그인에 필요한 refresh 자격은 OS의 자격 저장소 등 접근 통제가 있는 저장소를 사용합니다. CLI가 브라우저와 다르다고 평문 설정 파일·셸 히스토리·환경 출력·crash dump에 노출해도 되는 것은 아닙니다. 저장소가 없으면 세션 한정 로그인이나 사용자가 이해한 제한적 보관 정책을 택합니다.

기기별 세션 계열을 분리하면 TV 하나의 로그아웃이 노트북의 정상 세션을 불필요하게 끊지 않습니다. refresh 회수와 이미 발급한 access token의 잔여 사용 가능 시간은 별도입니다. 발급 후 자동으로 모든 권한을 영구 부여하지 말고 audience·scope·만료와 현재 계정 상태를 검사합니다.

승인·발급 전이별 중단 시험

합성 서버에서 승인 전 poll, 늦은 승인, 승인·거절 동시 실행, 발급 직후 응답 유실을 재현합니다. polling 간격이 늘어나는지와 만료 후 멈추는지 시간을 제어해 검사합니다. 재전달을 지원한다면 여러 서버 인스턴스에서도 하나의 발급 계열만 생겨야 합니다.

기기 로그아웃 뒤 저장소 원문 제거, 토큰이 없는 진단 로그, 재시작 후 만료 자격 거절도 확인합니다. 여기서 제시한 흐름은 RFC 8628에 따른 설계 설명이며 실제 TV나 외부 공급자 로그인 실행 결과는 아닙니다. RFC 8628 준수 여부와 공급자별 재전달·scope·오류 응답은 대상 authorization server의 공식 문서와 합성 서버 시험으로 별도 확인해야 하며, 이 설명을 특정 공급자의 보장으로 확대하지 않습니다.

후속·관련 개념

함께 읽을 문서

전체 기술 지식
선택 연습 · 관련 질문 3개

질문은 이해를 확인하는 보조 자료입니다. 학습 경로와 문서의 범위는 질문 수와 독립적입니다.