回答編集履歴

42

追記

2022/05/03 20:10

投稿

退会済みユーザー
test CHANGED
@@ -1,4 +1,7 @@
1
1
  **<下記は「試みたものの、結果としてはうまくいなかった例」になりますが、試行の過程として残しています。修正後の内容は、後述の「追記2」を参照してください>**
2
+ また、以下は、Amazon SP-API上での検証ではなく、他の一般的なOAuth2.0アプリケーションでの検証になります。
3
+  
4
+  
2
5
  コピー元のスクリプトに doGet() を実装してWebアプリとしてデプロイし、コピー先からコピー元に対して、認証に必要な処理を呼び出せるようにしてはいかがでしょうか。
3
6
 
4
7
  + DEPLOY_URL は、一度コピー元をデプロイして確定してしまえば、変更がない限りコピー先で変更する必要はありません。(コピー先ファイルごとのデプロイURLに変える必要はありません。)

41

 

2022/05/01 06:05

投稿

退会済みユーザー
test CHANGED
@@ -224,8 +224,8 @@
224
224
  # 追記
225
225
 
226
226
  他の人にも協力してもらい、いろいろ試しましたが、このスクリプトは下記のような根本的な問題点があるらしいことが分かりました。
227
- + ①originalを所有(作成)しているGoogleアカウント以外のアカウントが、コピーしたファイルから showDialog を実行した場合、認可フローを完了させることができない(トークンが無効または期限が切れていると表示される)
227
+ + ①originalを所有(作成)しているGoogleアカウント**以外**のアカウントが、コピーしたファイルから showDialog を実行した場合、認可フローを完了させることができない(トークンが無効または期限が切れていると表示される)
228
- (①[オリジナル]を所有(作成)しているアカウント ②[コピー]を実行する場合は認証フローを完了できる)
228
+ (①[オリジナル]を所有(作成)しているGoogleアカウントであれば ②[コピー]のshowDialogを実行しても問題なく認証フローを完了できる)
229
229
  これは、オリジナルとコピー両方公開ファイルにしても変わりません。
230
230
  (おそらくGASまたはOAuth2.0の仕組み上不可避と思われます)
231
231
 

40

 

2022/05/01 06:04

投稿

退会済みユーザー
test CHANGED
@@ -225,6 +225,7 @@
225
225
 
226
226
  他の人にも協力してもらい、いろいろ試しましたが、このスクリプトは下記のような根本的な問題点があるらしいことが分かりました。
227
227
  + ①originalを所有(作成)しているGoogleアカウント以外のアカウントが、コピーしたファイルから showDialog を実行した場合、認可フローを完了させることができない(トークンが無効または期限が切れていると表示される)
228
+ (①[オリジナル]を所有(作成)しているアカウントが ②[コピー]を実行する場合は認証フローを完了できる)
228
229
  これは、オリジナルとコピー両方公開ファイルにしても変わりません。
229
230
  (おそらくGASまたはOAuth2.0の仕組み上不可避と思われます)
230
231
 

39

 

2022/05/01 05:29

投稿

退会済みユーザー
test CHANGED
@@ -224,12 +224,13 @@
224
224
  # 追記
225
225
 
226
226
  他の人にも協力してもらい、いろいろ試しましたが、このスクリプトは下記のような根本的な問題点があるらしいことが分かりました。
227
- + ①を所有(作成)しているGoogleアカウント以外のアカウントが ②のファイルから showDialog を実行した場合、認可フローを完了させることができない(トークンが無効または期限が切れていると表示される)
227
+ + ①originalを所有(作成)しているGoogleアカウント以外のアカウントが、コピーしたファイルから showDialog を実行した場合、認可フローを完了させることができない(トークンが無効または期限が切れていると表示される)
228
- これは、両方公開ファイルにしても変わりません。
228
+ これは、オリジナルコピー両方公開ファイルにしても変わりません。
229
229
  (おそらくGASまたはOAuth2.0の仕組み上不可避と思われます)
230
230
 
231
+ 一方、一部ではうまく行っています。
231
- + ①での認証・認可後、を所有しているアカウント以外のアカウントが ②を利用して①からアクセストークンを受け取り、アクセストークンを利用した処理を行うことは一応可能。
232
+ + ①[オリジナル]での認証・認可後、オリジナルを所有(作成)しているアカウント以外のアカウントが ②[コピー]を利用して①[オリジナル]からアクセストークンを受け取り、アクセストークンを利用した処理を行うことは可能。
232
- + ①の発行しているアクセストークンが揮発しも、①を所有しているアカウント以外のアカウントは ②を利用中に更新後のアクセストークンを取得できる。
233
+ + ①からもらったアクセストークンが揮発した場合でも、①から自動的に更新後のアクセストークンを取得できる。
233
234
   
234
235
  したがって、少なくとも最初の認証・認可フローは①を所有しているアカウント(①を作成したアカウント)で行う必要がありそうです。
235
236
 

38

 

2022/05/01 05:24

投稿

退会済みユーザー
test CHANGED
@@ -1,4 +1,5 @@
1
+ **<下記は「試みたものの、結果としてはうまくいなかった例」になりますが、試行の過程として残しています。修正後の内容は、後述の「追記2」を参照してください>**
1
- 下記ようdoGet() を実装して、コピー先からコピー元に対して、認証に必要な処理を呼び出せるようにしてはいかがでしょうか。
2
+ コピー元スクリプト doGet() を実装してWebアプリとしてデプロイし、コピー先からコピー元に対して、認証に必要な処理を呼び出せるようにしてはいかがでしょうか。
2
3
 
3
4
  + DEPLOY_URL は、一度コピー元をデプロイして確定してしまえば、変更がない限りコピー先で変更する必要はありません。(コピー先ファイルごとのデプロイURLに変える必要はありません。)
4
5
 

37

 

2022/05/01 02:17

投稿

退会済みユーザー
test CHANGED
@@ -225,7 +225,7 @@
225
225
  他の人にも協力してもらい、いろいろ試しましたが、このスクリプトは下記のような根本的な問題点があるらしいことが分かりました。
226
226
  + ①を所有(作成)しているGoogleアカウント以外のアカウントが ②のファイルから showDialog を実行した場合、認可フローを完了させることができない(トークンが無効または期限が切れていると表示される)
227
227
  これは、①と②両方公開ファイルにしても変わりません。
228
- (おそらくGASまたはOauth2の仕組み上不可避と思われます)
228
+ (おそらくGASまたはOAuth2.0の仕組み上不可避と思われます)
229
229
 
230
230
  + ①での認証・認可後、①を所有しているアカウント以外のアカウントが ②を利用して①からアクセストークンを受け取り、アクセストークンを利用した処理を行うことは一応可能。
231
231
  + ①の発行しているアクセストークンが揮発しても、①を所有しているアカウント以外のアカウントは ②を利用中に更新後のアクセストークンを取得できる。

36

 

2022/05/01 01:43

投稿

退会済みユーザー
test CHANGED
@@ -337,5 +337,5 @@
337
337
  }
338
338
  ```
339
339
   
340
- ただし、現状のコードだと、DEPLOY_URLを第三者に知られてしまうと、その人がアクセストークンを取得して勝手にいろいろできてしまうので、何らかの管理のしくみ(GET時のパラメータに特別なトークンが埋め込まれていないとアクセストークンを発行できないようにする等)が別途必要かもしれません
340
+ ただし、現状の単純なコードでは、DEPLOY_URLを第三者に知られてしまうと、その人がアクセストークンを取得して勝手にいろいろできてしまうので、何らかの管理のしくみ(GET時のパラメータに特別なトークンが埋め込まれていないとアクセストークンを発行できないようにする等)を実装することが必要です
341
- (この点は冒頭に記載した単一ファイルを運用する場合でも同じです。さらに単一ファイルだとclient_secret利用者セラーに知られてしまうのが問題す)
341
+ (この点は冒頭に記載した単一ファイルを運用する場合でも同じです。さらに単一ファイルだと認証に必要なclient_id や client_secret まで利用者セラーに知られてしまうのが問題だと思います)

35

 

2022/05/01 01:41

投稿

退会済みユーザー
test CHANGED
@@ -337,5 +337,5 @@
337
337
  }
338
338
  ```
