分享方式:


Microsoft 身分識別平台和 OAuth 2.0 隱含授與流程

Microsoft 身分識別平台支援 OAuth 2.0 規格中所述的 OAuth 2.0 隱含授與流程。 隱含授與的定義特性是權杖 (識別碼權杖或存取權杖) 會直接從 /authorize 端點 (而非 /token 端點) 傳回。 這通常用來做為授權碼流程的一部分,在所謂的「混合式流程」中,會在 /authorize 要求上擷取識別碼權杖以及授權碼。

本文說明如何在您的應用程式中直接針對通訊協定進行程式設計,以向 Microsoft Entra ID 要求權杖。 建議您盡可能改為使用支援的 Microsoft 驗證程式庫 (MSAL),以取得權杖並呼叫受保護的 Web API。 如需使用 MSAL 的程式碼範例清單,請參閱 Microsoft 身分識別平台程式碼範例

警告

Microsoft 建議您「不要」使用隱含授與流程。 在大部分的情況下,有更安全的可用替代方案,也建議使用這些方案。 某流程的些設定在應用程式中需要非常高的信任度,而且帶有未在其他流程中出現的風險。 您應該只在其他更安全的流程都無法使用時,才使用此流程。 如需詳細資訊,請參閱隱含授與流程的安全性考慮

通訊協定圖表

下圖說明整個隱含登入流程,而後續幾節則會詳細說明每個步驟。

顯示隱含登入流程的螢幕擷取畫面。

OAuth2 隱含授與的適用案例

隱含授與只適用於您登入流程的初始互動部分,其中缺少第三方 Cookie 不會影響您的應用程式。 此限制表示您應該將其專門作為混合式流程的一部分,在其中您的應用程式會要求程式碼以及來自授權端點的權杖。 在混合式流程中,您的應用程式會收到可兌換重新整理權杖的程式碼,如此可確保您的應用程式登入工作階段在一段時間內保持有效。

最好使用授權碼流程

有了從瀏覽器中移除第三方 Cookie 的一些瀏覽器,隱含授與流程不再是合適的驗證方法。 隱含流程的無訊息單一登入 (SSO) 功能無法在沒有第三方 Cookie 的情況下運作,導致應用程式會在嘗試取得新權杖時中斷。 強烈建議所有新應用程式都使用現在支援單一頁面應用程式的授權碼流程取代隱含流程。 現有的單一頁面應用程式也應該移轉至授權碼流程

隱含授與流程的安全性考慮

隱含授與流程適用於伺服器可安全地控制處理 POST 資料的傳統 Web 應用程式。 使用隱含授與流程傳遞權杖有兩種主要方式:其中 response_mode 會以 URL 片段或查詢參數的形式傳回 (使用 form POSTGET)。 在 response_mode=form_post 的隱含流程中,權杖會透過 HTML 表單 POST 安全地傳遞至用戶端的重新導向 URI。 此方法可確保權杖不會在 URL 片段中公開,進而避免透過瀏覽器歷程記錄或參考者標頭洩漏權杖的風險。

使用 response_mode=fragment 傳遞權杖時,會產生隱含流程的安全性考慮。 URL 片段是 URL 的一部分,在 # 符號之後,而且在瀏覽器要求新頁面時不會傳送至伺服器,但可供在瀏覽器中執行的 JavaScript 使用。 這表示權杖會公開給頁面上執行的任何 JavaScript,如果頁面包含第三方指令碼,可能會有安全性風險。 此 SPA 中權杖的安全性考慮也不適用於 form POST 的隱含流程。

何時應該允許使用隱含授與或混合式流程要求時發出存取權杖或標識碼權杖?

隱含授與和混合式流程不像其他 OAuth 流程那麼安全。 除非絕對必要,否則在應用程式註冊中使用隱含授與或混合式流程要求時,您不應該允許發出存取或標識碼權杖。 如果您 (或您的開發人員) 在應用程式中使用 MSAL 來實作驗證和授權,則不需要啟用這兩個欄位。

不過,如果您 (或開發人員) 未在應用程式中使用 MSAL,下表概述了何時應啟用存取權杖或識別碼權杖。

您要建立的應用程式類型 您應該在應用程式註冊中啟用的權杖
未搭配 PKCE 使用授權碼流程的 SPA (單頁應用程式) 存取權杖 & 識別碼權杖
使用隱含流程透過 JavaScript 呼叫 Web API 的 Web 或 SPA 應用程式 存取權杖 & 識別碼權杖
ASP.NET Core Web 應用程式和使用混合式驗證的其他 Web 應用程式 識別碼權杖

傳送登入要求

若要開始將使用者登入應用程式,您可以傳送 OpenID Connect 驗證要求,並透過 Microsoft 身分識別平台取得 id_token

