티스토리 뷰

Server

[Server] CLI를 위한 2가지 인증 방식, Authorization Code Flow와 Device Authorization Flow

망나니개발자 2026. 7. 14. 10:00
반응형

 

 

1. CLI를 위한 2가지 인증 방식, Authorization Code Flow와 Device Authorization Flow


[ Authorization Code Flow와 PKCE이란? ]

PKCE(Proof Key for Code Exchange, "픽시")는 OAuth 2.0의 인증 코드 가로채기 공격을 막기 위한 보안 확장이다. 기존의 OAuth 2.0의 인증 코드 플로우(Authorization Code Flow)에서는 인증 서버가 리디렉션을 통해 인증 코드를 클라이언트에 돌려주면, 클라이언트가 그 코드를 활용해 액세스 토큰으로 교환한다.

이를 위해 사용자는 인증 코드를 돌려받을 본인 서버의 리디렉션 전용 URI를 인증 서버에 사전에 등록을 해두어야 한다. 그러면 인증 서버는 인증 코드를 쿼리 파라미터에 실려 돌려주고, 클라이언트는 이에 접속해 코드를 획득하게 된다.

https://mangkyu.com/callback?code=AUTH_CODE_HERE&state=xyz

 

 

전반적인 Authorization Code Flow를 살펴보면 다음과 같다.

sequenceDiagram
    autonumber
    participant C as Client
    participant B as Browser
    participant A as Auth Server

    C->>B: 브라우저로 인증 요청 시작
    B->>A: 인증 요청 전달
    A-->>B: 로그인 페이지 제공
    B->>A: 사용자 로그인 및 동의
    A-->>B: 리디렉션을 통해 Authorization Code 반환
    B-->>C: Authorization Code 전달
    C->>A: Authorization Code로 Access Token 교환 요청
    A-->>C: Access Token 반환

 

 

하지만 바로 이 과정에서 문제가 생길 수 있다. 바로 악의적인 방법으로 인증 코드가 탈취당하는 것이다. 특히 스마트폰과 같은 기기에서는 다른 애플리케이션이 동일한 리디렉션 URI를 등록하고 인증 코드를 가로챌 수 있다. 그러면 권한이 없는 리소스에 대한 액세스 토큰이 발급되어 접근이 가능해진다. 따라서 이를 방지하려면, 처음 인증을 시작한 앱이 인증 코드를 잘 전달받아 액세스 토큰을 교환하는 주체인지 확인해야 한다. 이를 위해 “일회성 인증” 개념을 기반으로 하는 PKCE가 활용된다.

PKCE를 위해서는 크게 2가지 검증값이 사용된다.

  1. code_verifier: 클라이언트가 매 요청마다 생성하여 활용하는 랜덤한 문자열
  2. code_challenge: verifier를 특정 알고리즘으로 해싱하고 base64url 인코딩한 값

 

 

클라이언트는 인증을 시작하기 전에, 무작위 검증 코드인 code_verifier를 생성하여 로컬에 저장한다. 그리고 인증 서버를 통해 인증을 시작할 때, code_verifier를 code_challenge 값으로 변환하고, 변환한 방식(code_challenge_method, 보통 SHA256)과 code_challenge를 함께 보내면, 인증 서버는 이 값을 저장해둔다.

그리고 나중에 인증 코드를 액세스 토큰으로 교환할 때 원본 code_verifier를 함께 보낸다. 그러면 인증 서버에서 이전에 전달받은 code_challenge_method로 code_verifier를 code_challenge 값으로 변환하고, 이전에 전달받은 code_challenge 값과 일치하는지 비교한다. 그래서 맞으면 토큰을 발급하고, 틀리면 거부하는 것이다.

sequenceDiagram
    autonumber
    participant C as Client
    participant B as Browser
    participant A as Auth Server

    C->>C: code_verifier, code_challenge 생성
    C->>B: 브라우저로 인증 요청 시작<br/>(with code_challenge, code_challenge_method)
    B->>A: 인증 요청 전달
    A->>A: code_challenge 저장
    A-->>B: 로그인 페이지 제공
    B->>A: 사용자 로그인 및 동의
    A-->>B: 리디렉션을 통해 Authorization Code 반환
    B-->>C: Authorization Code 전달
    C->>A: Access Token 교환 요청<br/>(with Authorization Code, code_verifier)
    A->>A: code_verifier로 code_challenge 생성 후 저장값과 비교 검증
    A-->>C: 검증 성공 시 Access Token 반환

 

 

[ CLI와 Authorization Code Flow 방식 ]

문제는 Authorization Code Flow(+PKCE)가, 스마트 티비나 CLI와 같은 브라우저가 존재하지 않는 환경에서 활용이 어렵다는 것이다. 근본적으로 Authorization Code Flow는 인증 서버가 리디렉션 URI로 코드를 돌려주는 걸 전제로 한다. CLI가 인증을 요청할 때 인증 코드를 돌려받을 리디렉션 URI를 함께 지정하는데, 인증 서버가 그 URI로 코드를 보내주려 해도 CLI에는 그걸 받을 서버가 없다는 것이다.

