diff --git a/config/auth_m2m.go b/config/auth_m2m.go index 76958b2ff..6692de362 100644 --- a/config/auth_m2m.go +++ b/config/auth_m2m.go @@ -31,7 +31,7 @@ func (c M2mCredentials) Configure(ctx context.Context, cfg *Config) (credentials ClientSecret: cfg.ClientSecret, AuthStyle: oauth2.AuthStyleInHeader, TokenURL: endpoints.TokenEndpoint, - Scopes: []string{"all-apis"}, + Scopes: cfg.GetScopes(), }).TokenSource(ctx) visitor := refreshableVisitor(ts) diff --git a/config/auth_m2m_test.go b/config/auth_m2m_test.go index e7b107e8d..1d36f450f 100644 --- a/config/auth_m2m_test.go +++ b/config/auth_m2m_test.go @@ -1,12 +1,13 @@ package config import ( + "errors" + "net/http" "net/url" "testing" "github.com/databricks/databricks-sdk-go/credentials/u2m" "github.com/databricks/databricks-sdk-go/httpclient/fixtures" - "github.com/stretchr/testify/require" "golang.org/x/oauth2" ) @@ -90,5 +91,82 @@ func TestM2mNotSupported(t *testing.T) { }, }, }) - require.ErrorIs(t, err, u2m.ErrOAuthNotSupported) + if !errors.Is(err, u2m.ErrOAuthNotSupported) { + t.Errorf("got error %v, want %v", err, u2m.ErrOAuthNotSupported) + } +} + +func TestM2M_Scopes(t *testing.T) { + tests := []struct { + name string + scopes []string + want string + }{ + { + name: "nil scopes uses default", + scopes: nil, + want: "all-apis", + }, + { + name: "empty scopes uses default", + scopes: []string{}, + want: "all-apis", + }, + { + name: "single scope", + scopes: []string{"dashboards"}, + want: "dashboards", + }, + { + name: "multiple scopes are sorted", + scopes: []string{"jobs", "files:read", "mlflow"}, + want: "files:read jobs mlflow", + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + transport := fixtures.MappingTransport{ + "GET /oidc/.well-known/oauth-authorization-server": { + Response: u2m.OAuthAuthorizationServer{ + AuthorizationEndpoint: "https://localhost/auth", + TokenEndpoint: "https://localhost/token", + }, + }, + "POST /token": { + // The scope assertion: verifies the SDK sends the correct scope parameter. + ExpectedRequest: url.Values{ + "grant_type": {"client_credentials"}, + "scope": {tt.want}, + }, + Response: oauth2.Token{ + TokenType: "Bearer", + AccessToken: "test-token", + }, + }, + } + + cfg := &Config{ + Host: "a", + ClientID: "b", + ClientSecret: "c", + AuthType: "oauth-m2m", + Scopes: tt.scopes, + HTTPTransport: transport, + ConfigFile: "/dev/null", + } + + req, err := http.NewRequest("GET", "http://localhost", nil) + if err != nil { + t.Fatalf("http.NewRequest(): unexpected error: %v", err) + } + err = cfg.Authenticate(req) + if err != nil { + t.Fatalf("Authenticate(): unexpected error: %v", err) + } + if got, want := req.Header.Get("Authorization"), "Bearer test-token"; got != want { + t.Errorf("Authorization header: got %q, want %q", got, want) + } + }) + } }