메인 콘텐츠로 건너뛰기

PKCE를 사용하는 OAuth 2.0 승인 코드 플로우로 엔드포인트에 연결하는 방법

엔드포인트에 연결하는 방법

사용자를 인증하려면 App에서 인가 플로우를 구현해야 합니다. 이 인가 플로우를 통해 사용자를 X의 인가 대화상자로 보낼 수 있습니다. 그 이후부터는 기본 X 사용 환경에서 인가 대화상자를 표시하고 App을 대신해 인가 과정을 처리합니다. 사용자는 App에 권한을 부여하거나 권한 부여를 거부할 수 있습니다. 사용자가 선택을 완료하면 X는 사용자를 App으로 리디렉션하고, 그곳에서 (사용자가 App을 인가한 경우) 인가 코드를 액세스 토큰으로 교환하거나 (사용자가 App을 인가하지 않은 경우) 거부 상황을 처리할 수 있습니다.

기밀 클라이언트 사용하기

기밀 클라이언트를 사용하는 경우, 토큰 엔드포인트에 요청을 보낼 때 기본 인증 방식을 사용해 base64로 인코딩한 Authorization 헤더를 생성해야 합니다. 자격 증명에서 useridpassword는 base64로 인코딩된 문자열 안에서 콜론(”:”) 문자 하나로 구분됩니다. 예시는 다음과 같습니다: -header 'Authorization: Basic V1ROclFTMTRiVWhwTWw4M2FVNWFkVGQyTldNNk1UcGphUTotUm9LeDN4NThKQThTbTlKSXQyZm1BanEzcTVHWC1icVozdmpKeFNlR3NkbUd0WEViUA==' 사용자 에이전트가 Client ID “Aladdin”과 password “open sesame”를 전송하려는 경우, 다음과 같은 헤더 필드를 사용합니다: Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ== 기본 인증 헤더를 생성하려면, App의 “Keys and Tokens” 페이지( 개발자 콘솔 내에 위치)에서 확인할 수 있는 Client ID와 Client Secret에 base64 인코딩을 적용해야 합니다.

OAuth 2.0을 사용하여 연결하는 단계

