シングルページアプリケーションを作成されているということで、良いでしょうか?
当該エラーはブラウザからCORSアクセス時に付与されるOrigin
ヘッダが無いと発生するようです。
fetch のオプションにmode:'cors'
を付与することでトークンが取得できると思います。
(もし、サーバ側でトークンを扱いたいのであれば、通常のWebアプリケーションフローで大丈夫です。)
下記、私が試したコードです。CLIENT_ID
やテナント名を埋めていただき、CALLBACK_URI
でアクセスできるように配置すれば動きます。
※AADに登録されているCALLBACK_URI
と異なると、怒られます。
なお、エラーチェック等は省いています。
html
1 <! DOCTYPE html >
2 < html >
3 < head >
4 < meta charset = " utf8 " />
5 < title > example </ title >
6 </ head >
7 < body >
8 < pre > </ pre >
9 < script >
10 // 認可エンドポイント
11 const AUTH_ENDPOINT = 'https://login.microsoftonline.com/<テナント名>.onmicrosoft.com/oauth2/v2.0/authorize' ;
12 // トークンエンドポイント
13 const TOKEN_ENDPOINT = 'https://login.microsoftonline.com/<テナント名>.onmicrosoft.com/oauth2/v2.0/token' ;
14 // クライアントID
15 const CLIENT_ID = '<クライアントIDを埋めてください>' ;
16 // リダイレクトURI
17 const REDIRECT_URI = 'http://localhost:8080/' ;
18 // スコープ
19 const SCOPE = 'https://graph.microsoft.com/User.Read' ;
20 // コードチャレンジ 本当はコードベリファイアから計算 (RFC 7636に記載のテスト用のものを利用)
21 // [Appendix B. Example for the S256 code_challenge_method](https://tools.ietf.org/html/rfc7636#appendix-B)
22 const CODE_CHALLENGE = 'E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM' ;
23 const CODE_CHALLENGE_METHOD = 'S256' ;
24 // コードチャレンジ 本当は都度生成
25 // [Appendix B. Example for the S256 code_challenge_method](https://tools.ietf.org/html/rfc7636#appendix-B)
26 const CODE_VERIFIER = 'dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk' ; // RFC 7636
27
28 ( async ( ) => {
29 if ( ! location . hash || location . hash == '#' ) {
30 // hashが無い...コールバック前
31
32 const url = new URL ( AUTH_ENDPOINT ) ;
33 const params = url . searchParams ;
34
35 // クエリパラメータへ追加
36 params . set ( 'client_id' , CLIENT_ID ) ;
37 params . set ( 'response_type' , 'code' ) ;
38 params . set ( 'redirect_uri' , REDIRECT_URI ) ;
39 params . set ( 'response_mode' , 'fragment' ) ;
40 params . set ( 'scope' , SCOPE ) ;
41 params . set ( 'code_challenge' , CODE_CHALLENGE ) ;
42 params . set ( 'code_challenge_method' , CODE_CHALLENGE_METHOD ) ;
43
44 // 認可エンドポイントへ画面遷移
45 location . assign ( url ) ;
46
47 } else {
48 // 認可エンドポイントからのコールバック後
49
50 const hash = location . hash . slice ( 1 ) ; // '#'を取り除く
51 location . hash = '' ; // URLバーの#以降をクリア
52 const params = new URLSearchParams ( hash ) ;
53 // 認可コード取得
54 const code = params . get ( "code" ) ;
55
56 const body = new URLSearchParams ( ) ;
57 body . append ( 'client_id' , CLIENT_ID ) ;
58 body . append ( 'scope' , SCOPE ) ;
59 body . append ( 'code' , code ) ;
60 body . append ( 'redirect_uri' , REDIRECT_URI ) ;
61 body . append ( 'grant_type' , 'authorization_code' ) ;
62 body . append ( 'code_verifier' , CODE_VERIFIER ) ;
63
64 // トークン取得
65 const response = await fetch ( TOKEN_ENDPOINT , {
66 method : 'POST' ,
67 mode : 'cors' , // CORSでアクセス
68 body ,
69 } ) ;
70 const token = await response . json ( ) ;
71 document . querySelector ( 'pre' ) . textContent = JSON . stringify ( token , null , 2 ) ;
72 }
73 } ) ( ) ;
74 </ script >
75 </ body >
76 </ html >
77 <!-- vim:set ts=2 sts=2 sw=2: -->
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。