前提・実現したいこと
GASでLINEログインを用いたWebアプリを作成しています。
Oauth認証を用いてLINE認証した後のコールバック処理で、下記のエラーが発生しています。
何が問題で本事象が発生しているか、また、解決方法についてご存知の方がいらっしゃいましたらご教示頂けないでしょうか。
発生している問題・エラーメッセージ
Error: Error retrieving token: invalid_grant, authorization code expired or incompatible at Service_.getTokenFromResponse_(Service:541:11) at Service_.fetchToken_(Service:516:15) at Service_.handleCallback(Service:399:20)
該当のソースコード
test.gs
gs
1function doGet() { 2 'use strict'; 3 var service = getService(); 4 if (service.hasAccess()) { 5 createAndSendDocument(service.getAccessToken()); 6 return HtmlService.createHtmlOutput('Success'); 7 } 8 // 承認されていない場合、承認リンクをHTMLページに表示 9 var authorizationUrl = service.getAuthorizationUrl(); 10 var template = '<a href="' + authorizationUrl + '" target="_blank">Authorize</a>'; 11 return HtmlService.createHtmlOutput(template); 12} 13 14/** 15 * OAuth 2.0 serviceのセットアップ 16 */ 17function getService() { 18 'use strict'; 19 // OAuth 2.0承認サービスの生成 20 return OAuth2.createService('line') 21 22 .setAuthorizationBaseUrl('https://access.line.me/dialog/oauth/weblogin')// 認可エンドポイント 23 .setTokenUrl('https://api.line.me/oauth2/v2.1/token')// トークンエンドポイント 24 25 // LINEログインのクライアントIDおよびクライアントシークレットを設定 26 .setClientId('xxxxxxxxxx') // OAuthクライアントID 27 .setClientSecret('xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx') // OAuthクライアントシークレット 28 29 // OAuth2.0 承認後のコールバック関数名の設定 30 .setCallbackFunction('authCallback') 31 // 承認トークンを維持するプロパティーストアの設定 32 .setPropertyStore(PropertiesService.getUserProperties()) 33 // LINEログインリクエストのスコープ設定 34 .setScope('profile'); // LINEログインのスコープ 35} 36 37/** 38 * 最初のOAuth2承認の際のコールバック処理 39 */ 40function authCallback(request) { 41 'use strict'; 42 var service = getService(); 43 var authorized = service.handleCallback(request); 44 if (authorized) { 45 createAndSendDocument(service.getAccessToken()); 46 return HtmlService.createHtmlOutput('Success!'); 47 } 48 return HtmlService.createHtmlOutput('Denied.'); 49}
Oauthライブラリのソース抜粋
ソースコード全文
js
1Service_.prototype.handleCallback = function(callbackRequest) { 2 var code = callbackRequest.parameter.code; 3 var error = callbackRequest.parameter.error; 4 if (error) { 5 if (error == 'access_denied') { 6 return false; 7 } else { 8 throw new Error('Error authorizing token: ' + error); 9 } 10 } 11 validate_({ 12 'Client ID': this.clientId_, 13 'Client Secret': this.clientSecret_, 14 'Token URL': this.tokenUrl_ 15 }); 16 var payload = { 17 code: code, 18 client_id: this.clientId_, 19 client_secret: this.clientSecret_, 20 redirect_uri: this.getRedirectUri(), 21 grant_type: 'authorization_code' 22 }; 23 var token = this.fetchToken_(payload); 24 this.saveToken_(token); 25 return true; 26}; 27 28/** 29 * Fetches a new token from the OAuth server. 30 * @param {Object} payload The token request payload. 31 * @param {string} [optUrl] The URL of the token endpoint. 32 * @return {Object} The parsed token. 33 */ 34Service_.prototype.fetchToken_ = function(payload, optUrl) { 35 // Use the configured token URL unless one is specified. 36 var url = optUrl || this.tokenUrl_; 37 var headers = { 38 'Accept': this.tokenFormat_ 39 }; 40 if (this.tokenHeaders_) { 41 headers = extend_(headers, this.tokenHeaders_); 42 } 43 if (this.tokenPayloadHandler_) { 44 payload = this.tokenPayloadHandler_(payload); 45 } 46 var response = UrlFetchApp.fetch(url, { 47 method: 'post', 48 headers: headers, 49 payload: payload, 50 muteHttpExceptions: true 51 }); 52 return this.getTokenFromResponse_(response); 53}; 54 55/** 56 * Gets the token from a UrlFetchApp response. 57 * @param {UrlFetchApp.HTTPResponse} response The response object. 58 * @return {!Object} The parsed token. 59 * @throws If the token cannot be parsed or the response contained an error. 60 * @private 61 */ 62Service_.prototype.getTokenFromResponse_ = function(response) { 63 var token = this.parseToken_(response.getContentText()); 64 var resCode = response.getResponseCode(); 65 if ( resCode < 200 || resCode >= 300 || token.error) { 66 var reason = [ 67 token.error, 68 token.message, 69 token.error_description, 70 token.error_uri 71 ].filter(Boolean).map(function(part) { 72 return typeof(part) == 'string' ? part : JSON.stringify(part); 73 }).join(', '); 74 if (!reason) { 75 reason = resCode + ': ' + JSON.stringify(token); 76 } 77 throw new Error('Error retrieving token: ' + reason); 78 } 79 return token; 80};
試したこと
コールバック処理(authCallback)のINPUTパラメータ(request)の中身をログに出力したものの何が問題かが十分に分かりません。
log
1{ 2 parameters={ 3 code=[uLuj9s4Asa1qujrtAGm0] 4 , serviceName=line 5 , state=[ADEpC8zLJCo5fkyokPfDcyVfYbFS-2fdPU0DUBfrJOmN9E5-OWKdZW012RW3JViXtPw9EXtztv2FkxNqpeJ_3gkyhHb0xm-KDobrNbMz2NB_lV9scjSXFfdlnkD_FvCXNKR30oDMM1qOIBgxpwEFDLxq9mTVh0_sr2ZGNApQKsUpAa1y5PVrW70] 6 } 7 , parameter={ 8 serviceName=line 9 , code=uLuj9s4Asa1qujrtAGm0 10 , state=ADEpC8zLJCo5fkyokPfDcyVfYbFS-2fdPU0DUBfrJOmN9E5-OWKdZW012RW3JViXtPw9EXtztv2FkxNqpeJ_3gkyhHb0xm-KDobrNbMz2NB_lV9scjSXFfdlnkD_FvCXNKR30oDMM1qOIBgxpwEFDLxq9mTVh0_sr2ZGNApQKsUpAa1y5PVrW70 11 } 12 , queryString=code=uLuj9s4Asa1qujrtAGm0 13 &state=ADEpC8zLJCo5fkyokPfDcyVfYbFS-2fdPU0DUBfrJOmN9E5-OWKdZW012RW3JViXtPw9EXtztv2FkxNqpeJ_3gkyhHb0xm-KDobrNbMz2NB_lV9scjSXFfdlnkD_FvCXNKR30oDMM1qOIBgxpwEFDLxq9mTVh0_sr2ZGNApQKsUpAa1y5PVrW70 14 , contextPath= 15 , contentLength=-1.0 16}
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。