diff --git a/Documentation/connectors/bitbucket.md b/Documentation/connectors/bitbucket.md
index f0746689e4fc0f37f91cb479070b0c884100e478..71754bee1322908d12a301ff39e93140d3e10f73 100644
--- a/Documentation/connectors/bitbucket.md
+++ b/Documentation/connectors/bitbucket.md
@@ -14,7 +14,7 @@ The following is an example of a configuration for `examples/config-dev.yaml`:
 
 ```yaml
 connectors:
-- type: bitbucket
+- type: bitbucket-cloud
   # Required field for connector id.
   id: bitbucket
   # Required field for connector name.
@@ -22,9 +22,11 @@ connectors:
   config:
     # Credentials can be string literals or pulled from the environment.
     clientID: $BITBUCKET_CLIENT_ID
-    clientSecret: BITBUCKET_CLIENT_SECRET
+    clientSecret: $BITBUCKET_CLIENT_SECRET
     redirectURI: http://127.0.0.1:5556/dex/callback
-    # Optional teams, communicated through the "groups" scope.
+    # Optional teams whitelist, communicated through the "groups" scope.
+    # If `teams` is omitted, all of the user's Bitbucket teams are returned when the groups scope is present.
+    # If `teams` is provided, this acts as a whitelist - only the user's Bitbucket teams that are in the configured `teams` below will go into the groups claim.  Conversely, if the user is not in any of the configured `teams`, the user will not be authenticated.
     teams:
     - my-team
 ```
