Authentication Code 방식 인증 프로세스
티스토리 API를 사용하려면 Authentication Code 방식을 통해 내가 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
참고
obfuscate() - httr2 공식문서
oauth_flow_auth_code() - httr2 공식문서
oauth_client() - httr2 공식문서
티스토리 API 공식 문서
이 블로그는 내부 정책으로 open api 사용할 수 없습니다 오류(403 forbidden) 관련 블로그
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()