R언어 시각화 통계 입문
동그랑땡의 github 자세히보기

동그랑땡의 데이터 데이터 데이터/R언어 입문땡

R httr2 패키지로 티스토리 API의 Authentication Code 방식 권한 받기

동그랑땡12 2023. 10. 27. 15:53

Authentication Code 방식 인증 프로세스

티스토리 API를 사용하려면 Authentication Code 방식을 통해 내가 API 사용에 적합한 사용자임을 인증해야 한다.

 

인증 프로세스는 다음과 같다.

티스토리(tistory.com)에 인증 요청 -> 웹브라우저에서 요청 확인 -> 리디렉션 페이지에서 url 내 code 확인 -> code를 이용하여 access token 요청 -> access token 확인(서버내 응답으로) -> access token을 이용하여 글 내용 요청(자세한 내용은 하단 티스토리 API 공식 문서 참고)

access token을 이용한 글 내용 요청은 인증에 성공하고 최종적으로 하려고 했던 프로세스이다.

 

R에서는 이러한 인증 프로세스를  httr2 패키지로 진행할 수 있다.

 

httr2 패키지는 R 필수 패키지인 tidyverse를 만든 해들리 위컴이 만들었다.

 

꽤나 최신 패키지라 그런지 httr2 패키지를 물어보면 gpt4가 이상한 응답을 내놓고 있다.(2023.10.27 기준)

 

때문에 이 글이 몇몇 소수의 R 덕후분들에게 가이드가 될 수 있지 않을까 살짝 기대해 본다.

 

(httr2 패키지와 관련된 자세한 내용은 하단 httr2 공식 문서 참고)


들어가기 전에.

 

이 글을 통한 티스토리 api 인증 프로세스는 세련된 플로우를 갖고 있진 못하다.

 

(몇몇 프로세스를 넘어가는데 수작업이 필요하다.)

 

이러한 원인은 본인의 지식, 노하우, 노력 부족 문제일 가능성이 크다.

 

(어쩌면, httr2 패키지의 한계일지도...) 

 

이 프로세스보다 세련된 프로세스를 만드셨다면, 공유해 주시길 간곡히 부탁하는 바이다.


1. 티스토리에 인증 요청 ~ url내 code 확인

티스토리 인증 요청은 httr2의 req_oauth_auth_code 혹은 oauth_flow_auth_code 두 가지 코드로 진행할 수 있다.

 

이 두 가지 코드를 사용하기 위해선 먼저 oauth_client를 만들어줘야 한다.


1.1. oauth_client

clientID='0000aaaa0000aaaa0000aaaa'
secretKey = '1111bbbb1111bbbb1111bbbb1111bbbb1111bbbb1111bbbb'
tokenUrl = 'https://www.tistory.com/oauth/access_token'

client1 = oauth_client(
  clientID,
  tokenUrl,
  secret = secretKey,
  name = 'oooo-tistory-auth'
  )
client1

oauth_client 함수의 인수(argument)를 뜯어보자.

oauth_client(
  id,
  token_url,
  secret = NULL,
  name = hash(id)
)

id = client id는 티스토리 api 앱에서 App id에 해당한다.

 

secret 역시 티스토리 api 앱에서  Secret Key를 복사하여 사용하면 된다.

Secret Key의 유출을 막기 위해 obfuscate()라는 함수로 난독화(난수화까지의 보안을 제공하는 것은 아닌 것으로 보인다.)하고 사용하는 방법이 있지만 여기서는 생략했다.

(obfuscate를 원한다면 하단에 링크한 공식문서를 참고하자)

 

token_url은 티스토리 api 공식 문서에 나온 access token 발급 주소 https://www.tistory.com/oauth/access_token을 사용했다.

 

name은 지정하지 않아도 된다.

 

코드를 실행해 보면 아래와 같은 결과창이 나온다.

<httr2_oauth_client>
name: oooo-tistory-auth
id: 0000aaaa0000aaaa0000aaaa
secret: <REDACTED>
token_url: https://www.tistory.com/oauth/access_token
auth: oauth_client_req_auth_body


1.2. oauth_flow_auth_code 혹은 req_oauth_auth_code 

만들어 놓은 oauth_client는  client1 객체에 할당했다.

 

이제 client1과 oauth_flow_auth_code 혹은 req_oauth_auth_code 함수를 통해 code를 받아올 것이다.

 

지금 과정을 통해 위 세 개 단계를 해치울수 있다!

두 가지 함수 중 더 간단한  oauth_flow_auth_code만 다뤄보겠다.

 

(req_oauth_auth_code 함수는 하단에 간단하게 사용한 코드만 적어놓겠다.)

 

oauth_flow_auth_code를 이용하면 웹브라우저가 자동으로 열리면서 아래와 같은 창을 만날 수 있다.

 

사용한 oauth_flow_auth_code는 다음과 같다.

authUrl = 'https://www.tistory.com/oauth/authorize'