diff --git a/connector/bitbucket/bitbucket.go b/connector/bitbucket/bitbucket.go
index 4e3620d3d718fa010dfa9b6eb37afa5985ab8947..0b3b1ba43e3d8f3bcfdef7ad553ac43b6b352a46 100644
--- a/connector/bitbucket/bitbucket.go
+++ b/connector/bitbucket/bitbucket.go
@@ -1,5 +1,5 @@
-// Package bitbucket provides authentication strategies using Bitbucket.
-package bitbucket
+// Package bitbucketcloud provides authentication strategies using Bitbucket Cloud.
+package bitbucketcloud
 
 import (
 	"context"
@@ -71,8 +71,7 @@ type bitbucketConnector struct {
 	clientID     string
 	clientSecret string
 	logger       logrus.FieldLogger
-	// apiURL defaults to "https://api.bitbucket.org/2.0"
-	apiURL string
+	apiURL       string
 
 	// the following are used only for tests
 	hostName   string
@@ -294,11 +293,11 @@ func (b *bitbucketConnector) user(ctx context.Context, client *http.Client) (use
 	)
 
 	if err = get(ctx, client, b.apiURL+"/user", &u); err != nil {
-		return u, err
+		return user{}, err
 	}
 
 	if u.Email, err = b.userEmail(ctx, client); err != nil {
-		return u, err
+		return user{}, err
 	}
 
 	return u, nil
@@ -309,7 +308,6 @@ func (b *bitbucketConnector) user(ctx context.Context, client *http.Client) (use
 type userEmail struct {
 	IsPrimary   bool   `json:"is_primary"`
 	IsConfirmed bool   `json:"is_confirmed"`
-	Type        string `json:"type"`
 	Email       string `json:"email"`
 }
 
@@ -356,7 +354,7 @@ func (b *bitbucketConnector) getGroups(ctx context.Context, client *http.Client,
 	if len(b.teams) > 0 {
 		filteredTeams := filterTeams(bitbucketTeams, b.teams)
 		if len(filteredTeams) == 0 {
-			return nil, fmt.Errorf("bitbucket: user %q not in required teams", userLogin)
+			return nil, fmt.Errorf("bitbucket: user %q is not in any of the required teams", userLogin)
 		}
 		return filteredTeams, nil
 	} else if groupScope {
@@ -367,23 +365,22 @@ func (b *bitbucketConnector) getGroups(ctx context.Context, client *http.Client,
 }
 
 // Filter the users' team memberships by 'teams' from config.
-func filterTeams(userTeams, configTeams []string) (teams []string) {
+func filterTeams(userTeams, configTeams []string) []string {
+	teams := []string{}
 	teamFilter := make(map[string]struct{})
 	for _, team := range configTeams {
-		if _, ok := teamFilter[team]; !ok {
-			teamFilter[team] = struct{}{}
-		}
+		teamFilter[team] = struct{}{}
 	}
 	for _, team := range userTeams {
 		if _, ok := teamFilter[team]; ok {
 			teams = append(teams, team)
 		}
 	}
-	return
+	return teams
 }
 
 type team struct {
-	Username string `json:"username"` // Username is actually the team name
+	Name string `json:"username"` // The "username" from Bitbucket Cloud is actually the team name here
 }
 
 type userTeamsResponse struct {
@@ -392,7 +389,10 @@ type userTeamsResponse struct {
 }
 
 func (b *bitbucketConnector) userTeams(ctx context.Context, client *http.Client) ([]string, error) {
-	apiURL, teams := b.apiURL+"/teams?role=member", []string{}
+
+	var teams []string
+	apiURL := b.apiURL + "/teams?role=member"
+
 	for {
 		// https://developer.atlassian.com/bitbucket/api/2/reference/resource/teams
 		var response userTeamsResponse
@@ -402,7 +402,7 @@ func (b *bitbucketConnector) userTeams(ctx context.Context, client *http.Client)
 		}
 
 		for _, team := range response.Values {
-			teams = append(teams, team.Username)
+			teams = append(teams, team.Name)
 		}
 
 		if response.Next == nil {
@@ -432,13 +432,13 @@ func get(ctx context.Context, client *http.Client, apiURL string, v interface{})
 	if resp.StatusCode != http.StatusOK {
 		body, err := ioutil.ReadAll(resp.Body)
 		if err != nil {
-			return fmt.Errorf("bitbucket: read body: %v", err)
+			return fmt.Errorf("bitbucket: read body: %s: %v", resp.Status, err)
 		}
 		return fmt.Errorf("%s: %s", resp.Status, body)
 	}
 
 	if err := json.NewDecoder(resp.Body).Decode(v); err != nil {
-		return fmt.Errorf("failed to decode response: %v", err)
+		return fmt.Errorf("bitbucket: failed to decode response: %v", err)
 	}
 
 	return nil
diff --git a/connector/bitbucket/bitbucket_test.go b/connector/bitbucket/bitbucket_test.go
index b5d962660cbeedf9b8b172c4b42b5916eaf67eb3..b9f4ba08f822857280f3e34b63dcbb16046254bc 100644
--- a/connector/bitbucket/bitbucket_test.go
+++ b/connector/bitbucket/bitbucket_test.go
@@ -1,4 +1,4 @@
-package bitbucket
+package bitbucketcloud
 
 import (
 	"context"
@@ -22,9 +22,9 @@ func TestUserGroups(t *testing.T) {
 			PageLen: 10,
 		},
 		Values: []team{
-			{Username: "team-1"},
-			{Username: "team-2"},
-			{Username: "team-3"},
+			{Name: "team-1"},
+			{Name: "team-2"},
+			{Name: "team-3"},
 		},
 	}
 
@@ -113,12 +113,12 @@ func newClient() *http.Client {
 
 func expectNil(t *testing.T, a interface{}) {
 	if a != nil {
-		t.Errorf("Expected %+v to equal nil", a)
+		t.Fatalf("Expected %+v to equal nil", a)
 	}
 }
 
 func expectEquals(t *testing.T, a interface{}, b interface{}) {
 	if !reflect.DeepEqual(a, b) {
-		t.Errorf("Expected %+v to equal %+v", a, b)
+		t.Fatalf("Expected %+v to equal %+v", a, b)
 	}
 }
diff --git a/server/server.go b/server/server.go
index a2ca3e189f7b2846ecf9255cf029f59038703381..adf872eb7df8294a0ae123d72775f5612c506295 100644
--- a/server/server.go
+++ b/server/server.go
@@ -24,7 +24,7 @@ import (
 
 	"github.com/dexidp/dex/connector"
 	"github.com/dexidp/dex/connector/authproxy"
-	"github.com/dexidp/dex/connector/bitbucket"
+	"github.com/dexidp/dex/connector/bitbucketcloud"
 	"github.com/dexidp/dex/connector/github"
 	"github.com/dexidp/dex/connector/gitlab"
 	"github.com/dexidp/dex/connector/ldap"
@@ -430,17 +430,17 @@ type ConnectorConfig interface {
 // ConnectorsConfig variable provides an easy way to return a config struct
 // depending on the connector type.
 var ConnectorsConfig = map[string]func() ConnectorConfig{
-	"mockCallback": func() ConnectorConfig { return new(mock.CallbackConfig) },
-	"mockPassword": func() ConnectorConfig { return new(mock.PasswordConfig) },
-	"ldap":         func() ConnectorConfig { return new(ldap.Config) },
-	"github":       func() ConnectorConfig { return new(github.Config) },
-	"gitlab":       func() ConnectorConfig { return new(gitlab.Config) },
-	"oidc":         func() ConnectorConfig { return new(oidc.Config) },
-	"saml":         func() ConnectorConfig { return new(saml.Config) },
-	"authproxy":    func() ConnectorConfig { return new(authproxy.Config) },
-	"linkedin":     func() ConnectorConfig { return new(linkedin.Config) },
-	"microsoft":    func() ConnectorConfig { return new(microsoft.Config) },
-	"bitbucket":    func() ConnectorConfig { return new(bitbucket.Config) },
+	"mockCallback":    func() ConnectorConfig { return new(mock.CallbackConfig) },
+	"mockPassword":    func() ConnectorConfig { return new(mock.PasswordConfig) },
+	"ldap":            func() ConnectorConfig { return new(ldap.Config) },
+	"github":          func() ConnectorConfig { return new(github.Config) },
+	"gitlab":          func() ConnectorConfig { return new(gitlab.Config) },
+	"oidc":            func() ConnectorConfig { return new(oidc.Config) },
+	"saml":            func() ConnectorConfig { return new(saml.Config) },
+	"authproxy":       func() ConnectorConfig { return new(authproxy.Config) },
+	"linkedin":        func() ConnectorConfig { return new(linkedin.Config) },
+	"microsoft":       func() ConnectorConfig { return new(microsoft.Config) },
+	"bitbucket-cloud": func() ConnectorConfig { return new(bitbucketcloud.Config) },
 	// Keep around for backwards compatibility.
 	"samlExperimental": func() ConnectorConfig { return new(saml.Config) },
 }