📚

IDトークンVSアクセストークン

2022/06/06に公開

https://auth0.com/blog/id-token-access-token-what-is-the-difference/
をdeeplに突っ込んだもの
後で、綺麗に整形できたらする

authorization 認可

authenticated. 認証

"このAPIコールを保護するためにトークンを使用しましょう。IDトークンとアクセストークンのどちらを使うべきですか?🤔 IDトークンの方がよさそうですね。結局のところ、ユーザーが誰なのか分かれば、より良い認可の判断ができるでしょ?"

同じような議論をしたことがありますか?直感で選んだ方が良さそうですが、直感的に見えることが必ずしも正しいとは限りません。IDトークンやアクセストークンの場合、明確な目的があるので、それに基づいて使うべきでしょう。間違ったトークンを使うと、ソリューションが安全でなくなる可能性があります。

"結局、何が変わるの?ただのトークンです。好きなように使えばいい。最悪何が起こるかわかりませんよ?"

この2種類のトークンを詳しく見て、認証と認可のプロセスにおけるトークンの役割をよりよく理解しましょう。

同じトピックに関するビデオもご覧ください。

IDトークンは、ユーザーが認証されたことを証明するアーティファクトである。GoogleやFacebook、そしてもちろんAuth0など、多くのIDプロバイダで使われている認証のオープンスタンダード、OpenID Connect (OIDC)によって導入されました。OpenID Connectの詳細については、こちらのドキュメントをご覧ください。OIDCが解決したい問題をざっと見てみましょう。

ここでは、ユーザーがブラウザでOpenIDプロバイダに対して認証を行い、Webアプリケーションにアクセスできるようにします。OpenID Connectに基づくその認証プロセスの結果がIDトークンであり、このIDトークンが、ユーザが認証されたことの証明としてアプリケーションに渡されるのです。

これで、IDトークンとは何か、つまりユーザーの認証の証明という、非常に基本的な考え方ができました。他の詳細も見てみましょう。

IDトークンはJSON Web Token(JWT)としてエンコードされます。JWTは標準的なフォーマットで、アプリケーションはその内容を簡単に確認でき、それが期待される発行者からのものであり、他の誰にも変更されていないことを確認できます。JWTについてもっと知りたい方は、「JWTハンドブック」をご覧ください。

簡単に言うと、IDトークンの例は以下のようなものです。

もちろん、これは人間の目には読めませんので、JWTがどんな内容を保持しているかを見るにはデコードする必要があります。ちなみに、IDトークンは暗号化されているわけではなく、Base 64でエンコードされているだけです。デコードするために多くの利用可能なライブラリのうちの1つを使うこともできますし、jwt.ioデバッガーを使って自分で調べることもできます。

詳細は省きますが、上記のIDトークンが持っている関連情報は以下のようなものです。

これらのJSONプロパティはクレームと呼ばれ、ユーザおよびトークン自身に関する宣言です。ユーザーに関するクレームは、そのユーザーのアイデンティティを定義します。

実は、OpenID Connectの仕様では、IDトークンがユーザのクレームを持つことは要求されていません。最小限の構造では、ID トークンはユーザに関するデータを持たず、認証操作に関する情報のみを持ちます。

重要なクレームの一つは、audクレームです。このクレームはトークンのオーディエンス、つまりトークンの最終的な受け手となるウェブ・アプリケーションを定義するものです。ID トークンの場合、その値はトークンを消費するアプリケーションのクライアント ID です。

オーディエンスクレームに関するこの小さな詳細は、後で正しい使い方を理解するために役立ちますので覚えておいてください。

IDトークンには、メールアドレス、写真、誕生日など、ユーザーに関する追加情報が含まれている場合があります。

最後に、おそらく最も重要なことは、IDトークンは発行者の秘密鍵で署名されていることです。これにより、トークンの出所を保証し、改竄されていないことを保証します。発行者の公開鍵を使って、これらのことを確認することができます。

カッコイイ! これでIDトークンが何であるかはわかりました。でも、IDトークンを使って何ができるのでしょうか?

