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

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

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

提示

嘗試在 Postman 中執行此要求
嘗試在 Postman 中執行此要求及其他操作 -- 別忘了取代權杖與識別碼!

最好使用授權碼流程

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

OAuth2 隱含授與的適用案例

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

通訊協定圖表

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

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

傳送登入要求

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

重要

若要成功要求識別碼權杖及/或存取權杖,Azure 入口網站 - 應用程式註冊頁面中的應用程式註冊必須啟用對應的隱含授與流程,方法是在 [隱含授與和混合式流程] 區段中選取 [識別碼權杖] 和 [存取權杖]。 如果未啟用,會傳回 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=6731de76-14a6-49ae-97bc-6eba6914391e
&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 必要 Azure 入口網站 - 應用程式註冊頁面指派給您應用程式的應用程式 (用戶端) 識別碼。
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 建議使用 應用程式的 redirect_uri,您的應用程式可以從中傳送及接收驗證回應。 其必須完全符合您在入口網站中註冊的其中一個 redirect_uris,不然就必須得是編碼的 URL。
scope 必要 範圍的空格分隔清單。 針對 OpenID Connect (id_tokens),即必須包含範圍 openid,其會在同意 UI 中轉譯成「讓您登入」權限。 您可以選擇性地包含 emailprofile 範圍,以取得額外使用者資料的存取權。 如果要求存取權杖,您也可以在此要求中包含其他範圍,以要求同意各種資源。
response_mode 選用 指定應該用來將所產生權杖傳回給應用程式的方法。 預設為只查詢存取權杖,但若要求包含 id_token,則會查詢片段。
state 建議使用 同樣會隨權杖回應傳回之要求中所包含的值。 其可以是您想要之任何內容的字串。 隨機產生的唯一值通常用於 防止跨站台要求偽造攻擊。 此狀態也可用來在驗證要求發生之前,將使用者狀態的相關資訊編碼,例如他們所在的頁面或檢視。
nonce 必要 包含在要求中的值 (由應用程式產生),該值將會以宣告的形式包含在產生的 id_token 中。 然後,應用程式可以驗證此值,以減輕權杖重新執行所造成的攻擊。 此值通常是隨機的唯一字串,可以用來識別要求的來源。 只有在要求 id_token 時才需要。
prompt 選用 表示必要的使用者互動類型。 目前的有效值只有 'login'、'none'、'select_account' 和 'consent'。 prompt=login 會強制使用者在該要求上輸入認證,否定單一登入。 prompt=none 則相反,其將確保使用者不會看到任何互動式提示。 如果無法透過單一登入以無訊息方式完成要求,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
參數 Description
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 適用的範圍。 如不適用於使用者,可能不會包含所有要求的範圍。 例如,使用個人帳戶登入時要求僅限 Azure AD 範圍。
id_token 已簽署的 JSON Web 權杖 (JWT)。 應用程式可以將此權杖的區段解碼,以索取已登入使用者的相關資訊。 應用程式可以快取並顯示值,但不應依賴這些值來取得任何授權或安全性界限。 如需有關 id_token 的詳細資訊,請參閱 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 協助開發人員識別驗證錯誤根本原因的特定錯誤訊息。

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

重要

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

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

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

// Line breaks for legibility only

https://login.microsoftonline.com/{tenant}/oauth2/v2.0/authorize?
client_id=6731de76-14a6-49ae-97bc-6eba6914391e
&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 中查詢參數的詳細資料,請參閱傳送登入要求

提示

嘗試將下列要求複製並貼上瀏覽器索引標籤! (請務必以您使用者的正確值取代 login_hint 值)

https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id=6731de76-14a6-49ae-97bc-6eba6914391e&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={your-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
參數 Description
access_token 如果 response_type 包含 token 則納入。 應用程式要求的存取權杖,在此案例中為 Microsoft Graph 的存取權杖。 該存取權杖不得經過解碼或檢查,而應將其視為不透明字串。
token_type 一律為 Bearer
expires_in 指出權杖有效的秒數,以供快取之用。
scope 表示 access_token 適用的範圍。 如果範圍不適用於使用者 (例如:在使用個人帳戶登入時,要求僅限 Azure AD 的範圍),則可能不會包含所有要求的範圍。
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 要求中收到此錯誤,使用者必須再次以互動方式登入以擷取新的權杖。 您可以選擇對於您的應用程式合理的任何方式處理這種情況。

重新整理權杖

隱含授與不提供重新整理權杖。 id_tokenaccess_token 馬上就會到期,因此您的應用程式必須準備好定期重新整理這些權杖。 若要重新整理任一類型的權杖,您可以使用 prompt=none 參數來控制身分識別平台的行為,以執行上述的相同隱藏 iframe 要求。 如果您想要收到新的 id_token,務必在 scope=openid 中使用 id_tokenresponse_type,以及 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 身分識別平台會向使用者顯示一般訊息。

後續步驟