重要

若要成功要求識別碼權杖及/或存取權杖,Microsoft Entra 系統管理中心 - 應用程式註冊頁面中的應用程式註冊必須啟用對應的隱含授與流程,方法是在 [隱含授與和混合式流程] 區段中選取 [識別碼權杖][存取權杖]。 如果未啟用,會傳回 unsupported_response 錯誤:

The provided value for the input parameter 'response_type' is not allowed for this client. Expected value is 'code'

// Line breaks for legibility only

https://login.microsoftonline.com/{tenant}/oauth2/v2.0/authorize?
client_id=00001111-aaaa-2222-bbbb-3333cccc4444
&response_type=id_token
&redirect_uri=http%3A%2F%2Flocalhost%2Fmyapp%2F
&scope=openid
&response_mode=fragment
&state=12345
&nonce=678910
參數 類型 描述
tenant 必要 要求路徑中的 {tenant} 值可用來控制可登入應用程式的人員。 允許的值為 commonorganizationsconsumers 及租用戶識別碼。 如需更多詳細資訊,請參閱 通訊協定基本概念。 嚴格來說,針對您會將使用者從一個租用戶登入另一個租用戶的來賓案例,您必須提供租用戶識別碼,才能正確地將其登入資源租用戶。
client_id 必要 Microsoft Entra 系統管理中心 - 應用程式註冊頁面指派給您應用程式的應用程式 (用戶端) 識別碼。
response_type 必要 必須包含用於 OpenID Connect 登入的 id_token。 它也可能包含 response_type, token。 這裡使用 token ,讓您的應用程式能夠立即從授權端點接收存取權杖,而不需要向授權端點進行第二次要求。 如果您使用 token response_type,scope 參數必須包含範圍,以指出要為其發出權杖的資源 (例如,Microsoft Graph 上的 user.read)。 其也可以包含 code 以取代 token,用來提供授權碼,以便用於授權碼流程。 此 id_token+code 回應有時稱為混合式流程。
redirect_uri 建議使用 應用程式的重新導向 URI,您的應用程式會在此處傳送及接收驗證回應。 其必須完全符合您在 Microsoft Entra 系統管理中心內所註冊的其中一個重新導向 URI,但必須進行 URL 編碼。
scope 必要 範圍的空格分隔清單。 針對 OpenID Connect (id_tokens),即必須包含範圍 openid,其會在同意 UI 中轉譯成「讓您登入」權限。 您可以選擇性地包含 emailprofile 範圍,以取得額外使用者資料的存取權。 如果要求存取權杖,您也可以在此要求中包含其他範圍,以要求同意各種資源。
response_mode 建議使用 指定應該用來將所產生權杖傳回給應用程式的方法。 預設為只存取權杖的 query,但若要求包含 id_token,則為 fragment。 基於安全性考慮,建議針對隱含流程使用 form_post,以確保權杖不會在 URL 片段中公開。
state 建議使用 要求中包含的值,也會隨權杖回應傳回。 其可以是任何內容的字串。 隨機產生的唯一值通常用於防止跨網站偽造要求攻擊。 此狀態也可用來在驗證要求發生之前,將使用者狀態的相關資訊編碼,例如他們所在的頁面或檢視。
nonce 必要 包含在要求中的值 (由應用程式所產生),將會包含在所得的識別碼權杖中來做為宣告。 然後,應用程式可以驗證此值,以減輕權杖重新執行所造成的攻擊。 此值通常是隨機的唯一字串,可以用來識別要求的來源。 只有在要求 id_token 時才需要。
prompt 選用 表示必要的使用者互動類型。 此時唯有 loginnoneselect_accountconsent 是有效值。 prompt=login 會強制使用者在該要求上輸入其認證,而不要進行單一登入。 prompt=none 則相反,其會確保使用者不會看到任何互動式提示。 如果無法透過 SSO 以無訊息方式完成要求,Microsoft 身分識別平台將傳回錯誤。 prompt=select_account 會將使用者傳送至帳戶選擇器,工作階段中記下的所有帳戶都會出現在當中。 prompt=consent 會在使用者登入之後觸發 OAuth 同意對話方塊,詢問使用者是否要授與權限給應用程式。
login_hint 選用 如果您事先知道使用者名稱,便可使用此參數為使用者預先填入登入頁面的使用者名稱和電子郵件地址欄位。 通常應用程式會在重新驗證期間,在已從稍早的登入擷取 login_hint 選擇性宣告之後使用此參數。
domain_hint 選用 如果包含,其會略過使用者在登入頁面上所經歷以電子郵件為基礎的探索程序,進而提供略為更有效率的使用者體驗。 此參數通常用於在單一租用戶中作業的企業營運應用程式,在該租用戶中會提供指定租用戶內的網域名稱,並將使用者轉送至該租用戶的同盟提供者。 此提示會防止來賓登入此應用程式,並限制使用雲端認證 (如 FIDO)。

此時,系統會要求使用者輸入其認證並完成驗證。 Microsoft 身分識別平台會確認使用者已經同意 scope 查詢參數所指出的權限。 如果使用者完全未同意這些權限的任一項,其會要求使用者同意必要權限。 如需詳細資訊,請參閱權限、同意及多租用戶應用程式

一旦使用者驗證並同意,Microsoft 身分識別平台就會使用 response_mode 參數中指定的方法,將回應傳回至應用程式於指定的 redirect_uri 位置。

成功回應

使用 response_mode=fragmentresponse_type=id_token+code 的成功回應如下所示 (內含分行符號以利閱讀):

GET https://localhost/myapp/#
code=0.AgAAktYV-sfpYESnQynylW_UKZmH-C9y_G1A
&id_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ik5HVEZ2ZEstZnl0aEV1Q...
&state=12345
參數 描述
code 如果 response_type 包含 code 則納入。 這是適用於授權碼流程的授權碼。
access_token 如果 response_type 包含 token 則納入。 應用程式要求的存取權杖。 該存取權杖不得經過解碼或檢查,而應將其視為不透明字串。
token_type 如果 response_type 包含 token 則納入。 這永遠是 Bearer
expires_in 如果 response_type 包含 token 則納入。 指出權杖有效的秒數,以供快取之用。
scope 如果 response_type 包含 token 則納入。 指出 access_token 有效的一或多個範圍。 如不適用於使用者,可能不會包含所有要求的範圍。 例如,使用個人帳戶登入時要求僅限 Microsoft Entra 範圍。
id_token 已簽署的 JSON Web 權杖 (JWT)。 應用程式可以將此權杖的區段解碼,以索取已登入使用者的相關資訊。 應用程式可以快取並顯示值,但不應依賴這些值來取得任何授權或安全性界限。 如需有關識別碼權杖的詳細資訊,請參閱 id_token reference
注意:只有在要求 openid 範圍且 response_type 包含 id_tokens 時才提供。
state 如果要求中包含 state 參數,則回應中應該會出現相同的值。 應用程式必須確認要求與回覆中的狀態值完全相同。

警告

請勿在程式碼中,嘗試驗證或讀取任何您未擁有的 API 的權杖 (包括此範例中的權杖)。 Microsoft 服務的權杖可以使用不會驗證為 JWT 的特殊格式,且可能為取用者 (Microsoft 帳戶) 使用者進行加密。 雖然讀取權杖是很實用的偵錯與學習工具,但請勿在程式碼中依賴此功能的相依性,或是假設並非用於您所控制 API 的權杖相關內容。

錯誤回應

錯誤回應可能也會傳送至 redirect_uri ,讓應用程式可以適當地處理:

GET https://localhost/myapp/#
error=access_denied
&error_description=the+user+canceled+the+authentication
參數 描述
error 用以分類發生的錯誤類型與回應錯誤的錯誤碼字串。
error_description 協助開發人員識別驗證錯誤之根本原因的特定錯誤訊息。

以無訊息方式取得存取權杖

您已經將使用者註冊到單一頁面應用程式,您可以無訊息地取得存取權杖以呼叫受到 Microsoft 身分識別保護的 Web API,例如 Microsoft Graph。 即使您已經收到使用 token response_type 的權杖,仍可使用此方法來取得其他資源的權杖,不用重新導向使用者再次登入。

重要

由於預設會移除第三方 Cookie,因此隱含流程的此部分不太可能對您的應用程式有作用,因為其是在不同的瀏覽器上使用。 雖然這目前仍可在未處於無痕模式的 Chromium 瀏覽器中使用,但開發人員應該重新考量使用此部分的流程。 在不支援第三方 Cookie 的瀏覽器中,您會收到錯誤,指出沒有任何使用者登入,因為瀏覽器已移除登入頁面的工作階段 Cookie。

在正常的 OpenID Connect/OAuth 流程中,您可以藉由對 Microsoft 身分識別平台 /token 端點提出要求來完成這個作業。 您可以在隱藏的 iframe 中提出要求,以取得其他 Web API 的新權杖:

// Line breaks for legibility only

https://login.microsoftonline.com/{tenant}/oauth2/v2.0/authorize?
client_id=00001111-aaaa-2222-bbbb-3333cccc4444&response_type=token
&redirect_uri=http%3A%2F%2Flocalhost%2Fmyapp%2F
&scope=https%3A%2F%2Fgraph.microsoft.com%2Fuser.read
&response_mode=fragment
&state=12345
&nonce=678910
&prompt=none
&login_hint=myuser@mycompany.com