339
339
   
340
- ただし、現状のコードだと、DEPLOY_URLを第三者に知られてしまうと、その人がアクセストークンを取得して勝手にいろいろできてしまうので、何らかの管理のしくみ(post時に別トークン埋め込識別する等)が別途必要かもしれません。
340
+ ただし、現状のコードだと、DEPLOY_URLを第三者に知られてしまうと、その人がアクセストークンを取得して勝手にいろいろできてしまうので、何らかの管理のしくみ(GETのパラメータトークン埋め込まれていないとアクセストークンを発行きないようにする等)が別途必要かもしれません。
341
341
  (この点は冒頭に記載した単一ファイルを運用する場合でも同じです。さらに単一ファイルだとclient_secretも利用者セラーに知られてしまうのが問題です)

34

 

2022/05/01 01:39

投稿

退会済みユーザー
test CHANGED
@@ -223,14 +223,14 @@
223
223
  # 追記
224
224
 
225
225
  他の人にも協力してもらい、いろいろ試しましたが、このスクリプトは下記のような根本的な問題点があるらしいことが分かりました。
226
- + ①を所有(作成)しているGoogleアカウント以外のアカウントが ②のファイルから showDialog を実行した場合、認フローを完了させることができない(トークンが無効または期限が切れていると表示される)
226
+ + ①を所有(作成)しているGoogleアカウント以外のアカウントが ②のファイルから showDialog を実行した場合、認フローを完了させることができない(トークンが無効または期限が切れていると表示される)
227
227
  これは、①と②両方公開ファイルにしても変わりません。
228
228
  (おそらくGASまたはOauth2の仕組み上不可避と思われます)
229
229
 
230
- + ①での認証後、①を所有しているアカウント以外のアカウントが ②を利用して①からアクセストークンを受け取り、アクセストークンを利用した処理を行うことは一応可能。
230
+ + ①での認証・認可後、①を所有しているアカウント以外のアカウントが ②を利用して①からアクセストークンを受け取り、アクセストークンを利用した処理を行うことは一応可能。
231
231
  + ①の発行しているアクセストークンが揮発しても、①を所有しているアカウント以外のアカウントは ②を利用中に更新後のアクセストークンを取得できる。
232
232
   
233
- したがって、少なくとも最初の認証フローは①を所有しているアカウント(①を作成したアカウント)で行う必要がありそうです。
233
+ したがって、少なくとも最初の認証・認可フローは①を所有しているアカウント(①を作成したアカウント)で行う必要がありそうです。
234
234
 
235
235
   
236
236
 
@@ -238,8 +238,8 @@
238
238
   
239
239
  # 追記2
240
240
  結局、運用方針としては、下記のように①と②を分離し、
241
- + ①は開発者/管理者が専有してメンテナンス(最初だけ認証を行ってリフレッシュトークン・アクセストークンをキャッシュしておく)
241
+ + ①は開発者/管理者が専有してメンテナンス(最初だけ認証・認可を行ってリフレッシュトークン・アクセストークンをキャッシュしておく)
242
- + 利用者側には②をコピーして使ってもらう(①がアクセストークンを保持している限り②側での認証フローは不要)
242
+ + 利用者側には②をコピーして使ってもらう(①がアクセストークンを保持している限り②側での認証・認可フローは不要)
243
243
  というのが現実的かもしれませんね。
244
244
   
245
245
  crient_secret が書かれたファイルをむやみに渡す必要がなくなるというメリットもあると思います。
@@ -293,7 +293,7 @@
293
293
 
294
294
  ②改
295
295
  実際の処理を行うファイル。こちらを複製してセラーにつかってもらう。
296
- 利用者セラーは認証フローを行わない前提のため、showDialogは①へ移動した。
296
+ 利用者セラーは認証・認可フローを行わない前提のため、showDialogは①へ移動した。
297
297
  こちらは特にデプロイする必要はない。
298
298
  ```js
299
299
  const DEPLOY_URL = 'https://script.google.com/macros/s/***/exec'; // ①のデプロイURL

33

  

2022/05/01 01:35

投稿

退会済みユーザー
test CHANGED
@@ -223,8 +223,10 @@
223
223
  # 追記
224
224
 
225
225
  他の人にも協力してもらい、いろいろ試しましたが、このスクリプトは下記のような根本的な問題点があるらしいことが分かりました。
226
- + ①を所有しているアカウント以外のアカウントが ②の showDialog を実行した場合、認証フローを完了させることができない(トークンが無効または期限が切れていると表示される)(これはおそらくOauth2の仕組み上不可避と思われます)
226
+ + ①を所有(作成)しているGoogleアカウント以外のアカウントが ②のファイルから showDialog を実行した場合、認証フローを完了させることができない(トークンが無効または期限が切れていると表示される)
227
227
  これは、①と②両方公開ファイルにしても変わりません。
228
+ (おそらくGASまたはOauth2の仕組み上不可避と思われます)
229
+
228
230
  + ①での認証後、①を所有しているアカウント以外のアカウントが ②を利用して①からアクセストークンを受け取り、アクセストークンを利用した処理を行うことは一応可能。
229
231
  + ①の発行しているアクセストークンが揮発しても、①を所有しているアカウント以外のアカウントは ②を利用中に更新後のアクセストークンを取得できる。
230
232
   

32

 

2022/05/01 01:34

投稿

退会済みユーザー
test CHANGED
@@ -229,8 +229,11 @@
229
229
  + ①の発行しているアクセストークンが揮発しても、①を所有しているアカウント以外のアカウントは ②を利用中に更新後のアクセストークンを取得できる。
230
230
   
231
231
  したがって、少なくとも最初の認証フローは①を所有しているアカウント(①を作成したアカウント)で行う必要がありそうです。
232
-  
233
- ---
232
+
233
+  
234
+
235
+
236
+  
234
237
  # 追記2
235
238
  結局、運用方針としては、下記のように①と②を分離し、
236
239
  + ①は開発者/管理者が専有してメンテナンス(最初だけ認証を行ってリフレッシュトークン・アクセストークンをキャッシュしておく)

31

 

2022/05/01 01:32

投稿

退会済みユーザー
test CHANGED
@@ -223,7 +223,7 @@
223
223
  # 追記
224
224
 
225
225
  他の人にも協力してもらい、いろいろ試しましたが、このスクリプトは下記のような根本的な問題点があるらしいことが分かりました。
226
- ①を所有しているアカウント以外のアカウントが ②の showDialog を実行した場合、認証フローを完了させることができない(トークンが無効または期限が切れていると表示される)(これはおそらくOauth2の仕組み上不可避)
226
+ + ①を所有しているアカウント以外のアカウントが ②の showDialog を実行した場合、認証フローを完了させることができない(トークンが無効または期限が切れていると表示される)(これはおそらくOauth2の仕組み上不可避と思われます
227
227
  これは、①と②両方公開ファイルにしても変わりません。
228
228
  + ①での認証後、①を所有しているアカウント以外のアカウントが ②を利用して①からアクセストークンを受け取り、アクセストークンを利用した処理を行うことは一応可能。
229
229
  + ①の発行しているアクセストークンが揮発しても、①を所有しているアカウント以外のアカウントは ②を利用中に更新後のアクセストークンを取得できる。

30

 

2022/05/01 01:31

投稿

退会済みユーザー
test CHANGED
@@ -223,14 +223,16 @@
223
223
  # 追記
224
224
 
225
225
  他の人にも協力してもらい、いろいろ試しましたが、このスクリプトは下記のような根本的な問題点があるらしいことが分かりました。
226
- ・①を所有しているアカウント以外のアカウントが ②の showDialog を実行した場合、認証フローを完了させることができない(トークンが無効または期限が切れていると表示される)
226
+ ・①を所有しているアカウント以外のアカウントが ②の showDialog を実行した場合、認証フローを完了させることができない(トークンが無効または期限が切れていると表示される)(これはおそらくOauth2の仕組み上不可避)
227
227
  これは、①と②両方公開ファイルにしても変わりません。
228
228
  + ①での認証後、①を所有しているアカウント以外のアカウントが ②を利用して①からアクセストークンを受け取り、アクセストークンを利用した処理を行うことは一応可能。
229
229
  + ①の発行しているアクセストークンが揮発しても、①を所有しているアカウント以外のアカウントは ②を利用中に更新後のアクセストークンを取得できる。
230
230
   
231
231
  したがって、少なくとも最初の認証フローは①を所有しているアカウント(①を作成したアカウント)で行う必要がありそうです。
232
232
   
233
+ ---
234
+ # 追記2
233
- 運用方針として、下記のように①と②を分離し、
235
+ 結局、運用方針として、下記のように①と②を分離し、
234
236
  + ①は開発者/管理者が専有してメンテナンス(最初だけ認証を行ってリフレッシュトークン・アクセストークンをキャッシュしておく)
235
237
  + 利用者側には②をコピーして使ってもらう(①がアクセストークンを保持している限り②側での認証フローは不要)
236
238
  というのが現実的かもしれませんね。

29

  

2022/05/01 01:30

投稿

退会済みユーザー
test CHANGED
@@ -330,5 +330,5 @@
330
330
  }
331
331
  ```