따라서 CLI에서는 인증 코드를 돌려받기 위한 임시 HTTP 서버를 띄우고, 리디렉션 URI를 자기 루프백 주소(http://127.0.0.1)로 지정한다. 그리고 인증 코드 발급을 위해 CLI에 노출된 URL을 브라우저에서 로그인 후 이 주소로 리디렉션하면, 로컬에서 대기 중이던 CLI가 코드를 받아낸다.

sequenceDiagram
    autonumber
    participant C as CLI
    participant B as Browser
    participant A as Auth Server

    C->>C: 로컬 루프백 서버 기동 (예: 127.0.0.1:52741)
    C->>B: 브라우저 실행 + 인증 요청 <br/>redirect_uri=http://127.0.0.1:52741/callback
    B->>A: 인증 요청 전달 (redirect_uri 포함)
    A->>A: 등록된 redirect_uri와 일치 검증
    A-->>B: 로그인 후 redirect_uri로 리디렉션<br/>?code=AUTH_CODE&state=xyz
    B-->>C: 루프백 주소로 코드 전달
    C->>C: state 검증 후 code 추출
    C->>A: Authorization Code로 Access Token 교환
    A-->>C: Access Token 반환

 

 

하지만 억지로 HTTP 서버를 띄우다 보니, 여러 가지 부가적인 문제들이 생길 수 있다.

  • 루프백 서버를 위한 포트 문제
    • 서버의 포트를 위해 고정 포트를 사용할 경우, 다른 프로세스가 사용중일 때 충돌이 생김
    • 동적 포트(비어 있는 포트를 골라 씀)로 하면, 인증 서버에 리디렉션 URI를 미리 등록해둘 때 포트를 특정할 수 없어 와일드카드 허용이 필요함
  • 브라우저 실행 환경 문제
    • CLI가 로그인 페이지를 열려면 브라우저를 띄워야 함
    • 로컬 데스크톱이면 open/xdg-open/start로 열면 되는데 원격 SSH 세션, 헤드리스 서버, 컨테이너 안에서는 브라우저가 아예 없어 로그인이 불가능함
  • 클라이언트 시크릿 문제
    • CLI는 사용자 기기에 바이너리로 배포되는데, 여기에 클라이언트 시크릿을 심으면 누구나 추출할 수 있음
    • 따라서 CLI는 시크릿을 못 쓰는 퍼블릭 클라이언트로 취급해야 하고, 코드 탈취 방어를 위해 PKCE가 필수가 됨

 

 

이러한 문제들로 인해, CLI를 위한 인증 방식으로는 Device Authorization Flow 방식이 권장된다.

 

 

[ Device Authorization Flow 방식이란? ]

Device Authorization Flow는 입력 기능이 제한된 스마트 TV 혹은 CLI와 같은 헤드리스 앱을 위해 설계된 OAuth 2.0 인증 부여 방식이다. 사용자가 이러한 디바이스에서 인증 요청을 시작하면, 스마트폰이나 노트북 등과 같은 더 많은 입력 기능을 가진 디바이스에서 프로세스를 완료할 수 있다. 예를 들어 우리가 스마트 TV에서 넷플릭스를 보기 위해 로그인을 할 때, 코드를 입력하는 방식이 바로 Device Authorization Flow라고 볼 수 있다.

 

 

 

Device Authorization Flow 인증 방식을 위해서는 크게 2가지 코드(Device Code, User Code) 개념이 등장한다.

  • User Code (사용자 코드)
    • 사람이 읽고 입력하는 코드로, 이를 기반으로 로그인을 시도하는 당사자가 맞는지를 확인함
    • 8자 내외, 대문자, 하이픈으로 구분되어 짧고 타이핑하기 쉽게 만들어짐 ex) WDJB-MJHT
    • 인증 서버는 짧은 만료 시간과 시도 횟수 제한으로 무차별 대입을 막음
  • Device Code (디바이스 코드)
    • CLI나 스마트 TV 등의 기기가 쓰는 코드로, 사람은 볼 일도, 입력할 일도 없음
    • 로그인을 시도하는 기계를 식별하기 위해 사용됨
    • 사람이 타이핑하지 않으니 길고 복잡해도 되어 긴 문자열이 사용됨

 

 

전반적인 인증 흐름 과정을 살펴보면 다음과 같다.

sequenceDiagram
    autonumber
    participant U as User at browser
    participant D as CLI
    participant A as Auth Server

    D->>A: Client ID로 인증 요청
    A-->>D: Device Code, User Code, 인증 URI를 제공함
    D->>U: 사용자에게 인증 URI를 열고 User Code를 입력하도록 지시함
    D->>A: Device Code와 Client ID로 Access Token 폴링 시작
    U->>A: 인증 URI 접속 및 User Code 입력
    A-->>U: 사용자를 로그인 페이지로 리디렉션
    U->>A: 로그인 플로우 완료 및 로그인
    A-->>U: 사용자를 로그인 성공 페이지로 리디렉션하고 브라우저를 닫도록 지시
    A-->>D: 폴링 결과로 Access Token을 반환받음

 

 

Device Authorization Flow 인증 방식을 사용하면, CLI 환경에서 Authorization Code Flow 인증 방식을 사용할 때 생겼던 여러 가지 문제로부터 자유로워질 수 있다. 토큰을 요청하는 CLI와 사용자가 인증하는 브라우저 장치를 분리해, 포트 바인딩이나 로컬 브라우저 의존이 없다. 또한 노트북이나 컨테이너, CI 등 어디서나 동일하게 작동할 수 있다.

 

 

 

참고 자료

 

 

 

 

 

반응형
댓글
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG more
«   2026/07   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함