Edited at

アプリで「ログインしっぱなし」はどのように実現されているか?

このツイートを見て、「アプリで再ログインを頻繁要求されるってユーザビリティ良くないな。」と思ったのですが、普段裏側の仕組みは意識していなかったりテックリードの方に任せきりだったりしていたので、これを気に調べてみました。

この記事は「アプリでログインしっぱなしは、どのように実現されるの?」という疑問と調べた結果を共有するために書いていきます。

間違いや「もっとこんな仕組みが使われてるよ!」等のツッコミがあれば、どしどし貰えると助かります!


疑問1. アクセストークンという仕組みとは?


「なぜアクセストークンという概念が必要なのか?」

モバイルアプリでユーザー認証をしつつAPI通信をしようと思うと、通信のたびにID/PassをAPIに渡す必要があります。それを実現するためには、ローカルにクレデンシャルを保存する必要があります。 しかし、これはセキュアではないという問題があります。

なので、アクセストークンという「これは認証済みのユーザによって認可されたリクエストだ」ということを保証するトークンを使った仕組みを利用します。

OAuth2.0の備忘録


「アクセストークンを用いてどのようにサーバーとやりとりしているのか?」

モバイルアプリのユーザ認証情報についてまとめてみたを読んで理解しました。

+--------+                                +--------+

| | | |
| |----(1) Credential ------------>| |
| | | |
| |<---(2) Access Token -----------| |
| | | |
| Client | | Server |
| | | |
| |----(3) API Call with Token --->| |
| | | |
| |<---(4) API Response -----------| |
| | | |
+--------+ +--------+


  1. Credentialをサーバーに渡す

  2. Access Tokenをクライアントに返す。

  3. Requestする時にAccessTokenをつける

  4. Access Tokenの検証をして、APIレスポンスを返す。

という形でアクセストークンを伴ったAPI callをしています。


疑問2. アクセストークンの有効期限が切れたら再認証必要になってしまうのでは?

ここで気になるのが、アクセストークンの有効期限」の事で、それを過ぎると結局は再認証が必要になってしまうのでは?と思ってしまいます。以下の記事が分かりやすかったのですが、 この問題は「リフレッシュトークン」を用いる事で解決します。

OAuth 2.0 全フローの図解と動画

仕組みとしては、アクセストークンを取得した時にリフレッシュトークンも一緒に返してもらい、このリフレッシュトークンをトークンエンドポイントに渡す事で、新しいアクセストークンが帰ってきます。(リフレッシュできる)

こうしてアクセストークンをリフレッシュして通信をし続ける事で、ログインしっぱなしを維持することができるようです。


疑問3. リフレッシュトークンに有効期限があったら、同じ問題が続くのでは?

リフレッシュトークンにも有効期限はあります。

ただし、アクセストークンの有効期限が非常に短いのに比べて、リフレッシュトークンの有効期限は長いです。

こちらのGoogleのOAuth2.0 Overviewのページを見ると、 「6ヶ月リフレッシュトークンが使われなければ失効する」 と書いてあるので、リフレッシュトークンの有効期限は半年等かなり長いので、十分にユーザビリティを損なわない体験を与える事ができます。

6ヶ月の間に一度も使われなければ、リフレッシュトークンは機能しなくなる。というニュアンスなので、こちらは一回でも使えば同じものを使い続けられるように思います。

15分とかだと、バックグラウンドに入ってるうちに有効期限が切れてしまってリフレッシュし損ねるみたいなケースが想定できますが、6ヶ月もあれば期限が切れるまでに十分な期間があるので、それまでにまたリフレッシュトークンを更新できていれば、ずっとログインしているように振る舞う事が出来ますね。


疑問4. そのリフレッシュトークンはどう管理するの?

iOSの場合は、ここで keychain が登場するように思います。ただ、このあたりに関してはあまりネットから知見を得られなかった(ググりかたが悪いかも)ので、教えていただけると助かります。

ただ注意点として


  • keychainItemは明示的に削除処理を入れないと、アプリ削除しても残る

  • 複数デバイス間の同期をfalseにしておく必要がある

などがあります。

リフレッシュトークンは、同一アカウントでも基本的に端末ごとに違うのが望ましいとのことです。

キーチェーンの挙動はiosのキーチェーンについてという記事がわかりやすかったです。


疑問5. リフレッシュトークンは何度でも使えるの?

teratailの記事が分かり易かったのですが、RFC6749では以下のように言及しています。


The authorization server MAY issue a new refresh token, in which case the

client MUST discard the old refresh token and replace it with the new refresh token.


認可サーバーは一度使われた リフレッシュトークンを無効化してもよい

その場合、クライアントは一度使われたリフレッシュトークンを破棄して、新しいトークンに置換しなければならない

この仕様通りに考えると、毎回リフレッシュトークンを生成する認可サーバーの場合は、クライアントは毎回新しいリフレッシュトークンを受け取って古いのと置換しながら使うのが正しいようです。


まとめ

以下がここまでの振り返りとなります。


  • アプリでID/Passを保存せずにセキュアにやりとりするための仕組みとしてアクセストークンという概念がある。

  • アクセストークンの有効期限は短いのでリフレッシュトークンという有効期限の長いトークンを合わせて発行し、リフレッシュトークンを使う事で新しいアクセストークンを得られる。 この仕組みでログイン維持の振る舞いが出来る。

  • リフレッシュトークンはGoogleだと6ヶ月の生存期間を持つ

  • トークンはkeychainに保存するのが良いっぽい

  • 古いリフレッシュトークンはクライアントで破棄し、毎回新しいものと置換する

セキュアかつ良いユーザービリティを提供するために、これからも色々と勉強していけたらと思います!

ここまでお読みいただきありがとうございました!