수정: `xurl` OAuth 2.0이 X API에서 'unauthorized_client' 오류로 실패

발행: (2026년 2월 23일 오후 09:22 GMT+9)
7 분 소요
원문: Dev.to

Source: Dev.to

xurl을 사용해 X API에 인증하고 다음 오류가 표시되는 경우:

OAuth2 authentication failed: Auth Error: TokenExchangeError
(cause: oauth2: "unauthorized_client" "Missing valid authorization header")

해결 방법은 X 개발자 포털의 한 가지 설정을 변경하는 것입니다.

왜 이런 일이 발생하는가

xurlOAuth 2.0 PKCE 흐름을 사용합니다. 이 흐름은 공개 클라이언트(모바일 앱, CLI, SPA)를 위해 설계되었습니다. 공개 클라이언트는 토큰 교환 시 요청 본문에 자격 증명을 포함합니다.

X API 앱은 기본적으로 기밀 클라이언트로 생성됩니다. 기밀 클라이언트는 Authorization: Basic 헤더를 통해 자격 증명을 전달해야 하는데, xurl은 이 방식을 사용하지 않습니다. xurl이 해당 헤더 없이 토큰 교환 요청을 보내면 X는 unauthorized_client 오류와 함께 이를 거부합니다.

앱 유형을 확인하려면 클라이언트 ID를 base64 디코딩해 보세요:

echo "YOUR_CLIENT_ID" | base64 -d
  • 디코딩된 값이 :ci 로 끝나면 기밀 클라이언트입니다.
  • :na 로 끝나면 네이티브(공개) 클라이언트입니다.

해결 방법

  1. X 앱 유형Web App에서 Native App으로 개발자 포털에서 변경합니다.

  2. 포털에서:
    앱 선택 → User authentication settingsEdit

    • App typeNative App으로 설정
    • Callback URIhttp://localhost:8080/callback 로 설정
    • 저장
  3. 새 자격 증명을 다시 등록하고 xurl로 인증합니다:

    # 포털에서 새 자격 증명을 생성한 후 다시 등록
    xurl auth apps add my-app \
      --client-id YOUR_NEW_CLIENT_ID \
      --client-secret YOUR_NEW_CLIENT_SECRET
    
    # 베어러 토큰 및 OAuth 1.0a 자격 증명 저장 (선택 사항)
    xurl auth app --bearer-token YOUR_BEARER_TOKEN
    xurl auth oauth1 \
      --consumer-key YOUR_CONSUMER_KEY \
      --consumer-secret YOUR_CONSUMER_SECRET \
      --access-token YOUR_ACCESS_TOKEN \
      --token-secret YOUR_ACCESS_TOKEN_SECRET
    
    # 기본 앱으로 설정
    xurl auth default my-app
    
    # PKCE 흐름 실행
    xurl --app my-app auth oauth2
  4. 브라우저 기반 동의 흐름을 완료한 후, 모든 것이 정상 작동하는지 확인합니다:

    xurl auth status
    xurl --auth oauth2 /2/users/me          # 사용자 컨텍스트
    xurl --auth oauth1 /2/users/me          # 역시 작동
    xurl --auth app "/2/tweets/search/recent?query=hello&max_results=5"  # 앱 전용

보너스: 앱 유형을 변경한 후 자격 증명 재생성

앱 유형을 전환하면 X는 :na 접미사가 붙은 새로운 클라이언트 ID를 발급합니다. 이전 :ci ID는 PKCE 흐름에서 더 이상 유효하지 않으므로, xurl로 다시 등록하기 전에 Keys and Tokens 탭에서 새로운 값을 복사하십시오.

TL;DR

앱 유형클라이언트 ID 접미사xurl OAuth 2.0와 호환 여부?
웹 앱 / 봇:ci (기밀)
네이티브 앱 / SPA:na (공개)

X 개발자 포털에서 네이티브 앱으로 변경하고, 자격 증명을 다시 생성하면 xurl의 OAuth 2.0 흐름이 정상적으로 작동합니다.

웹 앱은 OAuth 2.0을 지원하나요?

Web App/Bot 앱 OAuth 2.0을 지원하지만 xurl을 통해서는 지원되지 않습니다. xurl은 공개 클라이언트 PKCE 흐름만 구현하기 때문입니다. 기밀 클라이언트는 토큰 교환 단계에서 Authorization: Basic 헤더가 필요하며, 이는 대부분의 CLI 도구( xurl 포함)에서 X에 대해 처리하지 못합니다.

curl을 이용한 수동 OAuth 2.0

Step 1 – 인증 URL을 생성하고 브라우저에서 열기:

# 코드 검증자와 챌린지를 생성합니다 (PKCE는 선택 사항이지만 권장됩니다)
VERIFIER=$(openssl rand -base64 32 | tr -d '=+/' | cut -c1-43)
CHALLENGE=$(echo -n "$VERIFIER" | openssl dgst -sha256 -binary | base64 | tr '+/' '-_' | tr -d '=')
STATE=$(openssl rand -hex 16)

CLIENT_ID="YOUR_CLIENT_ID"
REDIRECT="http://localhost:8080/callback"

echo "https://x.com/i/oauth2/authorize?response_type=code&client_id=${CLIENT_ID}&redirect_uri=${REDIRECT}&scope=tweet.read%20users.read%20offline.access&state=${STATE}&code_challenge=${CHALLENGE}&code_challenge_method=S256"

출력된 URL을 브라우저에서 열고, 인증을 진행한 뒤 리다이렉트 URL에서 code=… 값을 복사합니다.

Step 2 – Basic Auth를 사용해 코드를 교환:

CLIENT_ID="YOUR_CLIENT_ID"
CLIENT_SECRET="YOUR_CLIENT_SECRET"
CODE="CODE_FROM_REDIRECT"
VERIFIER="THE_VERIFIER_FROM_STEP_1"

curl -X POST https://api.x.com/2/oauth2/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -H "Authorization: Basic $(echo -n "${CLIENT_ID}:${CLIENT_SECRET}" | base64 -w 0)" \
  -d "grant_type=authorization_code&code=${CODE}&redirect_uri=${REDIRECT}&code_verifier=${VERIFIER}"

응답에 포함된 access_token을 바로 xurl과 함께 사용할 수 있습니다:

xurl -H "Authorization: Bearer ACCESS_TOKEN" /2/users/me

언제 어떤 것을 사용해야 할까

사용 사례앱 유형인증 방법
CLI / 로컬 개발네이티브 앱xurl oauth2 (PKCE, 비밀키 없음)
서버‑사이드 앱웹 앱 / 봇OAuth 2.0 기밀 (Basic Auth, 비밀키는 서버에 보관)
자신으로 게시모든 앱OAuth 1.0a (개인용으로 가장 간단)
읽기 전용 공개 데이터모든 앱Bearer token (앱 전용)

Web App/Bot + OAuth 2.0은 클라이언트 비밀키가 서버를 떠나지 않는 서버‑사이드 애플리케이션을 위해 설계되었습니다. 로컬 CLI 사용의 경우 네이티브 앱이 올바른 선택입니다. OAuth 1.0a는 어느 앱 유형과도 함께 사용할 수 있으며, 개인용이나 개발용으로 가장 저항이 적은 경로가 되는 경우가 많습니다.

0 조회
Back to Blog

관련 글

더 보기 »