Applibot Advent Calendar 2024 16日目の記事です
はじめに
みなさん普段からサードパーティ認証してますか?私はしてます。
最近は色んなサービスのログインにGoogleアカウント使ったり、Twitterアカウント使ったり出来るのでわざわざサービス毎にアカウントを作ってパスワードを覚えてなどしなくてよくて便利な時代になりました。
今回は初めて手元で認証周りを触る機会があったので、自分なりにざっくりとまとめてみました。
この記事のゴール
OpenID Connectを通してサードパーティからID Tokenを受け取って検証するところまで
OpenID Connectってなんぞや
OpenID ConnectとはOAuth2.0で定義されている認可フローに則りつつ、認証まで出来るようにした規格のことです。
詳しくはこちらを読んでください。
~ Fin. ~
……で終わるのは流石に雑すぎるのでもう少し解説します。
まずOAuth2.0というのは外部アプリケーションがあるサービス(GoogleやApple、Facebookなど)にアクセスするための認可のフローを規格化したフレームワークのことです。
通常、サービスに対してアクセスするためにはアクセストークンという文字列が必要になります。
このアクセストークンを鍵としてサービス側に渡すことで、ユーザーデータの取得を行ったり、SNS系のサービスであればソーシャルグラフの取得を行ったりなどをすることが出来るのですが、あらゆるアプリケーションがそれを無制限にできてしまうと困ったことになるので、サービスが認めた限定された外部アプリケーションのみに渡す必要があります。
このアクセストークンを渡す仕組みを規格化したものが先ほどのOAuth2.0となります。
ではその上でOpenID Connectとは何かというと、OAuth2.0に則ったフローを保ちながら認証も出来るようにした拡張規格となります。
OAuth2.0では認可の結果としてアクセストークンを取得しました。
これはこれでいいのですが、このアクセストークンには誰が認証したのかなどの情報は含まれていないため、これを振りかざして身分証明書のように使うことはできません。
そこで誰が認証したのかや署名による改ざん防止などをID Tokenというトークンに含めて、身分証明書のように使えるようにし、それをアクセストークンと一緒に発行しようと定めたのがOpenID Connectになります。
手順
こちらのフローで進めていきます。
認証リクエストを作って認可エンドポイントに投げる
まず認可エンドポイントってどこ?という話ですが、これは各サービスのOpenID Configurationに全て記載されています。(OpenID Configurationに関してはこちらを参照してください。)
例えば、Googleであれば以下のURLから確認できます。
https://accounts.google.com/.well-known/openid-configuration
ここにアクセスするとJSON形式でいくつかパラメータがありますが、その中でもauthorization_endpoint
にあたる箇所が認可エンドポイントになるため、URLは以下の通りです。
https://accounts.google.com/o/oauth2/v2/auth
さて、その上でリクエストをするためにいくつかパラメータを指定する必要があり、必須のものだけを集めると以下になります。
名前 | 説明 |
---|---|
response_type |
code と指定してください。認可の方法を表していて、OAuth2.0的には全部で4つのやり方があるのですが、OpenID Connectではそのうちの一つに乗っかっています |
client_id | クライアントIDです。各サービスの管理画面から取得してください。 |
scope | 要求するアクセス権限となります。スペースもしくはカンマ区切りで要求する権限を記していきますが、必ずopenid を含めるようにしてください。また、サービス毎に固有のscope値が存在する場合があります。 |
redirect_uri | レスポンスが返されるURIです。ここで指定するURIは全く同じものをサービス側にも登録する必要があります。 |
state | リクエスト時とレスポンスを受け取った際に共通で把握できるランダム値です。CSRF対策に使用されます。 |
そしてリクエストの例が以下となります。
https://server.example.com/authorize?
response_type=code
&client_id=s6BhdRkqt3
&redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb
&scope=openid%20profile
&state=af0ifjsldkj
認可コードを貰う
無事認証が終わるとリダイレクトされてレスポンスが帰って来ます。
成功時は以下のパラメータが上で指定したredirect_uri
の後ろにくっついてきます
名前 | 説明 |
---|---|
code | 認可コードです。次のセクションで使います。 |
state | 上で送ったstateがそのまま送られてくるはずです。 全く同じであることを検証してください。 |
認可コードをトークンエンドポイントに投げる
認可コードだけ貰ってもしょうがないので、これをID TokenとAccess Tokenに交換してもらう必要があります。
まずトークンエンドポイントに関してですが、これも認可エンドポイントと同じようにOpenID Configurationに記載されています。
同じようにGoogleを例にとるとtoken_endpoint
の値がそれにあたるため、URLは以下になります。
https://oauth2.googleapis.com/token
次にリクエストのパラメータですが、以下を指定する必要があります。
名前 | 説明 |
---|---|
grant_type | 権限付与の種別です。ここではauthorization_code を指定してください。 |
code | 上で受け取った認可コードを指定してください。 |
redirect_uri | 認可時で指定したものと同じものを指定してください。 |
リクエストの例は以下となります
POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA
&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb
ID TokenとAccess Tokenを貰う
レスポンスとして下記のパラメータが返ってきます
名前 | 説明 |
---|---|
access_token | アクセストークン |
token_type | トークンの種別です。ここでは必ずBearer が返ってきます。 |
id_token | ID トークン |
ID Tokenを検証する
最後は返ってきたID Tokenが本物なのかを検証する必要があります。
検証するにあたってID Tokenの構成について知っておく必要があります。
ID TokenはJWT(JSON Web Token)形式の文字列で、ドットで区切られたヘッダ、ペイロード、署名の3つの部分から構成されています。
特にペイロードに関しては以下のパラメータを含んでおり、これらを元に検証を行います。
名前 | 説明 |
---|---|
iss | Issuerの識別子 |
sub | ユーザーの識別子 |
aud | トークンの発行対象の識別子 |
exp | トークンの有効期限 |
iat | 発行日時 |
具体的な手順に関してはそのまま引用する形になってしまうのでこちらを参照してください。
まとめ
かなり駆け足のまとめになってしまい恐縮ですが、以上が一連の流れになります。
本当は軽く実装まで書けるとよかったのですが、この記事を書き終わったのがかなりギリギリで体力の限界でした。
もっと早めから記事を書き始めるべきだったかもしれない……
明日は@yuucuさんになります!