1단계: Authorize URL 구성하기 App은 필요한 scope를 지정하여 X로 향하는 authorize URL을 구성해야 합니다. 예를 들어, App이 Tweet과 사용자 조회, 팔로우 관리를 해야 한다면 다음 scope를 요청해야 합니다: tweet.read%20users.read%20follows.read%20follows.write 이 URL에는 다른 필수 매개변수 외에 code_challenge와 state 매개변수도 포함됩니다. 운영 환경에서는 code_challenge에 임의의 문자열을 사용해야 합니다. 2단계: GET oauth2/authorize 사용자가 인증을 완료하고 애플리케이션에 authorization code를 보내도록 해야 합니다. App에 대해 OAuth 2.0을 활성화한 경우, App의 “Keys and Tokens” 페이지에서 Client ID를 확인할 수 있습니다. 사용자를 리디렉션할 예시 URL은 다음과 같습니다:
https://x.com/i/oauth2/authorize?response_type=code&client_id=M1M5R3BMVy13QmpScXkzTUt5OE46MTpjaQ&redirect_uri=https://www.example.com&scope=tweet.read%20users.read%20follows.read%20follows.write&state=state&code_challenge=challenge&code_challenge_method=plain
offline_access가 포함된 URL의 예시는 다음과 같습니다:
https://x.com/i/oauth2/authorize?response_type=code&client_id=M1M5R3BMVy13QmpScXkzTUt5OE46MTpjaQ&redirect_uri=https://www.example.com&scope=tweet.read%20users.read%20follows.read%20offline.access&state=state&code_challenge=challenge&code_challenge_method=plain
인증이 성공하면 redirect_uriauth_code 파라미터가 포함된 요청이 전달됩니다. 이때 애플리케이션은 state 파라미터를 검증해야 합니다. Clientredirect_uri 로 전달되는 요청 예시는 다음과 같습니다:
https://www.example.com/?state=state&code=VGNibzFWSWREZm01bjN1N3dicWlNUG1oa2xRRVNNdmVHelJGY2hPWGxNd2dxOjE2MjIxNjA4MjU4MjU6MToxOmFjOjE
3단계: POST oauth2/token - 액세스 토큰 이제 인가 코드를 사용해 액세스 토큰과 리프레시 토큰을 생성할 수 있습니다 (offline.access 스코프를 요청한 경우에만 해당). 다음 엔드포인트로 POST 요청을 전송할 수 있습니다:
https://api.x.com/2/oauth2/token
요청 헤더를 통해 Content-Type으로 application/x-www-form-urlencoded를 전달해야 합니다. 추가로, 요청에는 code, grant_type, client_id, redirect_uri, 그리고 code_verifier가 포함되어야 합니다. 다음은 public client용 토큰 요청 예시입니다:
curl --location --request POST 'https://api.x.com/2/oauth2/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'code=VGNibzFWSWREZm01bjN1N3dicWlNUG1oa2xRRVNNdmVHelJGY2hPWGxNd2dxOjE2MjIxNjA4MjU4MjU6MToxOmFjOjE' \
--data-urlencode 'grant_type=authorization_code' \
--data-urlencode 'client_id=rG9n6402A3dbUJKzXTNX4oWHJ' \
--data-urlencode 'redirect_uri=https://www.example.com' \
--data-urlencode 'code_verifier=challenge'
다음은 confidential 클라이언트를 사용하는 예제입니다:
curl --location --request POST 'https://api.x.com/2/oauth2/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--header 'Authorization: Basic V1ROclFTMTRiVWhwTWw4M2FVNWFkVGQyTldNNk1UcGphUTotUm9LeDN4NThKQThTbTlKSXQyZm1BanEzcTVHWC1icVozdmpKeFNlR3NkbUd0WEViUA=='\
--data-urlencode 'code=VGNibzFWSWREZm01bjN1N3dicWlNUG1oa2xRRVNNdmVHelJGY2hPWGxNd2dxOjE2MjIxNjA4MjU4MjU6MToxOmFjOjE' \
--data-urlencode 'grant_type=authorization_code' \
--data-urlencode 'redirect_uri=https://www.example.com' \
--data-urlencode 'code_verifier=challenge'
4단계: API에 연결하기 이제 OAuth 2.0을 사용해 엔드포인트에 연결할 준비가 되었습니다. 이를 위해 Bearer Token 인증을 사용할 때와 동일한 방식으로 API 요청을 보내면 됩니다. 다만 Bearer Token을 전달하는 대신, 직전 단계에서 생성한 액세스 토큰을 사용해야 합니다. 응답으로는 요청한 엔드포인트에 해당하는 적절한 페이로드가 반환되어야 합니다. 이 요청 방식은 공개 클라이언트(public client)와 기밀 클라이언트(confidential client) 모두에 동일하게 적용됩니다.  요청 예시는 다음과 같습니다:
curl --location --request GET 'https://api.x.com/2/tweets?ids=1261326399320715264,1278347468690915330' \
--header 'Authorization: Bearer Q0Mzb0VhZ0V5dmNXSTEyNER2MFNfVW50RzdXdTN6STFxQlVkTGhTc1lCdlBiOjE2MjIxNDc3NDM5MTQ6MToxOmF0OjE'
5단계: POST oauth2/token - refresh token refresh token을 사용하면 사용자의 추가 동의 없이도 애플리케이션이 새로운 access token을 발급받을 수 있습니다. refresh token은 다음 엔드포인트에 POST 요청을 보내 생성할 수 있습니다: https://api.x.com/2/oauth2/token 헤더에 Content-Type으로 application/x-www-form-urlencoded를 추가해야 합니다. 추가로, refresh_token을 전달하고, grant_type을 refresh_token으로 설정하며, client_id를 지정해야 합니다. 이 요청은 공개 클라이언트(public client)에 대해 동작합니다:
POST 'https://api.x.com/2/oauth2/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'refresh_token=bWRWa3gzdnk3WHRGU1o0bmRRcTJ5VUxWX1lZTDdJSUtmaWcxbTVxdEFXcW5tOjE2MjIxNDc3NDM5MTQ6MToxOnJ0OjE' \
--data-urlencode 'grant_type=refresh_token' \
--data-urlencode 'client_id=rG9n6402A3dbUJKzXTNX4oWHJ'
다음은 기밀 클라이언트용 예시입니다.
POST 'https://api.x.com/2/oauth2/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--header 'Authorization: Basic V1ROclFTMTRiVWhwTWw4M2FVNWFkVGQyTldNNk1UcGphUTotUm9LeDN4NThKQThTbTlKSXQyZm1BanEzcTVHWC1icVozdmpKeFNlR3NkbUd0WEViUA=='\
--data-urlencode 'refresh_token=bWRWa3gzdnk3WHRGU1o0bmRRcTJ5VUxWX1lZTDdJSUtmaWcxbTVxdEFXcW5tOjE2MjIxNDc3NDM5MTQ6MToxOnJ0OjE'\
--data-urlencode 'grant_type=refresh_token'
6단계: POST oauth2/revoke - 토큰 폐기 revoke 토큰은 access 토큰이나 refresh 토큰을 무효화합니다. 이는 클라이언트에서 “로그아웃” 기능을 구현할 때 사용되며, 더 이상 필요하지 않을 수 있는 인가 플로와 연관된 보안 자격 증명을 정리할 수 있도록 해 줍니다. revoke 토큰은 사용자가 아니라 App이 토큰을 취소하기 위한 것입니다. App이 자신에게 부여된 액세스를 프로그래밍 방식으로 취소(revoke)하려는 경우, 다음 URL로 POST 요청을 보내 revoke 토큰 요청을 생성할 수 있습니다:
https://api.x.com/2/oauth2/revoke
헤더를 통해 Content-Typeapplication/x-www-form-urlencoded로 지정하고, 토큰과 client_id를 함께 전달해야 합니다. 경우에 따라 사용자가 App에 부여한 권한을 취소하고 싶을 수 있습니다. 이때 Connected Apps 페이지를 방문하여 권한을 취소할 수 있습니다.
curl --location --request POST 'https://api.x.com/2/oauth2/revoke' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'token=Q0Mzb0VhZ0V5dmNXSTEyNER2MFNfVW50RzdXdTN6STFxQlVkTGhTc1lCdlBiOjE2MjIxNDc3NDM5MTQ6MToxOmF0OjE' \
--data-urlencode 'client_id=rG9n6402A3dbUJKzXTNX4oWHJ'
이 요청은 confidential 클라이언트에서 사용할 수 있습니다:
curl --location --request POST 'https://api.x.com/2/oauth2/revoke' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--header 'Authorization: Basic V1ROclFTMTRiVWhwTWw4M2FVNWFkVGQyTldNNk1UcGphUTotUm9LeDN4NThKQThTbTlKSXQyZm1BanEzcTVHWC1icVozdmpKeFNlR3NkbUd0WEViUA=='\
--data-urlencode 'token=Q0Mzb0VhZ0V5dmNXSTEyNER2MFNfVW50RzdXdTN6STFxQlVkTGhTc1lCdlBiOjE2MjIxNDc3NDM5MTQ6MToxOmF0OjE'