如需 URL 中查詢參數的詳細資料,請參閱傳送登入要求

提示

請嘗試使用真實 client_idusername 從您的應用程式註冊,將下列要求複製並貼上瀏覽器索引標籤。 這可讓您查看作用中的無訊息權杖要求。

https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id={your-client-id}&response_type=token&redirect_uri=http%3A%2F%2Flocalhost%2Fmyapp%2F&scope=https%3A%2F%2Fgraph.microsoft.com%2Fuser.read&response_mode=fragment&state=12345&nonce=678910&prompt=none&login_hint={username}

請注意,即使在沒有第三方 Cookie 支援的瀏覽器中,這也可以運作,因為您是直接將此資訊輸入瀏覽器列,而不是在 iframe 內開啟。

由於 prompt=none 參數,此要求會立即成功或失敗,並且傳回給您的應用程式。 系統會使用 response_mode 參數中指定的方法,將回應傳送給您的應用程式於指定的 redirect_uri

成功回應

使用 response_mode=fragment 的成功回應如下所示:

GET https://localhost/myapp/#
access_token=eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6Ik5HVEZ2ZEstZnl0aEV1Q...
&state=12345
&token_type=Bearer
&expires_in=3599
&scope=https%3A%2F%2Fgraph.microsoft.com%2Fdirectory.read
參數 描述
access_token 如果 response_type 包含 token 則納入。 應用程式要求的存取權杖,在此案例中為 Microsoft Graph 的存取權杖。 該存取權杖不得經過解碼或檢查,而應將其視為不透明字串。
token_type 這永遠是 Bearer
expires_in 指出權杖有效的秒數,以供快取之用。
scope 指出存取權杖有效的一或多個範圍。 如果範圍不適用於使用者 (如果在使用個人帳戶登入時,要求僅限 Microsoft Entra 的範圍),則可能不會包含所有要求的範圍。
id_token 已簽署的 JSON Web 權杖 (JWT)。 如果 response_type 包含 id_token 則納入。 應用程式可以將此權杖的區段解碼,以索取已登入使用者的相關資訊。 應用程式可以快取並顯示值,但不應依賴這些值來取得任何授權或安全性界限。 如需 id_token 的詳細資訊,請參閱 id_token 參考
注意:只在要求 openid 範圍時提供。
state 如果要求中包含 state 參數,則回應中應該會出現相同的值。 應用程式必須確認要求與回覆中的狀態值完全相同。

錯誤回應

錯誤回應可能也會傳送至 redirect_uri ,讓應用程式可以適當地處理。 如果 prompt=none,預期的錯誤為:

GET https://localhost/myapp/#
error=user_authentication_required
&error_description=the+request+could+not+be+completed+silently
參數 描述
error 用以分類發生的錯誤類型與回應錯誤的錯誤碼字串。
error_description 協助開發人員識別驗證錯誤之根本原因的特定錯誤訊息。

如果您在 iframe 要求中收到此錯誤,使用者必須再次以互動方式登入以擷取新的權杖。 您可以選擇對於您的應用程式合理的任何方式處理這種情況。

重新整理權杖

隱含授與不提供重新整理權杖。 識別碼權杖和存取權杖馬上就會到期,因此您的應用程式必須準備好定期重新整理這些權杖。 若要重新整理任一類型的權杖,您可以使用 prompt=none 參數來控制身分識別平台的行為,以執行先前概述的相同隱藏 iframe 要求。 如果您想要收到新的識別碼權杖,務必在 response_typescope=openid 中使用 id_token ,以及 nonce 參數。

在不支援第三方 Cookie 的瀏覽器中,這會導致錯誤,指出沒有任何使用者登入。

傳送登出要求

OpenID Connect end_session_endpoint 可讓您的應用程式將要求傳送至 Microsoft 身分識別平台,以結束使用者的工作階段,並清除 Microsoft 身分識別平台所設定的 Cookie。 若要將使用者從 Web 應用程式完全登出,您的應用程式應結束自己和使用者之間的工作階段 (通常是透過清除權杖快取或卸除 Cookie),然後將瀏覽器重新導向至:

https://login.microsoftonline.com/{tenant}/oauth2/v2.0/logout?post_logout_redirect_uri=https://localhost/myapp/
參數 類型 描述
tenant 必要 要求路徑中的 {tenant} 值可用來控制可登入應用程式的人員。 允許的值為 commonorganizationsconsumers 及租用戶識別碼。 如需更多詳細資訊,請參閱 通訊協定基本概念
post_logout_redirect_uri 建議使用 使用者在完成登出之後應該要返回的 URL。 這個值必須符合為應用程式註冊的其中一個重新導向 URI。 如果未包含,Microsoft 身分識別平台會向使用者顯示一般訊息。

另請參閱