332
332
   
333
- ただし、現状のコードだと、DEPLOY_URLを知られてしまうだけでアクセストークンを取得して勝手にいろいろできてしまうので、何らかの管理のしくみが別途必要かもしれません。
333
+ ただし、現状のコードだと、DEPLOY_URLを第三者に知られてしまうと、その人がアクセストークンを取得して勝手にいろいろできてしまうので、何らかの管理のしくみ(post時に別のトークンを埋め込んで識別する等)が別途必要かもしれません。
334
334
  (この点は冒頭に記載した単一ファイルを運用する場合でも同じです。さらに単一ファイルだとclient_secretも利用者セラーに知られてしまうのが問題です)

28

 

2022/05/01 01:28

投稿

退会済みユーザー
test CHANGED
@@ -331,4 +331,4 @@
331
331
  ```
332
332
   
333
333
  ただし、現状のコードだと、DEPLOY_URLを知られてしまうだけでアクセストークンを取得して勝手にいろいろできてしまうので、何らかの管理のしくみが別途必要かもしれません。
334
- ただし、この点は冒頭に記載した単一ファイルを運用する場合でも同じです。さらに単一ファイルだとclient_secretも利用者セラーに知られてしまうのが問題です)
334
+ (この点は冒頭に記載した単一ファイルを運用する場合でも同じです。さらに単一ファイルだとclient_secretも利用者セラーに知られてしまうのが問題です)

27

 

2022/05/01 01:28

投稿

退会済みユーザー
test CHANGED
@@ -230,15 +230,13 @@
230
230
   
231
231
  したがって、少なくとも最初の認証フローは①を所有しているアカウント(①を作成したアカウント)で行う必要がありそうです。
232
232
   
233
- 運用方針として、①と②を分離し、
233
+ 運用方針として、下記のように①と②を分離し、
234
234
  + ①は開発者/管理者が専有してメンテナンス(最初だけ認証を行ってリフレッシュトークン・アクセストークンをキャッシュしておく)
235
235
  + 利用者側には②をコピーして使ってもらう(①がアクセストークンを保持している限り②側での認証フローは不要)
236
236
  というのが現実的かもしれませんね。
237
237
   
238
238
  crient_secret が書かれたファイルをむやみに渡す必要がなくなるというメリットもあると思います。
239
-  
240
- ただし、現状のコードだと、DEPLOY_URLを知られてしまうだけでアクセストークンを取得して勝手にいろいろできてしまうので、何らかの管理のしくみが別途必要かもしれません。
239
+
241
- (この点は冒頭に記載した単一ファイルを運用する場合でも同じです。さらに単一ファイルだとclient_secretも明記されてしまっているのが問題)
242
240
   
243
241
  ①改(認証・認可用ファイル。showDialogを元に戻した)。デプロイし、デプロイURLを②改に記載する。
244
242
  ```js
@@ -331,4 +329,6 @@
331
329
  console.log(orders);
332
330
  }
333
331
  ```
332
+  
334
-
333
+ ただし、現状のコードだと、DEPLOY_URLを知られてしまうだけでアクセストークンを取得して勝手にいろいろできてしまうので、何らかの管理のしくみが別途必要かもしれません。
334
+ (ただし、この点は冒頭に記載した単一ファイルを運用する場合でも同じです。さらに単一ファイルだとclient_secretも利用者セラーに知られてしまうのが問題です)

26

 

2022/05/01 01:26

投稿

退会済みユーザー
test CHANGED
@@ -240,7 +240,7 @@
240
240
  ただし、現状のコードだと、DEPLOY_URLを知られてしまうだけでアクセストークンを取得して勝手にいろいろできてしまうので、何らかの管理のしくみが別途必要かもしれません。
241
241
  (この点は冒頭に記載した単一ファイルを運用する場合でも同じです。さらに単一ファイルだとclient_secretも明記されてしまっているのが問題)
242
242
   
243
- ①改(認証・認可用ファイル。showDialogを元に戻した)
243
+ ①改(認証・認可用ファイル。showDialogを元に戻した)。デプロイし、デプロイURLを②改に記載する。
244
244
  ```js
245
245
  AUTH_ENDPOINT = 'https://XXX';
246
246
  TOKEN_ENDPOINT = 'https://YYY';
@@ -286,7 +286,10 @@
286
286
  ```
287
287
 
288
288
 
289
+ ②改
290
+ 実際の処理を行うファイル。こちらを複製してセラーにつかってもらう。
289
- ②改’(実際の処理を行うファイル。こちらを複製してセラーにつかってもらう。セラーは認証フローを行わない前提のため、showDialogは①へ移動
291
+ 利用者セラーは認証フローを行わない前提のため、showDialogは①へ移動した。
292
+ こちらは特にデプロイする必要はない。
290
293
  ```js
291
294
  const DEPLOY_URL = 'https://script.google.com/macros/s/***/exec'; // ①のデプロイURL
292
295
 

25

 

2022/05/01 01:23

投稿

退会済みユーザー
test CHANGED
@@ -286,7 +286,7 @@
286
286
  ```
287
287
 
288
288
 
289
- ②改’(実際の処理を行うファイル。こちらを複製。showDialogは①へ移動)
289
+ ②改’(実際の処理を行うファイル。こちらを複製してセラーにつかってもらうセラーは認証フローを行わない前提のため、showDialogは①へ移動)
290
290
  ```js
291
291
  const DEPLOY_URL = 'https://script.google.com/macros/s/***/exec'; // ①のデプロイURL
292
292
 

24

 

2022/05/01 01:22

投稿

退会済みユーザー
test CHANGED
@@ -89,169 +89,6 @@
89
89
  output.setContent(JSON.stringify(content));
90
90
  return output;
91
91
  }
