EvernoteAPIを利用するためのサードパーティ用アクセストークンをOAuth認証で取得する

# 2021/08追記

本ブログで記載の方法よりもっと簡単にトークンが取得できるようになっていました。

- [Evernote APIを使用するためのPersonal OAuth Tokenが公式のWebフォームで取得できるようになっていました | DevelopersIO](https://dev.classmethod.jp/articles/personal-oauth-token-for-using-evernote-api-was-now-available-to-get-in-official-form/)

# はじめに

ノートテイキングアプリ[Evernote](https://evernote.com/)のサードパーティアプリを開発するにあたり、アプリで利用するアクセストークンをOAuth認証により取得する方法を確立させたのでメモ。

まず、Evernoteのサードパーティアプリ利用時のユーザー認可の方法には以下の二通りの方法がある。[^1]

1. EvernoteとサードパーティアプリのOAuth認証により取得した**Cookieをクライアント側で保存**し、以降サードパーティアプリ利用時の認可に利用
2. EvernoteとサードパーティアプリのOAuth認証により取得した**アクセストークンをサーバー側で保存**し、以降サードパーティアプリ利用時の認可に利用

1は**不特定多数**のユーザーが**各ユーザー自身のEvernoteアカウント**上のリソースをサードパーティアプリから利用することを想定した方法である。
2は**管理者や特定の少数**のユーザーが**特定のEvernoteアカウント**上のリソースをサードパーティアプリから利用することを想定した方法である。

本記事では**2**の利用方法を実現させるために、OAuth認証によりアクセストークンを取得する方法を紹介する。

# 手順

## API Key取得

Evernoteのサードパーティアプリごとに必要となるAPI KeyをEvernote開発者用サイトを通じて取得する。

### API Keyリクエスト

http://dev.evernote.com/doc/ にアクセスし、画面内の「GET AN API KEY」をクリック。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/258416/f371a520-a389-b5cf-c3df-05cd42a07779.png)

画面上部に下記フォームが表示されるので、入力欄に適当に入力して、「Full Access」を選択し、「I agree 〜」にチェックを入れて、「Request Key」をクリック。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/258416/f9bf1ffd-46b5-0934-3468-c055201ca6c8.png)

画面が遷移し「Consumer Key」と「Consumer Secret」が表示されるので控えておく。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/258416/3d04d87f-6fc8-28e1-4148-021de771d76d.png)

ここまでで取得したAPIキーはEvernoteのサンドボックス環境（Sandbox development server）では利用できるが、実際にコンシューマーが利用するEvernoteのプロダクション環境（production servers）で利用するためには次手順の**API Keyアクティベート**を行う必要がある。

### API Keyアクティベート

http://dev.evernote.com/support/glossary.php#k にアクセスし、「this form」をクリック。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/258416/71205c54-cb02-c931-69d3-68caaace14b3.png)

画面内に下記フォームが表示されるので先程控えた情報と合わせて入力し、「Submit」をクリック。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/258416/79cfc32e-d85f-6cad-5a39-b3b2bd9cf3b7.png)

Evernote開発者サポートから下記のようなメールが届いたらサードパーティアプリのAPI Keyのアクティベートは完了（アクティベートをリクエストしてから完了するまでには数日要する）。

```
差出人: devsupport@evernote.com
送信日時: 2018年7月21日 2:37:03 (UTC+09:00) 大阪、札幌、東京
宛先: XXXXXXXX
件名: Re: xxxxxxxx
 
##- Please type your reply above this line -##

xxxxxxxx (Evernote Developer Relations)
Jul 20, 10:37 AM PDT
Hello xxxxxxxx,
 
 We have activated your API key (xxxxxxx) on our production service. If you have questions, please proceed to Stack Overflow and join the community discussion there: http://stackoverflow.com/questions/tagged/evernote
 
 Thank you for building with our API,
 
 Evernote Developer Relations

xxxxxxxx
Jul 19, 1:10 AM PDT
xxxxxxxx

[XXXXXX-XXXX]
```

## アクセストークン取得

