OAuth 2.0 のプロバイダにおいて、アクセストークンをどのようにシステムで保持するのかっていうところを考えたり調べたりしていました。
前提として、OAuth のトークンには以下の 2 種類の表現方法があります (RFC 6819 3.1. Tokens)
- Handle
- "opaque" トークンとも呼ばれるトークンの表現方法です。
- 認可サーバー内部のデータ実体に対する単なる参照として表現され、トークンの文字列自体に意味はありません。トークンから参照を得るためには、トークンをキーにデータ実体を探して、必要な情報 (DB 上とかにある有効期限とか) を手に入れるという形になります。
- Assertion
- トークン自体に意味を持たせるトークンの表現方法です。
- トークンから直接、必要な情報 (有効期限とか) を取得できます。
アクセストークンに焦点を合わせると、トークンを発行するのは認可サーバ、トークンを検証するのはリソースサーバです。
Handle トークン
両者が 1 つのシステムの中にあるのであるのであれば、Handle トークンを使用するのが自然でしょう。なぜなら、DB 等、認可サーバとリソースサーバ間でトークンに関わる情報を共有できるからです。
- 認可サーバがトークンを発行するとき、トークン情報を DB に保存しておく
- リソースサーバがトークンを検証するとき、保存されているトークンに関わるデータを DB から抽出する
でも、認可サーバとリソースサーバは分散され得ます。この場合、認可サーバからリソースサーバへ、トークンの検証に関する情報を通知する必要がでてきます。 また、アクセストークンは一般に数分から数時間の有効期限を持つ (RFC 6819 3.2. Access Tokenより)ことを鑑みると、アクセストークンはそれなりの量が発行されます。これを都度 DB に保存すると、きちんとパージを考えないと、アクセストークンが DB を圧迫していくのは容易に想像ができます。
RFC 7662 には、トークンを input に、そのトークンが有効なのか、有効期限はいつまでなのか、といった情報を取得する Token Introspection が仕様化されていたりします。ただ、これを使うとトークンの検証を行う度に Introspection を提供するリソースサーバへのアクセスが発生するというデメリットがあります。
Assertion トークン
こうなったらアクセストークンそのものに、検証に必要な情報を持たせたらええやん、ということで、Assertion トークンが登場します。これにより、リソースサーバはどのサーバと通信することなく、アクセストークンのみから検証が可能になります。 ただし、これらの情報が容易に第三者が読み解くことができたり、改竄されたりするのはマズいので、この Assertion トークンを実現するための方法には完全性と秘匿性が要求されます。
ここで使われるのは JSON Web Token (JWT) (RFC 7519) です。JWT は電子署名と暗号化を行った JSON をトークン化したようなもので、上記のようなことが容易に実現できます。 ただ、トークンに付与する情報が多くなるほどトークンが長くなります。また、一度発行されたトークンは完全に「独立」するので、途中で無効化する、なんてことは難しくなります。有効期限の適切なコントロールが必要になるでしょう。