{"id":44,"date":"2026-08-02T22:07:59","date_gmt":"2026-08-02T13:07:59","guid":{"rendered":"https:\/\/www.ysharada.com\/?p=44"},"modified":"2026-08-02T22:07:59","modified_gmt":"2026-08-02T13:07:59","slug":"m365%e3%81%a7oauth2%ef%bc%8foidc%e8%aa%8d%e5%8f%af%e3%82%b3%e3%83%bc%e3%83%89%e3%83%95%e3%83%ad%e3%83%bc%e3%82%b5%e3%83%b3%e3%83%97%e3%83%ab%e3%82%92%e4%bd%9c%e6%88%90","status":"publish","type":"post","link":"https:\/\/www.ysharada.com\/?p=44","title":{"rendered":"M365\u3067OAUTH2\uff0fOIDC\u8a8d\u53ef\u30b3\u30fc\u30c9\u30d5\u30ed\u30fc\u30b5\u30f3\u30d7\u30eb\u3092\u4f5c\u6210"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">\u69cb\u6210\u30a4\u30e1\u30fc\u30b8<br>React SPA<br>\u3000\u3000\u2193<br>\u3000\u3000\u2193 \u8a8d\u53ef\u30b3\u30fc\u30c9\u30d5\u30ed\u30fc(PKCE)<br>\u3000\u3000\u2193<br>Microsoft Entra ID<br>\u3000\u3000\u2193<br>\u3000\u3000\u2193 Access Token<br>\u3000\u3000\u2193<br>Microsoft Graph<\/p>\n\n\n\n<h4 class=\"wp-block-heading\">\u4f5c\u6210\u624b\u9806<\/h4>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>1.Entra ID \u5074\u8a2d\u5b9a<\/strong><br>\u30a2\u30d7\u30ea\u306e\u767b\u9332<br>\u540d\u524d : spa-demo<br>Supported account types : Accounts in this organizational directory only<br>Redirect URI :<br>\u3000\u30d7\u30e9\u30c3\u30c8\u30d5\u30a9\u30fc\u30e0 : Single-page application (SPA)<br>\u3000URI : http:\/\/localhost:5173<br>\u3000\u203bCRA\u306e\u5834\u5408\u3000URI : http:\/\/localhost:3000<br>API Permissions\u3000\u59d4\u4efb\uff08\u30e6\u30fc\u30b6\u30fc\u540c\u610f\uff09<br>\u3000Microsoft Graph &#8211; User.Read<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>2.\u30d7\u30ed\u30b8\u30a7\u30af\u30c8\u4f5c\u6210<\/strong><br>npm create vite@latest spa-demo &#8212; &#8211;template react<br>cd spa-demo<br>npm install<br>npm install @azure\/msal-browser @azure\/msal-react<br>\u203bCRA\u306e\u5834\u5408<br>npx create-react-app spa-demo<br>cd spa-demo<br>npm install @azure\/msal-browser @azure\/msal-react<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>3.\u30c7\u30a3\u30ec\u30af\u30c8\u30ea\u69cb\u6210<\/strong><br>\u3000\u3000src\/<br>\u3000\u3000\u251c\u2500 main.jsx<br>\u3000\u3000\u251c\u2500 App.jsx<br>\u3000\u3000\u2514\u2500 authConfig.js<\/p>\n\n\n\n<ol class=\"wp-block-list\"><\/ol>\n\n\n\n<ol start=\"2\" class=\"wp-block-list\"><\/ol>\n\n\n\n<ol start=\"3\" class=\"wp-block-list\"><\/ol>\n\n\n\n<div class=\"wp-block-group\"><div class=\"wp-block-group__inner-container is-layout-constrained wp-block-group-is-layout-constrained\">\n<p class=\"wp-block-paragraph\"><strong>4.authConfig.js<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>export const msalConfig = {\n  auth: {\n    clientId: import.meta.env.VITE_CLIENT_ID,\n    authority: `https:\/\/login.microsoftonline.com\/${import.meta.env.VITE_TENANT_ID}`,\n    redirectUri: \"http:\/\/localhost:5173\"\n  }\n};\n\nexport const loginRequest = {\n  scopes: &#91;\"User.Read\"]\n};<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>5.main.jsx<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import React from \"react\";\nimport ReactDOM from \"react-dom\/client\";\n\nimport { PublicClientApplication } from \"@azure\/msal-browser\";\nimport { MsalProvider } from \"@azure\/msal-react\";\n\nimport App from \".\/App\";\nimport { msalConfig } from \".\/authConfig\";\n\nconst msalInstance =\n  new PublicClientApplication(msalConfig);\n\nReactDOM.createRoot(document.getElementById(\"root\")).render(\n  &lt;React.StrictMode>\n    &lt;MsalProvider instance={msalInstance}>\n      &lt;App \/>\n    &lt;\/MsalProvider>\n  &lt;\/React.StrictMode>\n);<\/code><\/pre>\n<\/div><\/div>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>6.App.js<\/strong><\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>import React, { useState } from \"react\";\n\nimport { useMsal } from \"@azure\/msal-react\";\nimport { loginRequest } from \".\/authConfig\";\n\nfunction App() {\n  const { instance, accounts } = useMsal();\n\n  const &#91;userInfo, setUserInfo] = useState(null);\n\n  const signIn = async () => {\n    try {\n      await instance.loginPopup(loginRequest);\n    } catch (error) {\n      console.error(error);\n    }\n  };\n\n  const getProfile = async () => {\n    try {\n      const response =\n        await instance.acquireTokenSilent({\n          ...loginRequest,\n          account: accounts&#91;0]\n        });\n\n      const graphResponse = await fetch(\n        \"https:\/\/graph.microsoft.com\/v1.0\/me\",\n        {\n          headers: {\n            Authorization: `Bearer ${response.accessToken}`\n          }\n        }\n      );\n\n      const data = await graphResponse.json();\n\n      setUserInfo(data);\n    } catch (error) {\n      console.error(error);\n    }\n  };\n\n  return (\n    &lt;div style={{ padding: \"20px\" }}>\n      &lt;h1>MSAL React Demo&lt;\/h1>\n\n      &lt;button onClick={signIn}>\n        Sign In\n      &lt;\/button>\n\n      &lt;button onClick={getProfile}>\n        Get Profile\n      &lt;\/button>\n\n      {userInfo &amp;&amp; (\n        &lt;div>\n          &lt;h3>User Info&lt;\/h3>\n\n          &lt;p>Name: {userInfo.displayName}&lt;\/p>\n\n          &lt;p>Mail: {userInfo.mail}&lt;\/p>\n\n          &lt;p>UPN: {userInfo.userPrincipalName}&lt;\/p>\n        &lt;\/div>\n      )}\n    &lt;\/div>\n  );\n}\n\nexport default App;<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>7.\u5b9f\u884c<\/strong><br>\u3000vite\u306e\u5834\u5408<br>\u3000\u3000npm run dev<br>\u3000\u3000\u30a2\u30af\u30bb\u30b9: http:\/\/localhost:5173<br>\u3000CRA\u306e\u5834\u5408<br>\u3000\u3000npm start<br>\u3000\u3000\u30a2\u30af\u30bb\u30b9: http:\/\/localhost:3000<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><strong>8.\u5b9f\u969b\u306e\u8a8d\u53ef\u30b3\u30fc\u30c9\u30d5\u30ed\u30fc<\/strong><br>\u8a8d\u53ef\u8981\u6c42<br>GET<br>\u3000\/oauth2\/v2.0\/authorize<br>\u3000\u2193<br>code\u53d6\u5f97<br>\u3000?code=xxxxxxxxxxxxx<br>\u3000\u2193<br>\u30c8\u30fc\u30af\u30f3\u53d6\u5f97<br>\u3000{<br>\u3000&#8221;access_token&#8221;: &#8220;\u2026&#8221;,<br>\u3000&#8221;id_token&#8221;: &#8220;\u2026&#8221;,<br>\u3000&#8221;refresh_token&#8221;: &#8220;\u2026&#8221;<br>\u3000}<br>\u203bSPA\u3067\u306f\u5185\u90e8\u7684\u306bPKCE\u4ed8\u304d\u8a8d\u53ef\u30b3\u30fc\u30c9\u30d5\u30ed\u30fc\u304c\u4f7f\u7528\u3055\u308c\u307e\u3059\u3002<\/p>\n\n\n\n<ol start=\"7\" class=\"wp-block-list\"><\/ol>\n\n\n\n<ol start=\"8\" class=\"wp-block-list\"><\/ol>\n\n\n\n<p class=\"wp-block-paragraph\"><\/p>\n","protected":false},"excerpt":{"rendered":"<p>\u69cb\u6210\u30a4\u30e1\u30fc\u30b8React SPA\u3000\u3000\u2193\u3000\u3000\u2193 \u8a8d\u53ef\u30b3\u30fc\u30c9\u30d5\u30ed\u30fc(PKCE)\u3000\u3000\u2193Microsoft Entra ID\u3000\u3000\u2193\u3000\u3000\u2193 Access Token\u3000\u3000\u2193Microsoft Graph \u4f5c\u6210\u624b\u9806 1.Entra ID&hellip; <a class=\"more-link\" href=\"https:\/\/www.ysharada.com\/?p=44\">\u7d9a\u304d\u3092\u8aad\u3080 <span class=\"screen-reader-text\">M365\u3067OAUTH2\uff0fOIDC\u8a8d\u53ef\u30b3\u30fc\u30c9\u30d5\u30ed\u30fc\u30b5\u30f3\u30d7\u30eb\u3092\u4f5c\u6210<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[6],"tags":[],"class_list":["post-44","post","type-post","status-publish","format-standard","hentry","category-m365","entry"],"_links":{"self":[{"href":"https:\/\/www.ysharada.com\/index.php?rest_route=\/wp\/v2\/posts\/44","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.ysharada.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.ysharada.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.ysharada.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.ysharada.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=44"}],"version-history":[{"count":2,"href":"https:\/\/www.ysharada.com\/index.php?rest_route=\/wp\/v2\/posts\/44\/revisions"}],"predecessor-version":[{"id":47,"href":"https:\/\/www.ysharada.com\/index.php?rest_route=\/wp\/v2\/posts\/44\/revisions\/47"}],"wp:attachment":[{"href":"https:\/\/www.ysharada.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=44"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.ysharada.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=44"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.ysharada.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=44"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}