[Evernote開発者用ドキュメント](http://dev.evernote.com/doc/)では各開発言語向けのSDKが取り揃えられている。今回はそのうちの[Python2向けのSDK](https://github.com/evernote/evernote-sdk-python)を利用してアクセストークン取得を行う。[^2]

また、Python2向けSDKではサンプルとして「client」、「django」、「pyramid」を利用した３種類のOAuth実装用のコードが含まれているが、今回は[Djangoを利用した方法](https://github.com/evernote/evernote-sdk-python/#getting-started---django-with-oauth)をもとにしたアクセストークン取得の手順を記載する。

### 前提

```shell
$ python -V
Python 2.7.10
```

### SDKをローカル環境にgit clone

```shell
$ git clone https://github.com/evernote/evernote-sdk-python.git
```

### 各種モジュールをpip install

```shell
$ cd evernote-sdk-python/sample/django
$ pip install -r requirements.txt
```

### views.py編集

`evernote-sdk-python/sample/django/oauth`内の`views.py`を下記のように編集する。（コード内①②③の箇所）

```views.py
from evernote.api.client import EvernoteClient

from django.core.urlresolvers import reverse
from django.shortcuts import render_to_response
from django.shortcuts import redirect
# rename config.py.template to config.py and paste your credentials. 
from config import EN_CONSUMER_KEY, EN_CONSUMER_SECRET

def get_evernote_client(token=None):
    if token:
        return EvernoteClient(token=token, sandbox=True)
    else:
        return EvernoteClient(
            consumer_key=EN_CONSUMER_KEY,
            consumer_secret=EN_CONSUMER_SECRET,
            sandbox=False #・・・① True => False
        )


def index(request):
    return render_to_response('oauth/index.html')


def auth(request):
    client = get_evernote_client()
    callbackUrl = 'http://%s%s' % (
        request.get_host(), reverse('evernote_callback'))
    request_token = client.get_request_token(callbackUrl)

    # Save the request token information for later
    request.session['oauth_token'] = request_token['oauth_token']
    request.session['oauth_token_secret'] = request_token['oauth_token_secret']

    # Redirect the user to the Evernote authorization URL
    return redirect(client.get_authorize_url(request_token))


def callback(request):
    try:
        client = get_evernote_client()
        access_token = client.get_access_token( #・・・② client.get_access_token( => access_token = client.get_access_token(
            request.session['oauth_token'],
            request.session['oauth_token_secret'],
            request.GET.get('oauth_verifier', '')
        )
    except KeyError:
        return redirect('/')
    print('\n--*-- Access Token --*--\n' + access_token + '\n') #・・・③
    note_store = client.get_note_store()
    notebooks = note_store.listNotebooks()

    return render_to_response('oauth/callback.html', {'notebooks': notebooks})


def reset(request):
    return redirect('/')
```

### config.py作成

`evernote-sdk-python/sample/django/oauth`内の`config.py.template`を`config.py`にリネームして、API Key取得手順で取得した「consumer key」と「consumer secret」を記載する。

```config.py
EN_CONSUMER_KEY = 'your consumer key'
EN_CONSUMER_SECRET = 'your consumer secret'
```

### OAuth認証実施、アクセストークン取得

`evernote-sdk-python/sample/django/`内の`manage.py`を実行してローカルでサーバーを起動。

```shell
$ python manage.py runserver
```

ブラウザから`http://127.0.0.1:8000/`にアクセス。
表示される画面内の「Click here」をクリック。
![img.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/258416/a923fcbd-f947-7915-bf1f-4609cc7b3eb4.png)

Evernoteのログイン画面が表示されるので、サードパーティアプリにアクセスさせたいEvernoteアカウントでログイン。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/258416/584e0a79-910b-155c-edda-6679428b01f0.png)

ログインをすると下記の承認画面に遷移するので、承認の有効期間を１日間、１週間、30日間、1年間から選択し、「承認する」をクリック。
![img.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/258416/4ef4cbc6-4b28-19ca-9019-123f397f27f5.png)

ログインしたEvernoteアカウント内のノートブック一覧が画面に表示されたらサードパーティアプリのOAuth認証完了である。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/258416/790e8aa2-23ec-24c2-95e3-08d6b1346ab0.png)

`manage.py`を実行したターミナル上で`--*-- Access Token --*--`の下にアクセストークンが表示される。
これでEvernoteのサードパーティ用のアクセストークンを取得することができた。

```
--*-- Access Token --*--
＜S=xxx:U=xxxxxxx:E=xxxxxxxxxxx:C=xxxxxxxxxxx:P=xxx:A=xxxxx:V=x:H=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx＞
```

~~次回、今回の手順で取得したアクセストークンを利用したサードパーティアプリの実装の一例を投稿予定。~~
→[AWS Lambda + API Gateway + PythonでEvernoteのRestful APIを実装する](https://qiita.com/r-wakatsuki/items/57b19375f98235d82409)

### 補足

すでに同じEvernoteアカウント、同じサードパーティアプリ(＝API Key)で承認済みの場合は下記ような承認画面が表示されて再承認を求められる。再承認をすると新しいアクセストークンが取得でき、再承認前のアクセストークンと同様に利用することができる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/258416/f51acdf0-e392-ea56-d091-9f8e17d5a715.png)

また、Evernoteの[サードパーティ製アプリケーション](https://evernote.com/intl/jp/privacy/third-party-apps)にある通り、自分のEvernoteアカウントのサードパーティアプリごとの承認状況は[アプリケーション](https://www.evernote.com/AuthorizedServices.action)ページで管理できる。承認の取り消しを行うと、その承認時に取得したアクセストークンは無効となり利用できなくなる。

# 参考

- https://myenigma.hatenablog.com/entry/2016/01/23/090212
- https://stackoverflow.com/questions/46260328/evernote-sdk-how-can-i-get-the-permission-to-access-all-notebooks-metadata

[^1]: 以前まではわざわざOAuth認証を利用しなくても[Developer Tokens](https://dev.evernote.com/doc/articles/dev_tokens.php)にある通り開発者用トークンというアクセストークンを利用する方法もあったようだが、現在はサンドボックス環境向けのみ取得可能で、プロダクション環境向けは取得できなくなっている。

[^2]: 残念なことに公式のPython向けSDKはPython2のみでPython3は未提供の様子（[Python3向けSDKのページ](https://github.com/evernote/evernote-sdk-python3)もあるにはあるが、作成中の様子で2017年9月から更新がされていないので公式は多分やる気なし）。ただしPython3向けのpypiパッケージ[evernote3](https://pypi.org/project/evernote3/)は利用可能。