まず、ユーザが信頼できる団体 (OpenID プロバイダ) によって認証されたことを示すので、その身元に関する主張を信頼することができます。

また、IDトークンに含まれるユーザーに関する情報を使って、アプリケーションはユーザーの体験をパーソナライズすることができます。例えば、UI上にユーザーの名前を表示したり、誕生日に「おめでとうございます」というメッセージを表示したりすることができます。面白いのは、追加のリクエストをする必要がないため、アプリケーションのパフォーマンスが少し向上するかもしれない点です。

IDトークンが何であるかが分かったところで、アクセストークンが何であるかを理解しましょう。

まず、アクセストークンが適合するシナリオを描いてみましょう。

上の図では、クライアントアプリケーションは、不正なアクセスから保護されているリソース、例えばAPIなどにアクセスすることを望んでいます。その図の他の2つの要素は、リソースの所有者であるユーザーと、認可サーバーである。このシナリオでは、アクセストークンは、クライアントアプリケーションがユーザーのリソースにアクセスするためのアーティファクトである。これは、ユーザーの認証に成功し、同意を得た後に認可サーバーから発行されます。

OAuth 2 のコンテキストでは、アクセストークンは、クライアントアプリケーションがユーザーに代わって特定のリソースにアクセスし、特定のアクションを実行することを可能にします。これは、いわゆる委任型認証のシナリオです。ユーザーは、自分に代わってリソースにアクセスするようクライアントアプリケーションに委任します。つまり、たとえば、LinkedInアプリがTwitterのAPIにアクセスし、両方のソーシャルプラットフォームにクロスポストすることを許可することができます。ただし、LinkedInに許可するのは、Twitterに投稿を公開することだけであることに留意してください。LinkedInには、投稿を削除したり、プロフィールのデータを変更したり、その他のことをする権限はありません。この制限は、委譲された権限のシナリオにおいて非常に重要であり、スコープによって実現されます。スコープとは、サードパーティのアプリケーションに対して、特定の操作のみを許可する仕組みです。

もちろん、アクセストークンを受け取るAPIは、それが実際に信頼する認可サーバーが発行した有効なトークンであることを確認し、それに関連する情報に基づいて認可の判断を下す必要があります。つまり、APIはクライアントアプリケーションがリソースに対して希望する操作を行うことを認可するために、何らかの方法でそのトークンを使用する必要があるのです。

認可を決定するためにアクセストークンをどのように使うべきかは、システム全体のアーキテクチャやトークンの形式など、多くの要因に依存する。例えば、アクセストークンは、APIが認可サーバーと共有するデータベースから必要な情報を取得するためのキーであったり、必要な情報をエンコードした形で直接格納したりすることが可能です。つまり、認可を決定するために必要な情報をどのように取得するかを理解することは、認可サーバとリソースサーバ、つまりAPIとの間の合意事項であることを意味します。

OAuth 2 のコア仕様には、アクセストークンの形式について何も書かれていません。どのような形式の文字列であってもかまいません。アクセストークンによく使われる形式はJWTであり、標準的な構造が用意されています。しかし、アクセストークンがその形式であるべきというわけではありません。

さてさて。これで、IDトークンとアクセストークンが何なのかがわかりましたね。🎉これで、間違いを恐れることなく、それらを使う準備ができました。でも、ちょっと待ってください。納得していないようですね。🤔 もしかしたら、他の情報が必要なのかもしれませんね。わかりました。では、これらのトークンが何に適さないか見てみましょう。

IDトークンを使って開発者が犯しがちな失敗のひとつに、IDトークンを使ってAPIを呼び出すというものがあります。

前述したように、IDトークンはユーザが認証されたことを証明するものです。ファーストパーティシナリオ、つまりクライアントとAPIの両方があなたによってコントロールされているシナリオでは、IDトークンは認可の決定をするのに適していると判断するかもしれません:あなたが知る必要があるのはユーザーIDだけかもしれません。

