1 //go:build go1.18
2 // +build go1.18
3 4 // Copyright (c) Microsoft Corporation. All rights reserved.
5 // Licensed under the MIT License.
6 7 package azidentity
8 9 import (
10 "context"
11 12 "github.com/Azure/azure-sdk-for-go/sdk/azcore"
13 "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
14 "github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime"
15 )
16 17 const credNameBrowser = "InteractiveBrowserCredential"
18 19 // InteractiveBrowserCredentialOptions contains optional parameters for InteractiveBrowserCredential.
20 type InteractiveBrowserCredentialOptions struct {
21 azcore.ClientOptions
22 23 // AdditionallyAllowedTenants specifies tenants to which the credential may authenticate, in addition to
24 // TenantID. When TenantID is empty, this option has no effect and the credential will authenticate to
25 // any requested tenant. Add the wildcard value "*" to allow the credential to authenticate to any tenant.
26 AdditionallyAllowedTenants []string
27 28 // AuthenticationRecord returned by a call to a credential's Authenticate method. Set this option
29 // to enable the credential to use data from a previous authentication.
30 AuthenticationRecord AuthenticationRecord
31 32 // Cache is a persistent cache the credential will use to store the tokens it acquires, making
33 // them available to other processes and credential instances. The default, zero value means the
34 // credential will store tokens in memory and not share them with any other credential instance.
35 Cache Cache
36 37 // ClientID is the ID of the application to which users will authenticate. When not set, users
38 // will authenticate to an Azure development application, which isn't recommended for production
39 // scenarios. In production, developers should instead register their applications and assign
40 // appropriate roles. See https://aka.ms/azsdk/identity/AppRegistrationAndRoleAssignment for more
41 // information.
42 ClientID string
43 44 // DisableAutomaticAuthentication prevents the credential from automatically prompting the user to authenticate.
45 // When this option is true, GetToken will return AuthenticationRequiredError when user interaction is necessary
46 // to acquire a token.
47 DisableAutomaticAuthentication bool
48 49 // DisableInstanceDiscovery should be set true only by applications authenticating in disconnected clouds, or
50 // private clouds such as Azure Stack. It determines whether the credential requests Microsoft Entra instance metadata
51 // from https://login.microsoft.com before authenticating. Setting this to true will skip this request, making
52 // the application responsible for ensuring the configured authority is valid and trustworthy.
53 DisableInstanceDiscovery bool
54 55 // LoginHint pre-populates the account prompt with a username. Users may choose to authenticate a different account.
56 LoginHint string
57 58 // RedirectURL is the URL Microsoft Entra ID will redirect to with the access token. This is required
59 // only when setting ClientID, and must match a redirect URI in the application's registration.
60 // Applications which have registered "http://localhost" as a redirect URI need not set this option.
61 RedirectURL string
62 63 // TenantID is the Microsoft Entra tenant the credential authenticates in. Defaults to the
64 // "organizations" tenant, which can authenticate work and school accounts.
65 TenantID string
66 }
67 68 func (o *InteractiveBrowserCredentialOptions) init() {
69 if o.TenantID == "" {
70 o.TenantID = organizationsTenantID
71 }
72 if o.ClientID == "" {
73 o.ClientID = developerSignOnClientID
74 }
75 }
76 77 // InteractiveBrowserCredential opens a browser to interactively authenticate a user.
78 type InteractiveBrowserCredential struct {
79 client *publicClient
80 }
81 82 // NewInteractiveBrowserCredential constructs a new InteractiveBrowserCredential. Pass nil to accept default options.
83 func NewInteractiveBrowserCredential(options *InteractiveBrowserCredentialOptions) (*InteractiveBrowserCredential, error) {
84 cp := InteractiveBrowserCredentialOptions{}
85 if options != nil {
86 cp = *options
87 }
88 cp.init()
89 msalOpts := publicClientOptions{
90 AdditionallyAllowedTenants: cp.AdditionallyAllowedTenants,
91 Cache: cp.Cache,
92 ClientOptions: cp.ClientOptions,
93 DisableAutomaticAuthentication: cp.DisableAutomaticAuthentication,
94 DisableInstanceDiscovery: cp.DisableInstanceDiscovery,
95 LoginHint: cp.LoginHint,
96 Record: cp.AuthenticationRecord,
97 RedirectURL: cp.RedirectURL,
98 }
99 c, err := newPublicClient(cp.TenantID, cp.ClientID, credNameBrowser, msalOpts)
100 if err != nil {
101 return nil, err
102 }
103 return &InteractiveBrowserCredential{client: c}, nil
104 }
105 106 // Authenticate opens the default browser so a user can log in. Subsequent
107 // GetToken calls will automatically use the returned AuthenticationRecord.
108 func (c *InteractiveBrowserCredential) Authenticate(ctx context.Context, opts *policy.TokenRequestOptions) (AuthenticationRecord, error) {
109 var err error
110 ctx, endSpan := runtime.StartSpan(ctx, credNameBrowser+"."+traceOpAuthenticate, c.client.azClient.Tracer(), nil)
111 defer func() { endSpan(err) }()
112 tk, err := c.client.Authenticate(ctx, opts)
113 return tk, err
114 }
115 116 // GetToken requests an access token from Microsoft Entra ID. This method is called automatically by Azure SDK clients.
117 func (c *InteractiveBrowserCredential) GetToken(ctx context.Context, opts policy.TokenRequestOptions) (azcore.AccessToken, error) {
118 var err error
119 ctx, endSpan := runtime.StartSpan(ctx, credNameBrowser+"."+traceOpGetToken, c.client.azClient.Tracer(), nil)
120 defer func() { endSpan(err) }()
121 tk, err := c.client.GetToken(ctx, opts)
122 return tk, err
123 }
124 125 var _ azcore.TokenCredential = (*InteractiveBrowserCredential)(nil)
126