grpc/grpc-go · error

unable to transfer oauthAccess PerRPCCredentials: %v

Error message

unable to transfer oauthAccess PerRPCCredentials: %v

What it means

Thrown from oauthAccess.GetRequestMetadata (oauth.go:133) when the security-level check fails for credentials created by the deprecated oauth.NewOauthAccess(token). The supplied static OAuth token is a bearer secret, so gRPC will not attach it over an insecure channel. RequireTransportSecurity() returns true.

Source

Thrown at credentials/oauth/oauth.go:133

	return true
}

// oauthAccess supplies PerRPCCredentials from a given token.
type oauthAccess struct {
	token oauth2.Token
}

// NewOauthAccess constructs the PerRPCCredentials using a given token.
//
// Deprecated: use oauth.TokenSource instead.
func NewOauthAccess(token *oauth2.Token) credentials.PerRPCCredentials {
	return oauthAccess{token: *token}
}

func (oa oauthAccess) GetRequestMetadata(ctx context.Context, _ ...string) (map[string]string, error) {
	ri, _ := credentials.RequestInfoFromContext(ctx)
	if err := credentials.CheckSecurityLevel(ri.AuthInfo, credentials.PrivacyAndIntegrity); err != nil {
		return nil, fmt.Errorf("unable to transfer oauthAccess PerRPCCredentials: %v", err)
	}
	return map[string]string{
		"authorization": oa.token.Type() + " " + oa.token.AccessToken,
	}, nil
}

func (oa oauthAccess) RequireTransportSecurity() bool {
	return true
}

// NewComputeEngine constructs the PerRPCCredentials that fetches access tokens from
// Google Compute Engine (GCE)'s metadata server. It is only valid to use this
// if your program is running on a GCE instance.
// TODO(dsymonds): Deprecate and remove this.
func NewComputeEngine() credentials.PerRPCCredentials {
	return TokenSource{google.ComputeTokenSource("")}
}

View on GitHub (pinned to 03255a9237)

Solutions

  1. Migrate from deprecated NewOauthAccess to oauth.TokenSource{TokenSource: oauth2.StaticTokenSource(token)}.
  2. Always pair these credentials with TLS transport credentials.
  3. If plaintext is required, remove the per-RPC credentials entirely.

Example fix

// before
creds := oauth.NewOauthAccess(token)
conn, _ := grpc.NewClient(addr,
    grpc.WithTransportCredentials(insecure.NewCredentials()),
    grpc.WithPerRPCCredentials(creds),
)

// after
creds := oauth.TokenSource{TokenSource: oauth2.StaticTokenSource(token)}
conn, _ := grpc.NewClient(addr,
    grpc.WithTransportCredentials(credentials.NewClientTLSFromCert(caPool, "")),
    grpc.WithPerRPCCredentials(creds),
)
Defensive patterns

Strategy: validation

Validate before calling

// Migrate off deprecated NewOauthAccess and always use TLS.
creds := oauth.TokenSource{TokenSource: oauth2.StaticTokenSource(token)}
tlsCreds := credentials.NewClientTLSFromCert(caPool, "")
conn, err := grpc.NewClient(addr,
    grpc.WithTransportCredentials(tlsCreds),
    grpc.WithPerRPCCredentials(creds),
)

Try / catch

if st, ok := status.FromError(err); ok && st.Code() == codes.Unavailable {
    if strings.Contains(st.Message(), "oauthAccess PerRPCCredentials") {
        // channel insecure; reconfigure with TLS
    }
}

Prevention

When it happens

Trigger: Using oauth.NewOauthAccess(token) (deprecated) on a channel with insecure.NewCredentials() or no transport credentials.

Common situations: Legacy code that still calls the deprecated NewOauthAccess; examples that predate oauth.TokenSource; mixing a manually obtained oauth2.Token with a plaintext channel.

Related errors


AI-assisted analysis of grpc/grpc-go@03255a9237 (2026-08-07). Data as JSON: /api/errors/2065fa2ed1460801. Report an issue: GitHub.