92
- ```
93
-
94
- -----
95
- # 説明 
96
-  
97
- 上記は、実質的には下記の2つのコードを合体したものになります。
98
- ① original.gs
99
- ・認証・認可の処理を行う専用のファイル。
100
- ・アクセストークンを保管するとともに、②からの要求に応じて authorizationUrl やアクセストークンを渡す。
101
- ```js
102
- AUTH_ENDPOINT = 'https://XXX';
103
- TOKEN_ENDPOINT = 'https://YYY';
104
- CLIENT_ID = 'AAA';
105
- CLIENT_SECRET = 'BBB';
106
- APP_ID = 'CCC';
107
-
108
- // OAuth2ライブラリ使用
109
- function getService() {
110
-  略
111
- }
112
-
113
- function authCallback(request) {
114
-  略
115
- }
116
-
117
- function doGet(e) {
118
- if (e.parameter.authmode)
119
- return toJson({ authorizationUrl: getService.getAuthorizationUrl() })
120
-
121
- if (getService.hasAccess())
122
- return toJson({ authorized: true, token: getService.getAccessToken() })
123
-
124
- return toJson({ authorized: false })
125
- }
126
-
127
- function toJson(content) {
128
-  略
129
- }
130
- ```
131
-
132
- ② copy.gs
133
- ・実際の処理を行うファイル
134
- ```js
135
- const DEPLOY_URL = 'https://script.google.com/macros/s/***/exec'; // ①のデプロイURL
136
-
137
- /**
138
- * 認証用ダイアログ(html)表示
139
- * セラーセントラルの認証URLへリンクさせる
140
- */
141
- function showDialog() {
142
- const respjson = UrlFetchApp.fetch(DEPLOY_URL + '?authmode=true').getContentText();
143
- const response = JSON.parse(respjson);
144
- const url = response.authorizationUrl;
145
- const tag_text = `<button type="button" class="btn btn-primary" onclick="window.open('${url}')">セラーセントラルで認証する</button>`;
146
- const html = HtmlService.createHtmlOutput(tag_text);
147
- SpreadsheetApp.getUi().showModalDialog(html, "認証ダイアログ");
148
- }
149
-
150
- /**
151
- * アクセストークンを取得する。
152
- */
153
- function getToken() {
154
- const respjson = UrlFetchApp.fetch(DEPLOY_URL).getContentText();
155
- const response = JSON.parse(respjson);
156
- if (response.authorized) {
157
- return response.token;
158
- } else {
159
- return "UNAUTHORIZED"
160
- }
161
- }
162
- ```
163
-  
164
- 上記のように2つに分けた場合は、①単独では動かず、②の copy.js を複製して使用することを想定しています。
165
- (冒頭に記載したコードは、①と②を合体したものですので、単一のファイルだけで動くはずです)
166
-  
167
- ②で認証・認可が必要になる場面で ①を呼び出して認証・認可に必要な処理を肩代わりさせます。
168
- この過程でアクセストークンを ①の中に保管しておきます。
169
-  
170
- 実際に②がいろいろな処理を行う場面でアクセストークンが必要になった場合は、getToken()によって①からアクセストークンを取得する、という考え方です。
171
-
172
- -----
173
- # 追記
174
-
175
- 他の人にも協力してもらい、いろいろ試しましたが、このスクリプトは下記のような根本的な問題点があるらしいことが分かりました。
176
- ・①を所有しているアカウント以外のアカウントが ②の showDialog を実行した場合、認証フローを完了させることができない(トークンが無効または期限が切れていると表示される)
177
- これは、①と②両方公開ファイルにしても変わりません。
178
- + ①での認証後、①を所有しているアカウント以外のアカウントが ②を利用して①からアクセストークンを受け取り、アクセストークンを利用した処理を行うことは一応可能。
179
- + ①の発行しているアクセストークンが揮発しても、①を所有しているアカウント以外のアカウントは ②を利用中に更新後のアクセストークンを取得できる。
180
-  
181
- したがって、少なくとも最初の認証フローは①を所有しているアカウント(①を作成したアカウント)で行う必要がありそうです。
182
-  
183
- 運用方針として、①と②を分離し、
184
- + ①は開発者/管理者が専有してメンテナンス(最初だけ認証を行ってリフレッシュトークン・アクセストークンをキャッシュしておく)
185
- + 利用者側には②をコピーして使ってもらう(①がアクセストークンを保持している限り②側での認証フローは不要)
186
- というのが現実的かもしれませんね。
187
-  
188
- crient_secret が書かれたファイルをむやみに渡す必要がなくなるというメリットもあると思います。
189
-  
190
- ただし、現状のコードだと、DEPLOY_URLを知られてしまうだけでアクセストークンを取得して勝手にいろいろできてしまうので、何らかの管理のしくみが別途必要かもしれません。
191
- (この点は冒頭に記載した単一ファイルを運用する場合でも同じです。さらに単一ファイルだとclient_secretも明記されてしまっているのが問題)
192
-  
193
- ①改(認証・認可用ファイル。showDialogを元に戻した)
194
- ```js
195
- AUTH_ENDPOINT = 'https://XXX';
196
- TOKEN_ENDPOINT = 'https://YYY';
197
- CLIENT_ID = 'AAA';
198
- CLIENT_SECRET = 'BBB';
199
- APP_ID = 'CCC';
200
-
201
- // OAuth2ライブラリ使用
202
- function getService() {
203
-  略
204
- .setLock(LockService.getUserLock());
205
- }
206
-
207
- function authCallback(request) {
208
-  略
209
- }
210
-
211
- function doGet(e) {
212
- if (e.parameter.authmode)
213
- return toJson({ authorizationUrl: getService.getAuthorizationUrl() })
214
-
215
- if (getService.hasAccess())
216
- return toJson({ authorized: true, token: getService.getAccessToken() })
217
-
218
- return toJson({ authorized: false })
219
- }
220
-
221
- function toJson(content) {
222
-  略
223
- }
224
-
225
- /**
226
- * 認証用ダイアログ(html)表示
227
- * セラーセントラルの認証URLへリンクさせる
228
- */
229
- function showDialog(){
230
- const service = getService();
231
- const url = service.getAuthorizationUrl();
232
- const tag_text = `<button type="button" class="btn btn-primary" onclick="window.open('${url}')">セラーセントラルで認証する</button>`;
233
- const html = HtmlService.createHtmlOutput(tag_text);
234
- SpreadsheetApp.getUi().showModalDialog(html, "認証ダイアログ");
235
- }
236
- ```
237
-
238
-
239
- ②改’(実際の処理を行うファイル。こちらを複製。showDialogは①へ移動)
240
- ```js
241
- const DEPLOY_URL = 'https://script.google.com/macros/s/***/exec'; // ①のデプロイURL
242
-
243
- /**
244
- * アクセストークンを取得する。
245
- */
246
- function getToken() {
247
- const respjson = UrlFetchApp.fetch(DEPLOY_URL).getContentText();
248
- const response = JSON.parse(respjson);
249
- if (response.authorized) {
250
- return response.token;
251
- } else {
252
- return "UNAUTHORIZED"
253
- }
254
- }
255
92
 
