【AWS】CognitoでGoogleソーシャルログイン。Amplifyと連携してVue.jsアプリケーションに組み込む
前回、Qiita初投稿させて頂いた、個人開発のAWSサーバーレスWEBサイト「ボケさせて(BOKESASETE)」ですが、
前回記事
【個人開発】AWSサーバーレスアーキテクチャで機械学習とボケ。フロントエンドはVue.jsで遊ぶ
おかげさまで、徐々にではありますが、ご登録頂けるユーザーも増えつつあります。
しかしながら、現状のフローではメールアドレス認証による会員登録しかできない状態となっていて、モダンなWEBサイトとは言えません。
せめて、ソーシャルログインぐらいは欲しいところです。
そこで今回、AWS Cognito × Vue.js
のWEBサイトにGoogleでログインするソーシャルログイン機能を追加しました、という話。
はじめに
写真で一言。ボケてみるよりボケさせて - BOKESASETE
https://bokesasete.me/
ボケさせて(BOKESASETE)では、会員情報の管理にAWS Cognito
を利用しています。
今回、Cognito
のフェデレーションという仕組みを利用し、ユーザープールとGoogleアカウントが連携できるよう機能改修しました。
公式
サードパーティー経由のユーザープールへのサインインの追加
やり方
Cognito側の設定
基本的には、以下記事にて詳細手順をまとめて頂いておりますので、ご参照ください。
参考
AWS CognitoにGoogleとYahooとLINEアカウントを連携させる
ただ、上記例ですと「ログインエンドポイント」を利用していますので、ボケさせて(BOKESASETE)のように、既にログイン画面をアプリケーション側で用意してしまっている場合、使い勝手が悪いです。
なので、次のSTEPでご紹介する「認証エンドポイント」を利用します。
認証ボタン設置
Cognito
の様々なエンドポイントについては、以下記事でかなり詳しくおまとめ頂いています。
筆者の場合、「認証エンドポイント(許可されているOAuthフロー:Authorization Code Grant
)」を利用し、既存のログイン画面に「Googleでログイン」ボタンを設置しました。
以下、設置例です(Vuetify
を利用してます)
..略
<a :href="COGNITO_BASE_URL+'/oauth2/authorize?identity_provider=Google&response_type=code&client_id='+USER_POOL_WEB_CLIENT_ID+'&redirect_uri='+COGNITO_REDIRECT_URL">
<v-btn round large color="red darken-2" dark>
<v-icon class="pa-2" small>fab fa-google</v-icon>
Googleでログイン
</v-btn>
</a>
..略
※「COGNITO_BASE_URL」「USER_POOL_WEB_CLIENT_ID」「COGNITO_REDIRECT_URL」のところは環境に合わせて設定してください
上記「redirect_uri」で指定した戻り先URLに対して、認証を終えると「認可コード」が渡ってくる仕様です。
https://example.com/redirect?code=hogehogehugahuga
こんな感じでリダイレクトされて返ってきます。
さて、ここまでは参考記事のおかげで、割とすんなり実装できたのですが、ここからVue.js
で作ったアプリケーション(認証にはAmplify
を利用)に対して、どのようにログイン認証情報を渡せばよいのか、というところで行き詰まりました。
結論から申し上げると、今回は力技で乗り切りました。
なので、もっとスマートなやり方があるはずですので、どなたかもしご存知でしたらこっそりと教えてください。
やったこと
まず、Amplify
の認証情報を解析しました。
すると、localStorage
内にトークン類(accessToken
,idToken
,refreshToken
)が以下のようなルールで格納されていることが分かりました。
'CognitoIdentityServiceProvider.' + クライアントID + '.' + ユーザーID + '.accessToken'
'CognitoIdentityServiceProvider.' + クライアントID + '.' + ユーザーID + '.idToken'
'CognitoIdentityServiceProvider.' + クライアントID + '.' + ユーザーID + '.refreshToken'
Amplify
では、ここに格納された認証情報を参照してログイン判定/処理を行っているに違いない
そのように考え、各エンドポイントを駆使して、自分でlocalStorageを書き換えて対応しました。
以下、コード抜粋です。
// ..略
// googleログインの場合、localstorageに認証情報を補完
let code = this.$route.query.code
if (code) {
let params = new URLSearchParams();
params.append('grant_type', 'authorization_code')
params.append('redirect_uri', COGNITO_REDIRECT_URL)
params.append('code', code)
params.append('client_id', USER_POOL_WEB_CLIENT_ID)
axios.post(COGNITO_BASE_URL + '/oauth2/token', params, {
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
})
.then(token => {
let bearer = 'Bearer ' + token.data.access_token
axios.post(COGNITO_BASE_URL + '/oauth2/userInfo', {}, {
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': bearer
}
})
.then(userInfo => {
// localStorageを書き換え
localStorage.setItem('CognitoIdentityServiceProvider.' + USER_POOL_WEB_CLIENT_ID + '.' + userInfo.data.sub + '.accessToken', token.data.access_token)
localStorage.setItem('CognitoIdentityServiceProvider.' + USER_POOL_WEB_CLIENT_ID + '.' + userInfo.data.sub + '.idToken', token.data.id_token)
localStorage.setItem('CognitoIdentityServiceProvider.' + USER_POOL_WEB_CLIENT_ID + '.' + userInfo.data.sub + '.refreshToken', token.data.refresh_token)
localStorage.setItem('CognitoIdentityServiceProvider.' + USER_POOL_WEB_CLIENT_ID + '.' + userInfo.data.sub + '.clockDrift', 0)
localStorage.setItem('CognitoIdentityServiceProvider.' + USER_POOL_WEB_CLIENT_ID + '.LastAuthUser', userInfo.data.sub)
// 正常処理
})
.catch(error => {
// error 処理
})
})
.catch(error => {
// error 処理
})
}
// ..略
以下のような処理の流れ。
- リダイレクト時に渡ってきた「認可コード」を利用し、「トークンエンドポイント」からトークン情報を取得
- 「手順:1」で取得した「アクセストークン」を利用し、ユーザープールの情報(ユーザーIDなど)を「USERINFOエンドポイント」から取得
- トークン情報およびユーザー情報を
localStorage
に格納
上記手順で、AWS Cognito × Vue.js
のWEBサイトにGoogleでログインするソーシャルログイン機能を実装することができました。
現在、特に問題なく動作しています。
ハマったこと
基本的には上記手順にて、問題なくログイン連携できるのですが、ハマった部分もありましたのでご紹介します。
認証成功してもユーザーの属性情報が取得できない
認証自体は成功したにもかかわらず、Cognito
側からユーザーのニックネームやその他属性情報が取得できない状況に陥りました。
結論、これは凡ミスで「認証エンドポイント」に「&scope=openid%20email」というパラメタが付与されたままだった(コピペしたまま残っていた)ことが原因でした。
「Googleでログイン」ボタンのパラメタからscope指定を外すことで、Cognito
側の設定が効いて、ユーザーのニックネームや属性情報が取得できるようになりました。
(もちろんCognito
のコンソール側で、以下のように「許可されているOAuthスコープ」を適切に設定しておく必要があります)
ちょいちょいログインが切れる
これはそもそも認証エンドポイントの許可されているOAuthフローでImplicit Grant
を利用していることが原因でした。
Implicit Grant
を利用した認証の場合、リダイレクト先に直接トークン類が渡ってきますので、Authorization Code Grant
に比べて、一手間省けるため、当初この方式を採用していました。
しかしながらImplicit Grant
の場合、「refreshToken」が付与されない仕様のため、1時間でアクセストークンの有効期限が切れ、結果的にログイン状態が頻繁に解除されてしまう現象に陥りました。
そこでAuthorization Code Grant
による認証フローに変更し、先に記載したような流れでトークン取得を行うようプログラム調整を行ったところ、期待した動作をする(ログイン情報が常に維持される)ようになりました。
終わりに
どなたかの役に立てば何よりです。
Author And Source
この問題について(【AWS】CognitoでGoogleソーシャルログイン。Amplifyと連携してVue.jsアプリケーションに組み込む), 我々は、より多くの情報をここで見つけました https://qiita.com/chitamano/items/d28f205ece7cbe46c02a著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .