Auth0の認証トークンの保存方法がよくわかっていなかった
個人開発をする時にログイン周りをいつもFirebase Authenticationを使用していたため、他のIDaaSを使ってみたくなり、今回はAuth0を使ってみることにしました。
Auth0を使用していくうちに疑問が浮かんだのでメモのためにまとめておきます。
疑問
- 許可されたAPIを叩く際にAuthorization headerで付与するトークンはどこに保持しておくのか
- 一度ログインしたら一定期間はクライアント側に保存しておく?
- 一回一回、認可サーバーに問い合わせてアクセストークンを取得してからサーバーにいく?
この辺りがよくわからなくなってしまったので調べてみることにしました。
環境
- webを想定
- auth0-reactというパッケージを使用
- これはauth0-spa-jsをhooksのような実装にラップしたもので実際の実装はほとんどがこちらにある
また実装を追いやすいように専用のsampleアプリを作りました。 (https://github.com/haga0531/auth0-react-sample)
認証の流れ
Reactアプリ側でログインボタンを押す
auth0-react
のloginWithRedirect
を呼ぶようにしています。
<button onClick={() => loginWithRedirect()}>Log in</button>
loginWithRedirect
の実装を見てます。
/** * ```js * await loginWithRedirect(options); * ``` * * Performs a redirect to `/authorize` using the parameters * provided as arguments. Random and secure `state` and `nonce` * parameters will be auto-generated. */ loginWithRedirect: (options?: RedirectLoginOptions) => Promise<void>;
ここで行っていることとしては以下のようです。
- パラメータをセットして、 https://YOUR_DOMAIN/authorizeに移動
- エンドユーザーをhttps://YOUR_DOMAIN/loginの画面にリダイレクト
またこの時のURLは以下のようになっています。
https://YOUR_DOMAIN/login?state=g6Fo2SBjNTRyanlVa3ZqeHN4d1htTnh&...
ドキュメントにも詳しく書かれていました。
ログインができ、isAuthenticated
がtrueになる
sampleアプリの実装では以下のようになっているため、yarn start
を実行してlocalhostにアクセスすると、Log outボタンが表示されています。
import React from "react"; import "./App.css"; import { useAuth0 } from "@auth0/auth0-react"; function App() { const { isAuthenticated, loginWithRedirect, logout } = useAuth0(); return ( <div className="App"> <header className="App-header"> {!isAuthenticated ? ( <button onClick={() => loginWithRedirect()}>Log in</button> ) : ( <button onClick={() => logout()}>Log out</button> )} </header> </div> ); } export default App;
疑問: 許可されたAPIを叩く際にAuthorization headerで付与するトークンはどこに保持しておくのか
ここで当初の疑問を思い出します。
許可されたAPIを叩く際にAuthorization headerで付与するトークンはどこに保持しておくのか
ドキュメントによるとAuth0のデフォルトの実装だとブラウザのインメモリに保存されるらしいです。
Use Auth0 SPA SDK whose default storage option is in-memory storage to leverage both Web Workers and JavaScript closures depending on the type of token.
なるほど、クライアントに保存しておくらしい。
しかし、この記述の下にこう書いてありました。
The in-memory method for browser storage does not provide persistence across page refreshes and browser tabs.
なるほど。インメモリだとリロードしたりブラウザのタブを変えたりしたら、ログイン状態が保持されないのか。
試してみます。
あれ、リロードしたもちょっとガチャってなるだけど、ログイン状態に戻った(isAuthenticated
がtrueに)。。
さらに疑問が生まれます。
Auth0のデフォルトの実装(tokenはブラウザのインメモリに保存される)のはずだけどリロードしたりブラウザ変えてもログイン状態を保持しているのはなぜだ、、
こういう時のnetworkタブということでこちらをを見てみることにしました。
見慣れないパラメータ、prompt=none
、response_mode=web_message
を発見します。
こちらを調べてみるとAuth0のドキュメントがヒットしました。
どうやらAuth0ではSilent Authentication
という仕組みでこのパラメータを使っているようです。
また以下のような記述がありました。
By default,
auth0-spa-js
uses theprompt=none
andresponse_mode=web_message
flow for silent auth, which depends on the user's Auth0 session. https://github.com/auth0/auth0-spa-js/blob/master/FAQ.md#using-multi-factor-authentication-mfa
response_mode=web_message
についても調べてみました。
こちらの記事がとてもわかりやすく書かれていました。
また例を出すが、Auth0 の SPA 用ライブラリ auth0/auth0-spa-js は Silent Authentication を使っている。初回表示時に prompt=none をつけた /authorize リクエストを裏で実行して、セッションが残っていればアプリケーションを自動的にログイン済み状態にしてくれる。
なるほど。In-memory方式で保存されているがリロードをしてもログイン状態を保持するという実装になっているのか。
なんとなく理解することができました。
Silent Authentication
にも欠点があることが述べられていますが、当初の疑問は解決された気がするのでここまでにします。
参照
- 一番分かりやすい OAuth の説明 - Qiita
- GitHub - auth0/auth0-react: Auth0 SDK for React Single Page Applications (SPA)
- 認証用トークン保存先の第4選択肢としての「Auth0」 - ログミーTech
- GitHub - auth0/auth0-spa-js: Auth0 authentication for Single Page Applications (SPA) with PKCE
- Configure Default Login Routes
- Token Storage
- Configure Silent Authentication
- response_mode=web_messageを調べた - Qiita
- Auth0のSilent Authentication (サイレント認証)とRefresh Token Rotation (リフレッシュトークンローテーション)を完全に理解した (い) - 一から勉強させてください