第 4 章 Nuxt に AuthO を組み込む ⅲ…」が表示されていますが、今はこれ以上の処理は組み込んでいません。 この画面からプラウザバックで戻ろうとすると、「 wentwrong 」の画面が表示されるか もしれません。その場合は、再度 http://IocaIhost:3333/ヘアクセスして、再ログインし てみてください。 4.26 CaIIback パラメータ /callback ヘリダイレクトされた時に、やたらと URL が長いことに気づくはずです。実 は、取得したトークンがクエリバラメータとして付与されています。 JWT は URL Safe うな内容が含まれています。 なトークンですので、クエリバラメータとして受け渡しができます。パラメータは次のよ id access token (Auth0 ヘアクセスするためのアクセストークン ) ・ expires—in ( 有効期限 ) token_type ( トークンの種類、 Bearer) ・ state (CSRF 対策用 ) id token (JWT 、このキーで自前の API ヘアクセスする ) token が重要です。今回は、 profile や email の内容も含めているので、 かなり長い トークンになっています。 リスト 4.7 plugins/auth. js の scope 指定部分 params : { scope : openid profile email' 取得した id_token は、 jwt. io でデコードしてみましよう。 32 てみます ( 図 4.6 ) 。 ズムを RS256 にして、 id_token ()y から始まる文字列 ) を Encoded 工リアに貼り付け AuthO が発行するトークンは、デフォルトだと RS256 になります。使用するアルゴリ
第 4 章 Nuxt に AuthO を組み込む 4.3 生 3.1 トークン管理 トークンを保存する 取得したトークンをプラウザで保持する必要があります。 C ( ) okie を使用すると CSRF の対策が面倒になるので、プラウザの IocaIStorage に保存する方針です。 まずは必要なライプラリを追加します。 リスト 4.9 jwt-decode, query-string の追加 yarn add jwt—decode //JWT の decode を行うライブラリ yarn add query-string / / クエリバラメータの取得を行うライブラリ 次に、 plugins/auth(). js へ、パラメータの取得とトークン保存する関数を実装します。 M リスト 4.10 plugins/authO. js import AuthOLock from ー authO¯10ck ー import jwtDecode from ' jwt-decode ' //jwt¯decode をインポート import queryString from ・ query-string' //query¯string をインポ class AuthOUti1 { getQueryParams ( ) { return queryString ・ parse(location. hash) setToken({access—token, id—token, expires—in}) { window. 10ca1Storage const Ioca1Storage 10ca1Storage. setltem(' accessToken' , access—token) IocaIStorage. setltem(' idT0ken ' , id—token) ート expires—in * 1000 + new Date() . getTime() ) IocaIStorage . setltem(' expiresAt ー JSON. stringify(jwtl)ecode(id—token) ) ) 10caIStorage . setltem('user' setTokenByQuery ( ) { this. setToken(this. getQueryParams()) ; expiresAt ですが、 expires—in は「発行時点からの経過時間」であるため、現在時刻 との比較しやすいように、「有効期限」へこの段階で変換しておきます。 User は先ほど jwt. i ( ) で確認した内容をそのまま JSON で保持しておきます。 最後に、 pages/callback. vue に setT0ken の呼び出し処理を加えます。 34
4.3 トークン管理 ソリスト 4.11 pages/callback. vue く template> く p>Signing in ・ .. く /p> く /template> く script> export default { mounted() { this . $authO. setT0kenByQuery ( ) く /script> ゴ ] Elements Consoie sources Network petformance Application です ( 図 4.7 ) 。 タブ→ Storage → LocaIStorage を確認すると、トークンなどの保存が確認できるはず して /callback まで遷移してください。その後、 Chrome DevTooIs を開いて、 AppIication 動作確認してみましよう。もう一度 http://locaIhost:3333/Iogin からログイン処理を これで、 callback. vue のマウント時に、トークンが保存されるようになります。 AppIication ー Manifest service Workers ・ Clear 引 0 「 age Storage マま三 LocaI Storage 三 h p : 川 oca ぬ 0S1 : 3333 C ① )< Fiiter Key accessToken idToken exp:resAt user Value V5GOvnB30Qa6PuG5ucRDF1 -Z( eyJOeXAiOiJ KVI QiLCJ hbGciOiJ S 15202715 3 {"givemname':"Takahir00. 、ねm日Yー 図 4.7 Chrome DevTools での表示例 4.3.2 トークン取得後のリダイレクト 現在「 Signingin... 」で止まってしまっているので、トークンを保存した後にリダイレ クトするようにします。リダイレクト先はトップページでよいでしよう。 VueRouter の機能を利用して、トップページへリダイレクトさせます。 setToken の直 後に 1 行加えます。 。ーリスト 4.12 pages/callback. vue 35
第 1 章 JSON Web Token 1 .4.2 PayIoad / ペイロード トークンの第 2 部分はペイロードです。 用いてユーザー情報などが埋め込まれます。ヘッダー同様にデコードした場合、次のよう な JSON が得られます。 V リスト 1 .3 ペイロード こに、 CIaim/ クレーム ( キーと値のペア ) を "sub" " 1234567890 " " Jo Ⅱ Doe" クレームの種類は上記だけではありません。予約済みのクレームを紹介します。 名前 ISS aud sub iat exp nbf 正式名 lssuer AIIdience Subject lssued At Expiration Time Not Before JWT ID 表 1 . 1 予約済みクレーム 内容 ユニーク性を担保するための ID 。 有効になる日時。 有効期限。 発行日時。 ューザーを識別できる ID が入る。 何を認証したか。同じ lssuer または世界でユニーク。 利用者。認証情報を使ったサービスの情報が入る。 発行者。アプリケーションやドメイン名が入る。 iss ( 誰が ) ,aud ( 誰のために ) ,sub ( 何を ) 発行したかで覚えるといいです。これら 以外にも、ユーザーのプロフィールデータ (name や email や picture など) を含めるこ secret) base64Ur1Encode(header) + " " + base64Ur1Encode(pay10ad) , HMACSHA256 ( マリスト 1 .4 HMAC-256 の場合の署名方法 シークレットを使用します。 トークンの第 3 部分は署名です。署名を作成するためには、ヘッダーとペイロード、 れ生 3 Signature / 署名 とができます。
第 1 章 JSON Web Token * 1 Connect 12 JWT とは何か ? JSON Web Token (JWT) は、 2 者間で情報を安全に伝送するためのトークンです。 発音は扣 t ( ジョット ) です。 JWT には、ユーザーに関する必要な情報がすべて含まれ ているのが特徴です。つまりトークンの中にユーザー ID を含めることができます。含ま れている情報はデジタル署名しているので、トークンの発行者 ( および発行者が保有する 情報を保持する者 ) のみが鍵を使ってトークンが改ざんされていないことをチェックでき ます。 署名には HX , IAC ・ RSA などの良く知られたアルゴリズムが使用できます。 こで注意 したいのは、一般的に JWT とは「署名」であって「暗号化」ではないことです。 JWT に 含まれているユーザー情報は鍵を知っていなくても閲覧できてしまいます。 ただし、暗号化のオプションも存在します。署名は JSON Web Signature (JWS) 、暗 号化は JSON Web Encryption (JWE) と呼ばれ、一般的に JWS のことを JWT と呼ん でいます。 また、 JWT は URL-safe なトークンで、サイズが小さいので URL ・ POST パラメー タ・ HTTP ヘッダー内で送信できるのが特徴です。 JWT は RFC7519 、 2 で標準化の提案がされており、 2018 / 02 時点でのステータスは PROPOSED STANDARD です。 1 .3 JWT の使い所 JWT は「認証」と「情報伝達」を同時に行う場面で使われます。ューザー情報をベイ ロードとして保持することができるため、認証をしつつ、ユーザー ID やトークンの期限 を伝達することができます。オーバーヘッドが小さく、異なるドメイン間で簡単に使用で きるので、 SingIeSignOn ( シングルサインオン ) で広く使われています。 たとえば、メール認証やパスワード忘れメールのトークンとして使う場合、ユーザー ID を含めることができるので、 DB でトークンを管理することなく、ユーザーを同定する ことができます。有名どころですと GoogIe の OAuth Token は JWT を使用しているよ うです。 、 1 https://www.slidesha.re.net/ngzm/oauth-lO-oauth-20-openid-connect 、 2 https://tools.ietf.org/html/rfc7519 8
付録 A Tips 例えば、会社が独自ドメインで GoogIe アカウントを使用している場合に、 GoogIe に よるソーシャルログインと RuIe でのドメイン制限を組み合わせて、簡単な業務アプリを 作ったりできますね。 A23 トークンを更新したい 一般的にトークンの更新は Refresh Token を用います。本書で用いた Lock ⅵ 1 です が、認証時のレスポンスに Refresh Token は含まれません。 (scope に offline access す れば良いという情報もありますが、追加してもダメです。 ) Lock V11 では、 SIient Authentication と checkSession を使用する必要があります。詳 しくは次の URL を参照してください。 https://auth().com/docs/guides/migration-legacy-flows#renewing-tokens https://github.com/auth()/lock#checksessionoptions-callback auth(). js の lock. show() をサンプルのように書き換えてみると、新しい token が取得 できることを確認できます。ただしこれを行うためには、 GoogIe の設定を AuthO の DevKey ではなく、正式な Key を使うように設定しなければいけません。 プリスト A. 4 frontend/plugins/authO. js / / lock . show() lock. checkSession()} , function (error, if (error Ⅱ !authResu1t) { lock . show() ; } else { console .10g(authResu1t) ; authResuIt ) { IOCk. getUserInfo(authResuIt . accessT0ken, console . log(error, profile) ; function (error, profile) { AuthO とのセッション情報を用いて、トークンの更新を行っているようです。 authRe- sult に各種 token が入っているのが分かります。 58
第 1 章 JSON Web Token 本書で紹介する Auth0 は、 JSON Web Token (JWT) を利用したトークン認証を使い ます。まずはこの章で JWT について紹介します。 1 .1 認可と認証 7 アプリ開発で知っておきたい認証技術ー OAuth 1.0 十 OAuth 2.0 十 OpenID 認可認証に関しては、次の記事が良くまとまっています。 JWT は OpenID Connect の IdToken として使われる IdToken →認証用トークン、 JWT ・ AccessToken →認可用トークン うになります。 えてください。この IdToken が、本書で詳しく解説する、 JWT です。まとめると次のよ における認証用のトークンは IdToken (ldentity Token) と呼ばれます。「身分証」と考 OAuth2.0 十認証 = OpenID Connect という理解で問題ありません。 OpenID Connect ります。これは OAuth2 を拡張したもので「認証」と「認可」をどちらも含むものです。 「認可」対して「認証」は誰かを特定することです。 OpenID Connect という仕様があ ており、 OAuth の枠組みの中に「認証」は入っていません。 を使用してユーザー情報へのアクセスを行い、これを認証情報として用いることで実現し は認可の仕様で、認証ではありません。「 OAuth 認証」と呼ばれているものは、「通行証」 セス権は、 AccessToken と呼ばれます。「通行証」と考えてください。 OAuth や OAuth2 「認可」は特定の条件においてリソースアクセス権を与えることです。発行されるアク JWT の話をする前に、「認可」と「認証」について簡単に整理しておきます。
1 .4 JWT の構造 14 JWT の構造 JWT はドット (. ) で区切られた 3 つの部分で構成されます。 eyJhbGciOiJIUz11NiIsInR5cC161kpXVCJ9. マリスト 1 . 1 JWT のサンプル これらは Header 、 PayIoad 、 Signature の順で連結され、次のような形式になります。 Signature / 署名 ・ Payload/ ペイロード Header / ヘッダー eyJzdWIiOiIxMjMONTY30DkwIiwibmFtZS161kpvaG4gRG911iwiYWRtaW4iOnRydWV9. ますが、実際の JWT は改行が含まれません。 リスト 1.1 の各行が前述した 3 つの部分に該当します。横幅の関係上、改行を入れてい TJVA950rM7E2cBab30RMHrHDcEfxj oYZgeFONFh7HgQ リスト 1 .2 ヘッダー シュアルゴリズムが定義されています。中身を見てみましよう。 1 .4.1 Header/ ヘッダー トークンの第 1 部分はヘッダーです。ヘッダーではトークンの種類と、使用されるハッ "alg" "typ' " HS256 " " JWT " 署名アルゴリズムとして HMAC ー 256 を使用した JWT ということが分かります。 alg の種類はのちほど紹介します。 工ンコード済み Base64Url なので、 1 行目のドットの手前までをデコーディングしてみ ると、上記 JSON が得られるはずです。 Base64Decode*3 などのサイトを活用して、自身 で確認してみてください。 、 3 https://www.base64decode.org/ 9
6.6 認証必須な API を直接叩いてみる 6.7 Nuxt から API を呼ぶ " ID : 1 , SUB : goog1e—oauth2 ー XXXXXXXXXXXXXXXXXXXXXX" リスト 6.11 SecuredPing の結果 使ってユーザーが作成できているか確認してみてください。 次ののような結果が得られたら成功です。データベースを覗いた http: //localhost : 3000/api/v1/secured_ping curl —H "Authorization: Bearer く YOUR ID_TOKEN>t' \ リスト 6.10 idToken を使用して SecuredPing を叩く Storage の内容をコピーしましよう。 フロントで取得した idToken を使用して、 API を叩いてみます。 IdToken は Local- 6.6 認証必須な API を直接叩いてみる http://localhost:30()O/api/v1/secured—ping http://localhost:3000/api/v1/ping り、 rails C011S01e を、 手作業で動作確認ができたので、フロント側の処理を書き換えていきましよう。取得し たトークンを使えるようにしたいので、 frontend/plugins/auth(). js に、 localStorage か らキーを取得する関数を実装しておきます。 V リスト 6.12 frontend/plugins/authO. js class AuthOUti1 { getIdT0ken( ) { return this . isAuthenticated() ? 10ca1Storage . getltem(' idToken') index. vue を修正して、 SecuredPing ボタンを配置します。 Y リスト 6.13 frontend/pages/index. vue <template> 53 Ⅱ u11
第 4 章 Nuxt に AuthO を組み込む ログインしてください 初 Login 咽 4.8 非ログイン時の表示 ログイン中です ・ Logout △図 4.9 ログイン中の表示 ログアウトはボタンだけ用意してロジックは実装していませんが、 localStorage をクリ ログアウトは、 localStorage に保存されているトークンなどをクリアすることで実現し 4.4.4 ログアウトボタンの実装 アすると、 expiresAt が null になるため、実質ログアウトとなります。 IocaIStorage ・ removeltem('user つ 10caIStorage. removeltem(' expiresAt つ 10caIStorage. removeltem(' idT0ken') 10caIStorage. removeltem(' accessT0kent) const Ioca1Storage = window. 10calStorage unsetT0ken ( ) { class AuthOUti1 { リスト 4.17 plugins/auth0. js に unsetToken を追加 ます。 Auth0UtiI クラスに、 unsetToken メソッドを追加します。 38 するだけなので、 callback. vue と同じような内容になりますね。 ログアウトページを作成します。トークンをクリアして、トップページへリダイレクト