@@ -624,7 +624,7 @@ def _acquire_token_by_username_password_federated(
624624class ConfidentialClientApplication (ClientApplication ): # server-side web app
625625
626626 def acquire_token_for_client (self , scopes , ** kwargs ):
627- """Acquires token from the service for the confidential client .
627+ """Acquires token for the current confidential client, not for an end user .
628628
629629 :param list[str] scopes: (Required)
630630 Scopes requested to access a protected API (a resource).
@@ -639,17 +639,26 @@ def acquire_token_for_client(self, scopes, **kwargs):
639639 scope = scopes , # This grant flow requires no scope decoration
640640 ** kwargs )
641641
642- def acquire_token_on_behalf_of (
643- self , user_assertion , scope , authority = None , policy = '' ):
644- the_authority = Authority (authority ) if authority else self .authority
645- return oauth2 .Client (
646- self .client_id , token_endpoint = the_authority .token_endpoint ,
647- default_body = self ._build_auth_parameters (
648- self .client_credential , the_authority .token_endpoint ,
649- self .client_id )
650- )._get_token ( # TODO: Avoid using internal methods
651- "urn:ietf:params:oauth:grant-type:jwt-bearer" ,
652- assertion = user_assertion , requested_token_use = 'on_behalf_of' ,
653- scope = scope , # This grant flow requires no scope decoration???
654- query = {'p' : policy } if policy else None )
642+ def acquire_token_on_behalf_of (self , user_assertion , scopes , ** kwargs ):
643+ """Acquires token using on-behalf-of (OBO) flow.
644+
645+ The current app is a middle-tier service which already receives a token
646+ representing an end user.
647+ The current app can use such token (a.k.a. a user assertion) to request
648+ another token to access downstream service, on behalf of that user.
649+
650+ The current middle-tier app has no user interaction to obtain consent.
651+ See how to gain consent upfront for your middle-tier app from this article.
652+ https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-on-behalf-of-flow#gaining-consent-for-the-middle-tier-application
653+ """
654+ # The implementation is NOT based on Token Exchange
655+ # https://tools.ietf.org/html/draft-ietf-oauth-token-exchange-16
656+ return self .client .obtain_token_by_assertion ( # bases on assertion RFC 7521
657+ user_assertion ,
658+ self .client .GRANT_TYPE_JWT , # IDTs and AAD ATs are all JWTs
659+ scope = scopes , # Without decorate_scope(...), it still gets an AT.
660+ # As of 2019, AAD would even issue RT, and ClientInfo i.e. account.
661+ # No IDT will be issued. OBO app probably does not need one anyway.
662+ data = dict (kwargs .pop ("data" , {}), requested_token_use = "on_behalf_of" ),
663+ ** kwargs )
655664
0 commit comments