しかし、このシナリオでも、クライアントとAPIで構成されるアプリケーションのセキュリティは危険にさらされるかもしれません。実際、IDトークンをクライアントとAPIのチャネルに結びつける仕組みはありません。もし攻撃者があなたのIDトークンを盗むことに成功したら、彼らはそれを使って正規のクライアントのようにAPIを呼び出すことができる。

一方、アクセストークンについては、送信者制約と総称される一連のテクニックがあり、アクセストークンを特定の送信者に結びつけることができます。これにより、たとえ攻撃者がアクセストークンを盗んだとしても、トークンは最初に要求したクライアントにバインドされているので、それを使ってAPIにアクセスできないことが保証される。

サードパーティークライアントがあなたのAPIを呼び出したいという委任認証シナリオでは、APIを呼び出すのにIDトークンを使ってはならない。クライアントとバインドする仕組みがないことに加え、これを行わない理由がいくつかあります。

そもそもあなたのAPIが認証トークンとしてIDトークンを受け入れるなら、オーディエンスクレームが示す意図する受信者を無視することになる。その主張は、リソースサーバ(つまりAPI)向けではなく、あなたのクライアントアプリケーション向けであることを意味している。

あなたはこれを単なる形式的なものと思うかもしれませんが、ここにはセキュリティ上の意味があります。

まず第一に、他の検証チェックの中でも、APIはそのために使われていないトークンを受け入れてはならない。もし受け取れば、そのセキュリティは危険にさらされる。実際、もしAPIがトークンの用途を気にしないなら、クライアントアプリケーションから盗まれたIDトークンを使ってAPIにアクセスすることができる。もちろん、オーディエンスチェックは不正なアクセスを防ぐためにAPIが行うべきチェックの一つに過ぎない。

さらに、あなたのIDトークンはスコープを付与されていないでしょう(これも痛いところですね)。先に述べたように、スコープによって、ユーザーはクライアントアプリケーションが自分の代わりに行える操作を制限することができます。これらのスコープはアクセストークンに関連付けられ、クライアントアプリケーションが何をできて何をできないかをAPIが把握できるようにします。クライアントアプリケーションがIDトークンを使ってAPIを呼び出す場合、この機能を無視することになり、ユーザーが許可していない操作をアプリケーションに実行させる可能性があります。

アクセストークン側では、あるリソースへのアクセス、例えばAPIの呼び出しが許可されていることを示すために考え出されたものです。

クライアントアプリケーションは、このためだけにそれを使用すべきです。言い換えれば、アクセストークンはクライアントアプリケーションで検査されるべきではありません。アクセストークンはリソースサーバーのためのものであり、クライアントアプリケーションはアクセストークンを不透明な文字列、つまり特定の意味を持たない文字列として扱わなければなりません。たとえアクセストークンの形式を知っていたとしても、クライアントアプリケーションでその内容を解釈しようとするべきではありません。アクセストークンの形式は認可サーバーとリソースサーバーの間の取り決めであり、 クライアントアプリケーションが介入するべきではありません。ある日突然アクセストークンの形式が変更されたらどうなるか考えてみてください。もしあなたのクライアントコードがそのアクセストークンを検査していたら、予期せず壊れてしまうでしょう。

ID とアクセストークンの使用に関する混乱は非常に一般的で、その違いを理解するのは難しいかもしれません。それは、OAuthやOpenID Connectの仕様で定義されている、それぞれのアーティファクトの異なる目的を明確に理解していないことに起因しているのかもしれません。また、これらのアーティファクトが本来どのような場面で使われるものなのかを理解することも、使用上の混乱を防ぐために重要な役割を担っています。とはいえ、これでこのトピックが少しはクリアになったかと思います。

ここで、IDやアクセストークンを使ってできること、できないことについて学んだことを簡単にまとめます。

IDトークンやアクセストークンを実際に使ってみたい方は、Auth0の無料アカウントにサインアップして、お好みのプログラミング言語やフレームワークを使って、数分でアプリケーションに認証・認可を追加することができます。

Discussion