oauth_flow_auth_code(
	client1,
	auth_url = authUrl,
    	auth_params = list(redirect_uri='https://oooo12.tistory.com', response_type='code')
)

oauth_flow_auth_code 함수의 인수 역시 뜯어보자.

oauth_flow_auth_code(
  client,
  auth_url,
  auth_params = list()
)

client 에는 oauth_client 함수를 통해 생성한 객체 client1을 사용한다.

 

auth_url은 티스토리 api 공식 문서에 있는 https://www.tistory.com/oauth/authorize 를 사용한다.

 

auth_params는 oauth_flow_auth_code 인수 내에 포함되지 않았지만 인증 url에 포함된 parameter를 리스트로 만들어서 넣어준다.

# 티스토리 api 인증요청 url
https://www.tistory.com/oauth/authorize?
  client_id={client-id}
  &redirect_uri={redirect-uri}
  &response_type=code

티스토리 api 인증에는 client_id, redirect_uri, response_type 이 필요하다.

 

하지만 oauth_flow_auth_code 인수는 client만 커버하고 있다.

 

때문에 redirect_uri, response_type와 해당 값에 대한 list 객체를 만들어, auth_params 인수값으로 사용했다.

auth_params = list(redirect_uri='https://oooo12.tistory.com', response_type='code')

redirect_uri는 티스토리 api에서 클라이언트 정보의 callback경로와 동일하게 해야 한다 했기 때문에 티스토리 app에 등록한 callback 주소를 사용하면 된다.

 

callback 주소에는 블로그 주소를 사용한다.

 

이렇게 해서 아래 oauth_flow_auth_code 함수를 실행하면

authUrl = 'https://www.tistory.com/oauth/authorize'

oauth_flow_auth_code(
	client1,
	auth_url = authUrl,
    	auth_params = list(redirect_uri='https://oooo12.tistory.com', response_type='code')
)

웹브라우저가 열리고 위와 같은 창이 나온다.

 

'허가하기'를 누르면

 

callback url (= 블로그주소)로 리디렉션 되고 주소창을 클릭하면

 

code = ~~~~~ 부분이 url에 나타나있다. 이 부분 (~~~~~) 이 인증요청을 통해 받은 code에 해당한다.


2. code 이용하여 access token 요청 + 확인

확인한 code는 객체에 잘 보관해 두자.

 

주소창 url이 만약 아래와 같다면

 

https://oooo12.tistory.com/?code=0000011111122222333334444555566667777&state=0a1b2c3d4e5f6g7h

 

사용해야 할 코드는 빨간색 부분이고 이것을 code1라는 객체에 할당해 놓자.

https://oooo12.tistory.com/?code= 0000011111122222333334444555566667777&state=0a1b2c3d4e5f6g7h

code1 = '0000011111122222333334444555566667777'

토큰은 request 함수로 서버에 요청하여 확인할 수 있다.



2.1. 토큰 확인(발행)

토큰을 발행하려면 아래 주소의 서버로 요청하는 경우에만 토큰을 발급한다고 티스토리 api가 공식문서를 통해 밝혔다.(보안 때문)

 

때문에 브라우저로 아래 주소에 들어가더라도 토큰은 받을 수 없다.

https://www.tistory.com/oauth/access_token?
  client_id={client-id}
  &client_secret={client-secret}
  &redirect_uri={redirect-uri}
  &code={code}
  &grant_type=authorization_code

위 주소를 R에서 구현하기 위해 paste0 함수를 사용했다.(엑셀의 concatenate 함수와 비슷하다)

reqToken = request(
  paste0('https://www.tistory.com/oauth/access_token?client_id=',
         clientID,
         '&client_secret=',secretKey,
         '&redirect_uri=https://oooo12.tistory.com',
         '&code=',code1,
         '&grant_type=authorization_code')
)
reqToken

위 코드를 통해 구현한 요청은 다음과 같다.

<httr2_request>
GET
https://www.tistory.com/oauth/access_token?client_id=*********&client_secret=*********&redirect_uri=https://oooo12.tistory.com&code=*********&grant_type=authorization_code
Body: empty

아래 코드는 요청을 하고 받은 응답을 resp 객체에 저장한 것이다.

resp <- reqToken %>% req_perform()
resp

 

resp객체를 확인하면 토큰이 바로 보이지 않는다. 

<httr2_response>
GET
https://www.tistory.com/oauth/access_token?client_id=*******&client_secret=*********&redirect_uri=https://oooo12.tistory.com&code=*********&grant_type=authorization_code
Status: 200 OK
Content-Type: text/xml
Body: In memory (78 bytes)

토큰은 body에 숨겨져 있다.

resp %>% resp_raw()

resp_raw를 통해 응답으로 받은 모든 값을 확인할 수 있다.

