메인 콘텐츠로 건너뛰기

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

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

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

기밀 클라이언트와 작업하기

기밀 클라이언트와 작업하는 경우 토큰 엔드포인트에 요청을 보낼 때, Base64 인코딩을 사용해 인증 헤더를 생성하는 기본 인증 스키마를 사용해야 합니다. useridpassword는 자격 증명에서 Base64로 인코딩된 문자열 내부에서 콜론(”:”) 한 개로 구분됩니다. 예시는 다음과 같습니다: -header 'Authorization: Basic V1ROclFTMTRiVWhwTWw4M2FVNWFkVGQyTldNNk1UcGphUTotUm9LeDN4NThKQThTbTlKSXQyZm1BanEzcTVHWC1icVozdmpKeFNlR3NkbUd0WEViUA==' 사용자 에이전트가 Client ID “Aladdin”과 비밀번호 “open sesame”를 전송하려면 다음 헤더 필드를 사용합니다: Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ== 기본 인증 헤더를 생성하려면 App의 “키와 토큰(Keys and Tokens)” 페이지에서 확인할 수 있는 Client ID와 Client Secret에 대해 Base64 인코딩을 수행해야 합니다. 해당 페이지는 개발자 포털 내에 있습니다.

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

1단계: Authorize URL 구성 앱은 필요한 권한 범위(scope)를 명시하여 X로 향하는 authorize URL을 만들어야 합니다. 예를 들어, 앱이 게시물 조회, 사용자 조회 및 팔로우 관리를 해야 한다면 다음 권한 범위를 요청해야 합니다: tweet.read%20users.read%20follows.read%20follows.write 이 URL에는 다른 필수 매개변수와 함께 code_challenge 및 state 매개변수가 포함됩니다. 운영 환경에서는 code_challenge에 난수 문자열을 사용해야 합니다. 2단계: GET oauth2/authorize 사용자가 인증을 완료하고 애플리케이션에 authorization code를 보내도록 합니다. 앱에 대해 OAuth 2.0을 활성화했다면 앱의 “키와 토큰(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_uri로 auth_code 매개변수가 포함된 요청이 전달됩니다. 애플리케이션은 state 매개변수를 검증해야 합니다. 클라이언트의 리디렉션으로부터 수신되는 예시 요청은 다음과 같습니다:
https://www.example.com/?state=state&code=VGNibzFWSWREZm01bjN1N3dicWlNUG1oa2xRRVNNdmVHelJGY2hPWGxNd2dxOjE2MjIxNjA4MjU4MjU6MToxOmFjOjE
3단계: POST oauth2/token - 액세스 토큰 이제 인증 코드를 사용해 액세스 토큰과 리프레시 토큰(offline.access 범위를 요청한 경우에 한함)을 발급받을 수 있습니다. 다음 엔드포인트로 POST 요청을 보내세요:
https://api.x.com/2/oauth2/token
헤더를 통해 Content-Typeapplication/x-www-form-urlencoded로 설정해야 합니다. 또한 요청에는 code, grant_type, client_id, redirect_uri, 그리고 code_verifier를 포함해야 합니다. 다음은 퍼블릭 클라이언트를 위한 토큰 요청 예시입니다:
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'
다음은 기밀 클라이언트를 사용하는 예시입니다:
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을 전달하는 대신, 이전 단계에서 생성한 액세스 토큰을 사용해야 합니다. 응답으로는 요청한 엔드포인트에 해당하는 적절한 페이로드가 반환되어야 합니다. 이 요청 방식은 퍼블릭 클라이언트와 기밀 클라이언트 모두에 동일합니다. 다음은 수행할 요청의 예시입니다:
curl --location --request GET 'https://api.x.com/2/tweets?ids=1261326399320715264,1278347468690915330' \
--header 'Authorization: Bearer Q0Mzb0VhZ0V5dmNXSTEyNER2MFNfVW50RzdXdTN6STFxQlVkTGhTc1lCdlBiOjE2MjIxNDc3NDM5MTQ6MToxOmF0OjE'
5단계: POST oauth2/token - 리프레시 토큰 리프레시 토큰은 사용자에게 다시 동의를 요청하지 않고 애플리케이션이 새로운 액세스 토큰을 발급받을 수 있게 해줍니다. 다음 엔드포인트에 POST 요청을 보내 리프레시 토큰을 생성할 수 있습니다: https://api.x.com/2/oauth2/token 헤더에 Content-Type으로 application/x-www-form-urlencoded를 추가해야 합니다. 또한 refresh_token을 전달하고, grant_typerefresh_token으로 설정하며, client_id를 지정해야 합니다. 이 요청은 공개 클라이언트에서 동작합니다:
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 - 토큰 철회 토큰 취소는 액세스 토큰 또는 리프레시 토큰을 무효화합니다. 이는 클라이언트에서 로그아웃 기능을 구현할 때 사용되며, 더 이상 필요하지 않을 수 있는 인증 흐름과 관련된 보안 자격 증명을 정리할 수 있게 합니다. 토큰 취소는 사용자용이 아니라 App이 토큰을 취소하기 위한 것입니다. App이 자신에게 부여된 액세스를 프로그래밍 방식으로 취소하려는 경우, 다음 URL로 POST 요청을 보내 토큰 취소 요청을 생성할 수 있습니다:
https://api.x.com/2/oauth2/revoke
헤더를 통해 Content-Typeapplication/x-www-form-urlencoded로 지정하고, 토큰 및 client_id를 전달해야 합니다. 일부 경우 사용자가 앱에 부여한 액세스 권한을 해지하려면 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'
이 요청은 기밀 클라이언트에서 동작합니다:
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'