diff --git a/registry/client/auth/session.go b/registry/client/auth/session.go
index <HASH>..<HASH> 100644
--- a/registry/client/auth/session.go
+++ b/registry/client/auth/session.go
@@ -279,6 +279,9 @@ func (th *tokenHandler) getToken(params map[string]string, additionalScopes ...s
 	}
 	var addedScopes bool
 	for _, scope := range additionalScopes {
+		if hasScope(scopes, scope) {
+			continue
+		}
 		scopes = append(scopes, scope)
 		addedScopes = true
 	}
@@ -302,6 +305,15 @@ func (th *tokenHandler) getToken(params map[string]string, additionalScopes ...s
 	return th.tokenCache, nil
 }
 
+func hasScope(scopes []string, scope string) bool {
+	for _, s := range scopes {
+		if s == scope {
+			return true
+		}
+	}
+	return false
+}
+
 type postTokenResponse struct {
 	AccessToken  string    `json:"access_token"`
 	RefreshToken string    `json:"refresh_token"`
If the request already has the scope, don't force token fetch

AuthorizeRequest() injects the 'pull' scope if `from` is set
unconditionally. If the current token already has that scope, it will
be inserted into the scope list twice and `addedScopes` will be set to
true, resulting in a new token being fetched that has no net new scopes.

Instead, check whether `additionalScopes` are actually new.