HTTP/1.1 200 OK
date: Fri, 27 Oct 2023 05:43:49 GMT
content-type: text/xml; charset=utf-8
content-length: 85
x-ua-compatible: IE=Edge
p3p: CP='ALL DSP COR MON LAW OUR LEG DEL'
vary: Accept-Encoding
content-encoding: gzip
server: hide
x-content-type-options: nosniff
x-frame-options: "allow-from tistory.com"
x-xss-protection: 1
strict-transport-security: max-age=0;

access_token=00000000000000aaaaaaaaaaaa1111111111111bbbbbbbbb

access token은 맨 아래에서 확인할 수 있다.


3. access token을 이용한 글 내용 요청

글 내용 요청은 티스토리 정책 문제로 인해 실패했다.

 

요청에 문제가 있진 않았기 때문에 요청 과정과 실패 시 나타나는 코드를 이 글에서 다루도록 하겠다.

 

먼저 앞서 확인한 토큰을 token1 객체에 할당한다.

token1 = '00000000000000aaaaaaaaaaaa1111111111111bbbbbbbbb'

글 내용 요청 url은 티스토리 API 공식문서 중 '글 읽기' 섹션에 설명되어 있다.

GET https://www.tistory.com/apis/post/read?
  access_token={access-token}
  &blogName={blog-name}
  &postId={post-id}

req_url_path_append 함수와 req_url_query 함수로 글 내용 요청 url을 만들고 요청을 진행한다.

req_url_path_append 함수는 '슬래쉬(/) 인수값'을 url 경로에 추가해 준다.

req_url_query 함수는 요청 url에서 물음표(?) 이후의 url 경로를 추가해 준다.(각 인수와 값은 & 로 이어진다.)

url ='https://tistory.com'

req2 <- request(url) %>% req_url_path_append("apis") %>% req_url_path_append('post') %>% req_url_path_append('read') %>% req_url_query(access_token=token1,blogName='oooo12',postId='2')
req2

아래는 req2 요청을 보여준다.

req_url_path_append 함수와 req_url_query 함수로 만들어진 url을 확인할 수 있다.

<httr2_request>
GET
https://www.tistory.com/apis/post/read?access_token=00000000000000aaaaaaaaaaaa1111111111111bbbbbbbbb&blogName=oooo12&postId=2
Body: empty

이제 이렇게 요청을 하고 응답을 확인하면 글 내용을 받을 수 있지만 에러가 뜬다.

resp2 <- req2 %>% req_perform()
Error in `req_perform()`:
! HTTP 403 Forbidden.
Backtrace:
 1. req2 %>% req_perform()
 2. httr2::req_perform(.)

브라우저를 통해 확인하면 왜 403 forbidden이 떴는지 좀 더 명확히 알 수 있다.

글 작성 후 완료를 할 때 recapture를 하는 계정은 api를 이용할 수가 없다고 한다.

 

관련 내용에 대해 참고한 블로그글은 하단에 첨부해 두었다.


git repo

https://github.com/oooo12-git/applicationWithR/tree/5cee2c8241824dd1c078216ec71aeaeca0fc0d02/Tistory-translateToEng-GithubBlog

 


참고

obfuscate() - httr2 공식문서

 

Obfuscate mildly secret information — obfuscate

This pair of functions provides a way to obfuscate mildly confidential information, like OAuth client secrets. The secret can not be revealed from your source code, but a good R programmer could still figure it out with a little effort. The main goal is to

httr2.r-lib.org

oauth_flow_auth_code() - httr2 공식문서

 

OAuth flow: authorization code — oauth_flow_auth_code

These functions implement the OAuth authorization code flow, as defined by rfc6749, Section 4.1. This is the most commonly used OAuth flow where the user is opens a page in their browser, approves the access, and then returns to R. oauth_flow_auth_code() i

httr2.r-lib.org

oauth_client() - httr2 공식문서

 

Create an OAuth client — oauth_client

An OAuth app is the combination of a client, a set of endpoints (i.e. urls where various requests should be sent), and an authentication mechanism. A client consists of at least a client_id, and also often a client_secret. You'll get these values when you

httr2.r-lib.org

티스토리 API 공식 문서

 

Authorization Code 방식 · GitBook

No results matching ""

tistory.github.io

이 블로그는 내부 정책으로 open api 사용할 수 없습니다 오류(403 forbidden) 관련 블로그 

 

이 블로그는 내부 정책으로 OPEN API 사용할 수 없습니다

티스토리에 OPEN API를 사용해 댓글을 요청했는데 다음과 같은 응답이 돌아왔습니다. API 차이는 아니고 되는 블로그도 있고 안 되는 블로그도 있고 남의 블로그에 요청해도 저런 응답이 돌아올 때

kamilake.com


req_oauth_auth_code 사용 예시

req_oauth_auth_code 사용시에는 아래와 같이 req_perform()을 해줘야 한다.

reqA <- request("https://www.tistory.com") %>%
  req_oauth_auth_code(
    client1, 
    auth_url = "https://www.tistory.com/oauth/authorize",
    auth_params = list(redirect_uri='https://oooo12.tistory.com',response_type='code') 
)
reqA %>% req_perform()

 

});