@@ -601,21 +601,23 @@ func (cca Client) AcquireTokenSilent(ctx context.Context, scopes []string, opts
601601 return AuthResult {}, errors .New ("WithSilentAccount option is required" )
602602 }
603603
604- return cca .acquireTokenSilentInternal (ctx , scopes , o .account , o .claims , o .tenantID , o .authnScheme )
605- }
606-
607- // acquireTokenSilentInternal is the internal implementation shared by AcquireTokenSilent and AcquireTokenByCredential
608- func (cca Client ) acquireTokenSilentInternal (ctx context.Context , scopes []string , account Account , claims , tenantID string , authnScheme AuthenticationScheme ) (AuthResult , error ) {
609604 silentParameters := base.AcquireTokenSilentParameters {
610605 Scopes : scopes ,
611- Account : account ,
606+ Account : o . account ,
612607 RequestType : accesstokens .ATConfidential ,
613608 Credential : cca .cred ,
614- IsAppCache : account .IsZero (),
615- TenantID : tenantID ,
616- AuthnScheme : authnScheme ,
617- Claims : claims ,
609+ IsAppCache : o . account .IsZero (),
610+ TenantID : o . tenantID ,
611+ AuthnScheme : o . authnScheme ,
612+ Claims : o . claims ,
618613 }
614+
615+ return cca .acquireTokenSilentInternal (ctx , silentParameters )
616+ }
617+
618+ // acquireTokenSilentInternal is the internal implementation shared by AcquireTokenSilent and AcquireTokenByCredential
619+ func (cca Client ) acquireTokenSilentInternal (ctx context.Context , silentParameters base.AcquireTokenSilentParameters ) (AuthResult , error ) {
620+
619621 return cca .base .AcquireTokenSilent (ctx , silentParameters )
620622}
621623
@@ -718,8 +720,10 @@ func (cca Client) AcquireTokenByAuthCode(ctx context.Context, code string, redir
718720
719721// acquireTokenByCredentialOptions contains optional configuration for AcquireTokenByCredential
720722type acquireTokenByCredentialOptions struct {
721- claims , tenantID string
722- authnScheme AuthenticationScheme
723+ claims , tenantID string
724+ authnScheme AuthenticationScheme
725+ extraBodyParameters map [string ]string
726+ cacheKeyComponents map [string ]string
723727}
724728
725729// AcquireByCredentialOption is implemented by options for AcquireTokenByCredential
@@ -729,7 +733,7 @@ type AcquireByCredentialOption interface {
729733
730734// AcquireTokenByCredential acquires a security token from the authority, using the client credentials grant.
731735//
732- // Options: [WithClaims], [WithTenantID]
736+ // Options: [WithClaims], [WithTenantID], [WithFMIPath], [WithAttribute]
733737func (cca Client ) AcquireTokenByCredential (ctx context.Context , scopes []string , opts ... AcquireByCredentialOption ) (AuthResult , error ) {
734738 o := acquireTokenByCredentialOptions {}
735739 err := options .ApplyOptions (& o , opts )
@@ -746,9 +750,24 @@ func (cca Client) AcquireTokenByCredential(ctx context.Context, scopes []string,
746750 if o .authnScheme != nil {
747751 authParams .AuthnScheme = o .authnScheme
748752 }
753+ authParams .ExtraBodyParameters = o .extraBodyParameters
754+ authParams .CacheKeyComponents = o .cacheKeyComponents
749755 if o .claims == "" {
756+ silentParameters := base.AcquireTokenSilentParameters {
757+ Scopes : scopes ,
758+ Account : Account {}, // empty account for app token
759+ RequestType : accesstokens .ATConfidential ,
760+ Credential : cca .cred ,
761+ IsAppCache : true ,
762+ TenantID : o .tenantID ,
763+ AuthnScheme : o .authnScheme ,
764+ Claims : o .claims ,
765+ ExtraBodyParameters : o .extraBodyParameters ,
766+ CacheKeyComponents : o .cacheKeyComponents ,
767+ }
768+
750769 // Use internal method with empty account (service principal scenario)
751- cache , err := cca .acquireTokenSilentInternal (ctx , scopes , Account {}, o . claims , o . tenantID , authParams . AuthnScheme )
770+ cache , err := cca .acquireTokenSilentInternal (ctx , silentParameters )
752771 if err == nil {
753772 return cache , nil
754773 }
@@ -799,3 +818,63 @@ func (cca Client) Account(ctx context.Context, accountID string) (Account, error
799818func (cca Client ) RemoveAccount (ctx context.Context , account Account ) error {
800819 return cca .base .RemoveAccount (ctx , account )
801820}
821+
822+ // WithFMIPath specifies the path to a federated managed identity.
823+ // The path should point to a valid FMI configuration file that contains the necessary
824+ // identity information for authentication.
825+ func WithFMIPath (path string ) interface {
826+ AcquireByCredentialOption
827+ options.CallOption
828+ } {
829+ return struct {
830+ AcquireByCredentialOption
831+ options.CallOption
832+ }{
833+ CallOption : options .NewCallOption (
834+ func (a any ) error {
835+ switch t := a .(type ) {
836+ case * acquireTokenByCredentialOptions :
837+ if t .extraBodyParameters == nil {
838+ t .extraBodyParameters = make (map [string ]string )
839+ }
840+ if t .cacheKeyComponents == nil {
841+ t .cacheKeyComponents = make (map [string ]string )
842+ }
843+ t .cacheKeyComponents ["fmi_path" ] = path
844+ t .extraBodyParameters ["fmi_path" ] = path
845+ default :
846+ return fmt .Errorf ("unexpected options type %T" , a )
847+ }
848+ return nil
849+ },
850+ ),
851+ }
852+ }
853+
854+ // WithAttribute specifies an identity attribute to include in the token request.
855+ // The attribute is sent as "attributes" in the request body and returned as "xmc_attr"
856+ // in the access token claims. This is sometimes used withFMIPath
857+ func WithAttribute (attrValue string ) interface {
858+ AcquireByCredentialOption
859+ options.CallOption
860+ } {
861+ return struct {
862+ AcquireByCredentialOption
863+ options.CallOption
864+ }{
865+ CallOption : options .NewCallOption (
866+ func (a any ) error {
867+ switch t := a .(type ) {
868+ case * acquireTokenByCredentialOptions :
869+ if t .extraBodyParameters == nil {
870+ t .extraBodyParameters = make (map [string ]string )
871+ }
872+ t .extraBodyParameters ["attributes" ] = attrValue
873+ default :
874+ return fmt .Errorf ("unexpected options type %T" , a )
875+ }
876+ return nil
877+ },
878+ ),
879+ }
880+ }
0 commit comments