Salesforce の OAuth2 トークン。有効期限の仕様が独特だったので、調べた内容の記録です。「Web アプリケーションインテグレーションの OAuth 2.0 Web サーバフロー」で取得した OAuth2 トークンについて、調べた内容をまとめます。
Salesforce は、リフレッシュトークン/アクセストークンを返す際、有効期限 (expred_in) をレスポンスに含めません。実際には有効期限が存在し、
- アクセストークンは、ユーザセッションが有効である限り、有効
- リフレッシュトークンは、接続アプリケーションの設定に従う
となっています。ユーザセッションは Web アプリのログインセッションと同じように、それを使用してアクセスするたびに、有効期限が伸びます。つまり Salesforce のアクセストークンは、有効期限内に使用し続ける限り、その有効期限が伸び続けます。通常、OAuth2 アクセストークンの有効期限は伸びないので、この仕様は独特です。
ユーザセッションが有効な間、リフレッシュトークンから何度アクセストークンを取得しても、同じアクセストークンが返されます。リフレッシュトークンからアクセストークンを取得しても、ユーザセッションの期限は延長されます。
ユーザセッションが切れたあと、アクセストークンを使用すると、Session expired or invalid のエラーとなります。ユーザセッションが切れたあと、リフレッシュトークンからアクセストークンを再取得すると、これまでと同じアクセストークンが返されます。ユーザセッションも新たに作成されず、これまでのものの有効期限が更新されます。つまりリフレッシュトークンおよびアクセストークンとユーザセッションは、1対1に対応していると考えられます。
ユーザセッションの有効期限は、接続アプリケーションのタイムアウト設定によって決まります。接続アプリケーションのタイムアウト設定が「なし」の場合、ユーザプロファイルのタイムアウト設定によって決まります。(ユーザプロファイルのタイムアウト設定が未設定の場合、組織のタイムアウト設定によって決まるようですが、それは未確認です)
https://help.salesforce.com/articleView?id=connected_app_manage_session_policies.htm&type=5
リフレッシュトークンの有効期限も、接続アプリケーションの設定によって決まります。この設定が "Immediately expire refresh token" になっていると、リフレッシュトークンが発行されても、まったく使えないものとなります。注意が必要です。
なお認可からやり直すと、別のリフレッシュトークン/アクセストークンが返され、ユーザセッションも別のものとなります。これには注意が必要で、Salesforce には「1ユーザ・1接続アプリケーションあたり、トークン数 5 まで」という制限があるようです。
https://help.salesforce.com/articleView?id=remoteaccess_oauth_flows.htm&type=5
ただ制限はありそうだが、厳密でもなさそうです。試したところ、6 まで問題なくいけて、7 まで行ったときに、1 つアクセストークン破棄され、しばらくすると更に 2 つ破棄されて、4 だけ残る状態になりました。2 回試して、同じような感じです。古い順には破棄されるようです。
これで破棄されたものについては、リフレッシュトークンも破棄されています。リフレッシュトークンからアクセストークンを再取得しようとしても、"expired access/refresh token" のエラーになります。
不思議なことに、この状態になっても、Salesforce の "User Session Information" には残り続けます。かつ有効期限も伸びる。なので、「セッションが有効⇒トークンが有効」というわけでも無さそうです。逆「トークンが有効⇒セッションが有効」は言えると思います。いずれにせよ、「1ユーザ・1接続アプリケーション単位でトークン数に制限がある」ということは意識したほうが良さそうです。
以下、まとめです。
- アクセストークンの有効期限はユーザセッションの有効期限に従う
- アクセストークンを使うたびに、ユーザセッションの有効期限も伸びる
- アクセス/リフレッシュトークンの有効期限は接続アプリケーションの設定に従う
- ユーザセッションが切れた後(アクセストークンが無効になった後)も、リフレッシュトークンからアクセストークンを取得可能
- 「1ユーザ・1接続アプリケーションあたり、トークン数 5 まで」という制約がある。複数種類 Salesforce への API アクセスがあるなら、接続アプリケーションを分ける等の工夫が必要。