256
93
  /*個別処理を行う場合に必要となるアクセストークンは、getToken() で取得する。
257
94
  * 下記は注文を取得する例。
@@ -279,3 +116,216 @@
279
116
  }
280
117
  ```
281
118
 
119
+ -----
120
+ # 説明 
121
+  
122
+ 上記は、実質的には下記の2つのコードを合体したものになります。
123
+ ① original.gs
124
+ ・認証・認可の処理を行う専用のファイル。
125
+ ・アクセストークンを保管するとともに、②からの要求に応じて authorizationUrl やアクセストークンを渡す。
126
+ ```js
127
+ AUTH_ENDPOINT = 'https://XXX';
128
+ TOKEN_ENDPOINT = 'https://YYY';
129
+ CLIENT_ID = 'AAA';
130
+ CLIENT_SECRET = 'BBB';
131
+ APP_ID = 'CCC';
132
+
133
+ // OAuth2ライブラリ使用
134
+ function getService() {
135
+  略
136
+ }
137
+
138
+ function authCallback(request) {
139
+  略
140
+ }
141
+
142
+ function doGet(e) {
143
+ if (e.parameter.authmode)
144
+ return toJson({ authorizationUrl: getService.getAuthorizationUrl() })
145
+
146
+ if (getService.hasAccess())
147
+ return toJson({ authorized: true, token: getService.getAccessToken() })
148
+
149
+ return toJson({ authorized: false })
150
+ }
151
+
152
+ function toJson(content) {
153
+  略
154
+ }
155
+ ```
156
+
157
+ ② copy.gs
158
+ ・実際の処理を行うファイル
159
+ ```js
160
+ const DEPLOY_URL = 'https://script.google.com/macros/s/***/exec'; // ①のデプロイURL
161
+
162
+ /**
163
+ * 認証用ダイアログ(html)表示
164
+ * セラーセントラルの認証URLへリンクさせる
165
+ */
166
+ function showDialog() {
167
+ const respjson = UrlFetchApp.fetch(DEPLOY_URL + '?authmode=true').getContentText();
168
+ const response = JSON.parse(respjson);
169
+ const url = response.authorizationUrl;
170
+ const tag_text = `<button type="button" class="btn btn-primary" onclick="window.open('${url}')">セラーセントラルで認証する</button>`;
171
+ const html = HtmlService.createHtmlOutput(tag_text);
172
+ SpreadsheetApp.getUi().showModalDialog(html, "認証ダイアログ");
173
+ }
174
+
175
+ /**
176
+ * アクセストークンを取得する。
177
+ */
178
+ function getToken() {
179
+ const respjson = UrlFetchApp.fetch(DEPLOY_URL).getContentText();
180
+ const response = JSON.parse(respjson);
181
+ if (response.authorized) {
182
+ return response.token;
183
+ } else {
184
+ return "UNAUTHORIZED"
185
+ }
186
+ }
187
+
188
+ /*個別処理を行う場合に必要となるアクセストークンは、getToken() で取得する。
189
+ * 下記は注文を取得する例。
190
+ */
191
+ function getOrders(){
192
+ const access_token = getToken(); // アクセストークンの取得
193
+ if (access_token==='UNAUTHORIZED) {
194
+ console.log('認証が完了していないためアクセストークンを取得できません。' +
195
+ 管理者に連絡して、認証・認可ファイルで再認証を行ってもらってください。');
196
+ }
197
+
198
+
199
+ const end_point = 'https://sellingpartnerapi-eu.amazon.com';
200
+  略
201
+ const options = {
202
+ 'method': 'GET',
203
+ 'headers': {
204
+ 'x-amz-access-token': access_token,
205
+ 'x-amz-date': isoDate,
206
+ 'Authorization': 'AWS4-HMAC-SHA256 Credential=' + ACCESS_ID + '/' + credential_scope + ', SignedHeaders=' + signedheaders + ', Signature=' + signature,
207
+ }
208
+ }
209
+ const orders = UrlFetchApp.fetch(end_point + canonicalURI + canonicalQueryString, options);
210
+ console.log(orders);
211
+ }
212
+ ```
213
+  
214
+ 上記のように2つに分けた場合は、①単独では動かず、②の copy.js を複製して使用することを想定しています。
215
+ (冒頭に記載したコードは、①と②を合体したものですので、単一のファイルだけで動くはずです)
216
+  
217
+ ②で認証・認可が必要になる場面で ①を呼び出して認証・認可に必要な処理を肩代わりさせます。
218
+ この過程でアクセストークンを ①の中に保管しておきます。
219
+  
220
+ 実際に②がいろいろな処理を行う場面でアクセストークンが必要になった場合は、getToken()によって①からアクセストークンを取得する、という考え方です。
221
+
222
+ -----
223
+ # 追記
224
+
225
+ 他の人にも協力してもらい、いろいろ試しましたが、このスクリプトは下記のような根本的な問題点があるらしいことが分かりました。
226
+ ・①を所有しているアカウント以外のアカウントが ②の showDialog を実行した場合、認証フローを完了させることができない(トークンが無効または期限が切れていると表示される)
227
+ これは、①と②両方公開ファイルにしても変わりません。
228
+ + ①での認証後、①を所有しているアカウント以外のアカウントが ②を利用して①からアクセストークンを受け取り、アクセストークンを利用した処理を行うことは一応可能。
229
+ + ①の発行しているアクセストークンが揮発しても、①を所有しているアカウント以外のアカウントは ②を利用中に更新後のアクセストークンを取得できる。
230
+  
231
+ したがって、少なくとも最初の認証フローは①を所有しているアカウント(①を作成したアカウント)で行う必要がありそうです。
232
+  
233
+ 運用方針として、①と②を分離し、
234
+ + ①は開発者/管理者が専有してメンテナンス(最初だけ認証を行ってリフレッシュトークン・アクセストークンをキャッシュしておく)
235
+ + 利用者側には②をコピーして使ってもらう(①がアクセストークンを保持している限り②側での認証フローは不要)
236
+ というのが現実的かもしれませんね。
237
+  
238
+ crient_secret が書かれたファイルをむやみに渡す必要がなくなるというメリットもあると思います。
239
+  
240
+ ただし、現状のコードだと、DEPLOY_URLを知られてしまうだけでアクセストークンを取得して勝手にいろいろできてしまうので、何らかの管理のしくみが別途必要かもしれません。
241
+ (この点は冒頭に記載した単一ファイルを運用する場合でも同じです。さらに単一ファイルだとclient_secretも明記されてしまっているのが問題)
242
+  
243
+ ①改(認証・認可用ファイル。showDialogを元に戻した)
244
+ ```js
245
+ AUTH_ENDPOINT = 'https://XXX';
246
+ TOKEN_ENDPOINT = 'https://YYY';
247
+ CLIENT_ID = 'AAA';
248
+ CLIENT_SECRET = 'BBB';
249
+ APP_ID = 'CCC';
250
+
251
+ // OAuth2ライブラリ使用
252
+ function getService() {
253
+  略
254
+ .setLock(LockService.getUserLock());
255
+ }
256
+
257
+ function authCallback(request) {
258
+  略
259
+ }
260
+
261
+ function doGet(e) {
262
+ if (e.parameter.authmode)
263
+ return toJson({ authorizationUrl: getService.getAuthorizationUrl() })
264
+
265
+ if (getService.hasAccess())
266
+ return toJson({ authorized: true, token: getService.getAccessToken() })
267
+
268
+ return toJson({ authorized: false })
269
+ }
270
+
271
+ function toJson(content) {
272
+  略
273
+ }
274
+
275
+ /**
276
+ * 認証用ダイアログ(html)表示
277
+ * セラーセントラルの認証URLへリンクさせる
278
+ */
279
+ function showDialog(){
280
+ const service = getService();
281
+ const url = service.getAuthorizationUrl();
282
+ const tag_text = `<button type="button" class="btn btn-primary" onclick="window.open('${url}')">セラーセントラルで認証する</button>`;
283
+ const html = HtmlService.createHtmlOutput(tag_text);
284
+ SpreadsheetApp.getUi().showModalDialog(html, "認証ダイアログ");
285
+ }
286
+ ```
287
+
288
+
289
+ ②改’(実際の処理を行うファイル。こちらを複製。showDialogは①へ移動)
290
+ ```js
291
+ const DEPLOY_URL = 'https://script.google.com/macros/s/***/exec'; // ①のデプロイURL
292
+
293
+ /**
294
+ * アクセストークンを取得する。
295
+ */
296
+ function getToken() {
297
+ const respjson = UrlFetchApp.fetch(DEPLOY_URL).getContentText();
298
+ const response = JSON.parse(respjson);
299
+ if (response.authorized) {
300
+ return response.token;
301
+ } else {
302
+ return "UNAUTHORIZED"
303
+ }
304
+ }
305
+
306
+ /*個別処理を行う場合に必要となるアクセストークンは、getToken() で取得する。
307
+ * 下記は注文を取得する例。
308
+ */
309
+ function getOrders(){
310
+ const access_token = getToken(); // アクセストークンの取得
311
+ if (access_token==='UNAUTHORIZED) {
312
+ console.log('認証が完了していないためアクセストークンを取得できません。' +
313
+ 管理者に連絡して、認証・認可ファイルで再認証を行ってもらってください。');
314
+ }
315
+
316
+
317
+ const end_point = 'https://sellingpartnerapi-eu.amazon.com';
318
+  略
319
+ const options = {
320
+ 'method': 'GET',
321
+ 'headers': {
322
+ 'x-amz-access-token': access_token,
323
+ 'x-amz-date': isoDate,
324
+ 'Authorization': 'AWS4-HMAC-SHA256 Credential=' + ACCESS_ID + '/' + credential_scope + ', SignedHeaders=' + signedheaders + ', Signature=' + signature,
325
+ }
326
+ }
327
+ const orders = UrlFetchApp.fetch(end_point + canonicalURI + canonicalQueryString, options);
328
+ console.log(orders);
329
+ }
330
+ ```
331
+

23

 

2022/05/01 01:20

投稿

退会済みユーザー
test CHANGED
@@ -180,9 +180,9 @@
180
180
   
181
181
  したがって、少なくとも最初の認証フローは①を所有しているアカウント(①を作成したアカウント)で行う必要がありそうです。
182
182
   
183
- 運用方針として、①と②を分離してしまい
183
+ 運用方針として、①と②を分離し、
184
- + ①は開発者/管理者が専有してメンテナンス(最初認証を行ってリフレッシュトークン・アクセストークンをキャッシュしておく)
184
+ + ①は開発者/管理者が専有してメンテナンス(最初だけ認証を行ってリフレッシュトークン・アクセストークンをキャッシュしておく)
185
- + 利用者側には②コピーして使ってもらう(①がアクセストークンを保持している限り②側での認証フローは不要)
185
+ + 利用者側には②コピーして使ってもらう(①がアクセストークンを保持している限り②側での認証フローは不要)
186
186
  というのが現実的かもしれませんね。
187
187
   
188
188
  crient_secret が書かれたファイルをむやみに渡す必要がなくなるというメリットもあると思います。

22

 

2022/04/30 23:41

投稿

退会済みユーザー
test CHANGED
@@ -185,7 +185,7 @@
185
185
  + 利用者側には②コピーして使ってもらう(①がアクセストークンを保持している限り②側での認証フローは不要)
186
186
  というのが現実的かもしれませんね。
187
187
   
188
- crient_secret をむやみに公開必要がなくなるというメリットもあると思います。
188
+ crient_secret が書かれたファイルをむやみにす必要がなくなるというメリットもあると思います。
189
189
   
190
190
  ただし、現状のコードだと、DEPLOY_URLを知られてしまうだけでアクセストークンを取得して勝手にいろいろできてしまうので、何らかの管理のしくみが別途必要かもしれません。
191
191
  (この点は冒頭に記載した単一ファイルを運用する場合でも同じです。さらに単一ファイルだとclient_secretも明記されてしまっているのが問題)

21

 

2022/04/30 23:38

投稿

退会済みユーザー
test CHANGED
@@ -201,6 +201,7 @@
201
201
  // OAuth2ライブラリ使用
202
202
  function getService() {
203
203
   略
204
+ .setLock(LockService.getUserLock());
204
205
  }
205
206
 
206
207
  function authCallback(request) {

20

 

2022/04/30 23:36

投稿

退会済みユーザー
test CHANGED
@@ -188,7 +188,7 @@
188
188
  crient_secret をむやみに公開する必要がなくなるというメリットもあると思います。
189
189
   
190
190
  ただし、現状のコードだと、DEPLOY_URLを知られてしまうだけでアクセストークンを取得して勝手にいろいろできてしまうので、何らかの管理のしくみが別途必要かもしれません。
191
- (この点は冒頭に記載した単一ファイルを運用する場合でも同じです)
191
+ (この点は冒頭に記載した単一ファイルを運用する場合でも同じです。さらに単一ファイルだとclient_secretも明記されてしまっているのが問題
192
192
   
193
193
  ①改(認証・認可用ファイル。showDialogを元に戻した)
194
194
  ```js

19

 

2022/04/30 23:35

投稿

退会済みユーザー
test CHANGED
@@ -187,7 +187,7 @@
187
187
   
188
188
  crient_secret をむやみに公開する必要がなくなるというメリットもあると思います。
189
189
   
190
- ただし、DEPLOY_URLを知られてしまう勝手にいろいろできてしまうので、ユーザー管理のしくみ別途必要かもしれません。
190
+ ただし、現状のコードだと、DEPLOY_URLを知られてしまうだけでアクセストークンを取得して勝手にいろいろできてしまうので、何らかの管理のしくみ別途必要かもしれません。
191
191
  (この点は冒頭に記載した単一ファイルを運用する場合でも同じです)
192
192
   
193
193
  ①改(認証・認可用ファイル。showDialogを元に戻した)

18

 

2022/04/30 23:33

投稿

退会済みユーザー
test CHANGED
@@ -177,15 +177,16 @@
177
177
  これは、①と②両方公開ファイルにしても変わりません。
178
178
  + ①での認証後、①を所有しているアカウント以外のアカウントが ②を利用して①からアクセストークンを受け取り、アクセストークンを利用した処理を行うことは一応可能。
179
179
  + ①の発行しているアクセストークンが揮発しても、①を所有しているアカウント以外のアカウントは ②を利用中に更新後のアクセストークンを取得できる。
180
-
181
- したがって、
180
+  
182
- 少なくとも最初の認証フローは①を所有しているアカウント(①を作成したアカウント)で行う必要がありそうです。
181
+ したがって、少なくとも最初の認証フローは①を所有しているアカウント(①を作成したアカウント)で行う必要がありそうです。
182
+  
183
- ①と②の運用完全に分離し、
183
+ 運用方針として、①と②を分離してしまい
184
- + ①は開発者が専有してメンテナンス(最初に認証を行ってリフレッシュトークン・アクセストークンをキャッシュ)
184
+ + ①は開発者/管理者が専有してメンテナンス(最初に認証を行ってリフレッシュトークン・アクセストークンをキャッシュしておく
185
185
  + 利用者側には②コピーして使ってもらう(①がアクセストークンを保持している限り②側での認証フローは不要)
186
- というのが現実的かもしれませんね。
186
+ というのが現実的かもしれませんね。
187
187
   
188
188
  crient_secret をむやみに公開する必要がなくなるというメリットもあると思います。
189
+  
189
190
  ただし、DEPLOY_URLを知られてしまうと勝手にいろいろできてしまうので、ユーザー管理のしくみは別途必要かもしれません。
190
191
  (この点は冒頭に記載した単一ファイルを運用する場合でも同じです)
191
192
   

17

 

2022/04/30 23:31

投稿

退会済みユーザー
test CHANGED
@@ -175,14 +175,20 @@
175
175
  他の人にも協力してもらい、いろいろ試しましたが、このスクリプトは下記のような根本的な問題点があるらしいことが分かりました。
176
176
  ・①を所有しているアカウント以外のアカウントが ②の showDialog を実行した場合、認証フローを完了させることができない(トークンが無効または期限が切れていると表示される)
177
177
  これは、①と②両方公開ファイルにしても変わりません。
178
- ①での認証後、①を所有しているアカウント以外のアカウントが ②を利用して①からアクセストークンを受け取り、アクセストークンを利用した処理を行うことは一応可能。
178
+ + ①での認証後、①を所有しているアカウント以外のアカウントが ②を利用して①からアクセストークンを受け取り、アクセストークンを利用した処理を行うことは一応可能。
179
- ①を所有しているアカウント以外のアカウント ②を利用中にアクセストークンを更新できる
179
+ + の発行しているアクセストークンが揮発しても、①を所有しているアカウント以外のアカウント ②を利用中に更新後のアクセストークンを取得できる
180
- ~~についてはまだ確認できていません。~~ →更新できているようです。
181
180
 
182
181
  したがって、
183
182
  少なくとも最初の認証フローは①を所有しているアカウント(①を作成したアカウント)で行う必要がありそうです。
183
+ ①と②の運用を完全に分離し、
184
- と②の運用を完全に分離し、①は開発者側が専有してメンテナンス(最初に認証を行ってリフレッシュトークン・アクセストークンをキャッシュ)、利用者側には②を使ってもらう(①がアクセストークンを保持している限り②側での認証フローは不要)、というのが現実的かもしれませんね。
184
+ + ①は開発者側が専有してメンテナンス(最初に認証を行ってリフレッシュトークン・アクセストークンをキャッシュ)
185
-
185
+ + 利用者側には②コピーして使ってもらう(①がアクセストークンを保持している限り②側での認証フローは不要)
186
+ 、というのが現実的かもしれませんね。
187
+  
188
+ crient_secret をむやみに公開する必要がなくなるというメリットもあると思います。
189
+ ただし、DEPLOY_URLを知られてしまうと勝手にいろいろできてしまうので、ユーザー管理のしくみは別途必要かもしれません。
190
+ (この点は冒頭に記載した単一ファイルを運用する場合でも同じです)
191
+  
186
192
  ①改(認証・認可用ファイル。showDialogを元に戻した)
187
193
  ```js
188
194
  AUTH_ENDPOINT = 'https://XXX';

16

 

2022/04/30 23:26

投稿

退会済みユーザー
test CHANGED
@@ -266,7 +266,7 @@
266
266
  'Authorization': 'AWS4-HMAC-SHA256 Credential=' + ACCESS_ID + '/' + credential_scope + ', SignedHeaders=' + signedheaders + ', Signature=' + signature,
267
267
  }
268
268
  }
269
- consr orders = UrlFetchApp.fetch(end_point + canonicalURI + canonicalQueryString, options);
269
+ const orders = UrlFetchApp.fetch(end_point + canonicalURI + canonicalQueryString, options);
270
270
  console.log(orders);
271
271
  }
272
272
  ```

15

 

2022/04/30 23:25

投稿

退会済みユーザー
test CHANGED
@@ -250,6 +250,10 @@
250
250
  */
251
251
  function getOrders(){
252
252
  const access_token = getToken(); // アクセストークンの取得
253
+ if (access_token==='UNAUTHORIZED) {
254
+ console.log('認証が完了していないためアクセストークンを取得できません。' +
255
+ 管理者に連絡して、認証・認可ファイルで再認証を行ってもらってください。');
256
+ }
253
257
 
254
258
 
255
259
  const end_point = 'https://sellingpartnerapi-eu.amazon.com';

14

 

2022/04/30 23:22

投稿

退会済みユーザー
test CHANGED
@@ -182,3 +182,88 @@
182
182
  したがって、
183
183
  少なくとも最初の認証フローは①を所有しているアカウント(①を作成したアカウント)で行う必要がありそうです。
184
184
  ①と②の運用を完全に分離し、①は開発者側が専有してメンテナンス(最初に認証を行ってリフレッシュトークン・アクセストークンをキャッシュ)、利用者側には②を使ってもらう(①がアクセストークンを保持している限り②側での認証フローは不要)、というのが現実的かもしれませんね。
185
+
186
+ ①改(認証・認可用ファイル。showDialogを元に戻した)
187
+ ```js
188
+ AUTH_ENDPOINT = 'https://XXX';
189
+ TOKEN_ENDPOINT = 'https://YYY';
190
+ CLIENT_ID = 'AAA';
191
+ CLIENT_SECRET = 'BBB';
192
+ APP_ID = 'CCC';
193
+
194
+ // OAuth2ライブラリ使用
195
+ function getService() {
196
+  略
197
+ }
198
+
199
+ function authCallback(request) {
200
+  略
201
+ }
202
+
203
+ function doGet(e) {
204
+ if (e.parameter.authmode)
205
+ return toJson({ authorizationUrl: getService.getAuthorizationUrl() })
206
+
207
+ if (getService.hasAccess())
208
+ return toJson({ authorized: true, token: getService.getAccessToken() })
209
+
210
+ return toJson({ authorized: false })
211
+ }
212
+
213
+ function toJson(content) {
214
+  略
215
+ }
216
+
217
+ /**
218
+ * 認証用ダイアログ(html)表示
219
+ * セラーセントラルの認証URLへリンクさせる
220
+ */
221
+ function showDialog(){
222
+ const service = getService();
223
+ const url = service.getAuthorizationUrl();
224
+ const tag_text = `<button type="button" class="btn btn-primary" onclick="window.open('${url}')">セラーセントラルで認証する</button>`;
225
+ const html = HtmlService.createHtmlOutput(tag_text);
226
+ SpreadsheetApp.getUi().showModalDialog(html, "認証ダイアログ");
227
+ }
228
+ ```
229
+
230
+
231
+ ②改’(実際の処理を行うファイル。こちらを複製。showDialogは①へ移動)
232
+ ```js
233
+ const DEPLOY_URL = 'https://script.google.com/macros/s/***/exec'; // ①のデプロイURL
234
+
235
+ /**
236
+ * アクセストークンを取得する。
237
+ */
238
+ function getToken() {
239
+ const respjson = UrlFetchApp.fetch(DEPLOY_URL).getContentText();
240
+ const response = JSON.parse(respjson);
241
+ if (response.authorized) {
242
+ return response.token;
243
+ } else {
244
+ return "UNAUTHORIZED"
245
+ }
246
+ }
247
+
248
+ /*個別処理を行う場合に必要となるアクセストークンは、getToken() で取得する。
249
+ * 下記は注文を取得する例。
250
+ */
251
+ function getOrders(){
252
+ const access_token = getToken(); // アクセストークンの取得
253
+
254
+
255
+ const end_point = 'https://sellingpartnerapi-eu.amazon.com';
256
+  略
257
+ const options = {
258
+ 'method': 'GET',
259
+ 'headers': {
260
+ 'x-amz-access-token': access_token,
261
+ 'x-amz-date': isoDate,
262
+ 'Authorization': 'AWS4-HMAC-SHA256 Credential=' + ACCESS_ID + '/' + credential_scope + ', SignedHeaders=' + signedheaders + ', Signature=' + signature,
263
+ }
264
+ }
265
+ consr orders = UrlFetchApp.fetch(end_point + canonicalURI + canonicalQueryString, options);
266
+ console.log(orders);
267
+ }
268
+ ```
269
+

13

 

2022/04/30 22:33

投稿

退会済みユーザー
test CHANGED
@@ -181,4 +181,4 @@
181
181
 
182
182
  したがって、
183
183
  少なくとも最初の認証フローは①を所有しているアカウント(①を作成したアカウント)で行う必要がありそうです。
184
- ①と②の運用を完全に分離し、①は開発者側が専有してメンテナンス、利用者側に②を使ってもらう、というのが現実的かもしれまsね。
184
+ ①と②の運用を完全に分離し、①は開発者側が専有してメンテナンス(最初に認証を行ってリフレッシュトークン・アクセストークンをキャッシュ)、利用者側に②を使ってもらう(①がアクセストークンを保持している限り②側での認証フローは不要)、というのが現実的かもしれませんね。

12

 

2022/04/30 14:59

投稿

退会済みユーザー
test CHANGED
@@ -176,6 +176,9 @@
176
176
  ・①を所有しているアカウント以外のアカウントが ②の showDialog を実行した場合、認証フローを完了させることができない(トークンが無効または期限が切れていると表示される)
177
177
  これは、①と②両方公開ファイルにしても変わりません。
178
178
  ・①での認証後、①を所有しているアカウント以外のアカウントが ②を利用して①からアクセストークンを受け取り、アクセストークンを利用した処理を行うことは一応可能。
179
- ・①を所有しているアカウント以外のアカウントが ②を利用中にアクセストークンを更新できるかについてはまだ確認できていません。
179
+ ・①を所有しているアカウント以外のアカウントが ②を利用中にアクセストークンを更新できるか
180
+ ~~についてはまだ確認できていません。~~ →更新できているようです。
180
181
 
182
+ したがって、
181
- したがって、少なくとも最初の認証フローは①を所有しているアカウント(①を作成したアカウント)で行う必要がありそうです。
183
+ 少なくとも最初の認証フローは①を所有しているアカウント(①を作成したアカウント)で行う必要がありそうです。
184
+ ①と②の運用を完全に分離し、①は開発者側が専有してメンテナンス、利用者側に②を使ってもらう、というのが現実的かもしれまsね。

11

 

2022/04/30 12:05

投稿

退会済みユーザー
test CHANGED
@@ -174,6 +174,7 @@
174
174
 
175
175
  他の人にも協力してもらい、いろいろ試しましたが、このスクリプトは下記のような根本的な問題点があるらしいことが分かりました。
176
176
  ・①を所有しているアカウント以外のアカウントが ②の showDialog を実行した場合、認証フローを完了させることができない(トークンが無効または期限が切れていると表示される)
177
+ これは、①と②両方公開ファイルにしても変わりません。
177
178
  ・①での認証後、①を所有しているアカウント以外のアカウントが ②を利用して①からアクセストークンを受け取り、アクセストークンを利用した処理を行うことは一応可能。
178
179
  ・①を所有しているアカウント以外のアカウントが ②を利用中にアクセストークンを更新できるかについてはまだ確認できていません。
179
180
 

10

追記

2022/04/30 12:04

投稿

退会済みユーザー
test CHANGED
@@ -169,3 +169,12 @@
169
169
   
170
170
  実際に②がいろいろな処理を行う場面でアクセストークンが必要になった場合は、getToken()によって①からアクセストークンを取得する、という考え方です。
171
171
 
172
+ -----
173
+ # 追記
174
+
175
+ 他の人にも協力してもらい、いろいろ試しましたが、このスクリプトは下記のような根本的な問題点があるらしいことが分かりました。
176
+ ・①を所有しているアカウント以外のアカウントが ②の showDialog を実行した場合、認証フローを完了させることができない(トークンが無効または期限が切れていると表示される)
177
+ ・①での認証後、①を所有しているアカウント以外のアカウントが ②を利用して①からアクセストークンを受け取り、アクセストークンを利用した処理を行うことは一応可能。
178
+ ・①を所有しているアカウント以外のアカウントが ②を利用中にアクセストークンを更新できるかについてはまだ確認できていません。
179
+
180
+ したがって、少なくとも最初の認証フローは①を所有しているアカウント(①を作成したアカウント)で行う必要がありそうです。

9

2022/04/30 11:51

投稿

退会済みユーザー
test CHANGED
@@ -8,7 +8,11 @@
8
8
   
9
9
  + セラーセントラルのAPI登録画面でのリダイレクトURIは、コピー元のcallbackから変更する必要はありません。
10
10
   
11
+ + 複数ユーザーの同時アクセスに対応するためgetService関数の中でロックを設定しています。( [参照](https://github.com/googleworkspace/apps-script-oauth2#locking) )
12
+ ※実際にはその他の処理でも複数ユーザーによる競合が想定される部分には、ロックをかける必要があるかもしれません。
11
13
  DEPLOY_URLを追加しているほか、showDialog() も一部修正しています。
14
+
15
+
12
16
  ```js
13
17
  AUTH_ENDPOINT = 'https://XXX';
14
18
  他...
@@ -20,6 +24,7 @@
20
24
  // OAuth2ライブラリ使用
21
25
  function getService() {
22
26
   略
27
+ .setLock(LockService.getUserLock()); // 複数ユーザーが同時にトークンをリフレッシュしようとする可能性があるためロックを設定。
23
28
  }
24
29
 
25
30
  /**

8

 

2022/04/30 11:20

投稿

退会済みユーザー
test CHANGED
@@ -59,14 +59,14 @@
59
59
  }
60
60
 
61
61
  /**
62
- * GETリクエスト時に呼ばれる。
62
+ * クライアントからGETリクエストを受けた時に呼ばれる。
63
63
  * @return : JSON string
64
64
  * 呼び出し元に「authmode」パラメータが存在する場合
65
65
  *  {"authorizationUrl : 認可URL}
66
66
  * 呼び出し元に「authmode」パラメータが存在せず、認可済みの場合
67
67
  *   {"anthorized" : true, "token" : アクセストークン}
68
68
  * 呼び出し元に「authmode」パラメータが存在せず、未認可の場合
69
- * {"authorized" : "false"}
69
+ * {"authorized" : false}
70
70
  */
71
71
  function doGet(e) {
72
72
  if (e.parameter.authmode)

7

 

2022/04/30 10:48

投稿

退会済みユーザー
test CHANGED
@@ -92,7 +92,7 @@
92
92
  上記は、実質的には下記の2つのコードを合体したものになります。
93
93
  ① original.gs
94
94
  ・認証・認可の処理を行う専用のファイル。
95
- ・アクセストークンを保管するとともに、②からの要求に応じてトークンを渡す。
95
+ ・アクセストークンを保管するとともに、②からの要求に応じて authorizationUrl やアクセストークンを渡す。
96
96
  ```js
97
97
  AUTH_ENDPOINT = 'https://XXX';
98
98
  TOKEN_ENDPOINT = 'https://YYY';

6

 

2022/04/30 10:47

投稿

退会済みユーザー
test CHANGED
@@ -91,6 +91,8 @@
91
91
   
92
92
  上記は、実質的には下記の2つのコードを合体したものになります。
93
93
  ① original.gs
94
+ ・認証・認可の処理を行う専用のファイル。
95
+ ・アクセストークンを保管するとともに、②からの要求に応じてトークンを渡す。
94
96
  ```js
95
97
  AUTH_ENDPOINT = 'https://XXX';
96
98
  TOKEN_ENDPOINT = 'https://YYY';
@@ -123,6 +125,7 @@
123
125
  ```
124
126
 
125
127
  ② copy.gs
128
+ ・実際の処理を行うファイル
126
129
  ```js
127
130
  const DEPLOY_URL = 'https://script.google.com/macros/s/***/exec'; // ①のデプロイURL
128
131
 

5

 

2022/04/30 10:44

投稿

退会済みユーザー
test CHANGED
@@ -157,7 +157,6 @@
157
157
  (冒頭に記載したコードは、①と②を合体したものですので、単一のファイルだけで動くはずです)
158
158
   
159
159
  ②で認証・認可が必要になる場面で ①を呼び出して認証・認可に必要な処理を肩代わりさせます。
160
- ( たとえば、showDialog関数内で取得している authorizationUrl のリダイレクト先は①になっています)
161
160
  この過程でアクセストークンを ①の中に保管しておきます。
162
161
   
163
162
  実際に②がいろいろな処理を行う場面でアクセストークンが必要になった場合は、getToken()によって①からアクセストークンを取得する、という考え方です。

4

 

2022/04/30 10:43

投稿

退会済みユーザー
test CHANGED
@@ -157,6 +157,7 @@
157
157
  (冒頭に記載したコードは、①と②を合体したものですので、単一のファイルだけで動くはずです)
158
158
   
159
159
  ②で認証・認可が必要になる場面で ①を呼び出して認証・認可に必要な処理を肩代わりさせます。
160
+ ( たとえば、showDialog関数内で取得している authorizationUrl のリダイレクト先は①になっています)
160
161
  この過程でアクセストークンを ①の中に保管しておきます。
161
162
   
162
163
  実際に②がいろいろな処理を行う場面でアクセストークンが必要になった場合は、getToken()によって①からアクセストークンを取得する、という考え方です。

3

 

2022/04/30 10:41

投稿

退会済みユーザー
test CHANGED
@@ -156,7 +156,7 @@
156
156
  上記のように2つに分けた場合は、①単独では動かず、②の copy.js を複製して使用することを想定しています。
157
157
  (冒頭に記載したコードは、①と②を合体したものですので、単一のファイルだけで動くはずです)
158
158
   
159
- ②で認証が必要になる場面で ①を呼び出して認証処理を肩代わりさせます。
159
+ ②で認証・認可が必要になる場面で ①を呼び出して認証・認可に必要な処理を肩代わりさせます。
160
160
  この過程でアクセストークンを ①の中に保管しておきます。
161
161
   
162
162
  実際に②がいろいろな処理を行う場面でアクセストークンが必要になった場合は、getToken()によって①からアクセストークンを取得する、という考え方です。

2

 

2022/04/30 10:38

投稿

退会済みユーザー
test CHANGED
@@ -124,7 +124,7 @@
124
124
 
125
125
  ② copy.gs
126
126
  ```js
127
- const DEPLOY_URL = 'https://script.google.com/macros/s/***/exec'; // コピー元のデプロイURL
127
+ const DEPLOY_URL = 'https://script.google.com/macros/s/***/exec'; // のデプロイURL
128
128
 
129
129
  /**
130
130
  * 認証用ダイアログ(html)表示

1

 

2022/04/30 10:30

投稿

退会済みユーザー
test CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  + 逆に、コピー元のデプロイURLが変わってしまった場合は、コピー先ファイルに記載されているDEPLOY_URLを全部そのURLに修正しなければなりません。
6
6
   
7
- + アクセストークンを使うときは、その都度、getToken() を呼び出してください。
7
+ + **アクセストークンを使うときは、その都度、getToken() を呼び出してください**
8
8
   
9
9
  + セラーセントラルのAPI登録画面でのリダイレクトURIは、コピー元のcallbackから変更する必要はありません。
10
10
   
@@ -89,7 +89,7 @@
89
89
  -----
90
90
  # 説明 
91
91
   
92
- 上記は、実質的に下記の2つのコードを合したものになります。
92
+ 上記は、実質的に下記の2つのコードを合したものになります。
93
93
  ① original.gs
94
94
  ```js
95
95
  AUTH_ENDPOINT = 'https://XXX';
@@ -154,7 +154,7 @@
154
154
  ```
155
155
   
156
156
  上記のように2つに分けた場合は、①単独では動かず、②の copy.js を複製して使用することを想定しています。
157
- 最初のコードの場合は、①と②を合体しているので、単一のファイルだけで動くはずです)
157
+ 冒頭に記載したコードは、①と②を合体したものですので、単一のファイルだけで動くはずです)
158
158
   
159
159
  ②で認証が必要になる場面で ①を呼び出して認証処理を肩代わりさせます。
160
160
  この過程でアクセストークンを ①の中に保管しておきます。