-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Open
Labels
priority: p1Important issue which blocks shipping the next release. Will be fixed prior to next release.Important issue which blocks shipping the next release. Will be fixed prior to next release.type: bugError or flaw in code with unintended results or allowing sub-optimal usage patterns.Error or flaw in code with unintended results or allowing sub-optimal usage patterns.
Description
Client
Directly using the auth library
Environment
Local machine
$ go version
go version go1.23.4 darwin/arm64
Code and Dependencies
package main
import (
"context"
"fmt"
"log"
"cloud.google.com/go/auth/credentials/impersonate"
)
const sa = "your-sa-here"
const subject = "[email protected]"
var scopes = []string{}
func main() {
baseCreds, err := impersonate.NewCredentials(&impersonate.CredentialsOptions{
TargetPrincipal: sa,
Scopes: scopes,
Subject: subject,
})
if err != nil {
log.Fatal(err)
return
}
tok, err := baseCreds.Token(context.Background())
if err != nil {
log.Fatal(err)
}
fmt.Println(tok.Value)
}
go.mod
module auth-impersonate-repro-issue
go 1.23.4
require cloud.google.com/go/auth v0.16.3
require (
cloud.google.com/go/compute/metadata v0.7.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/google/s2a-go v0.1.9 // indirect
github.com/googleapis/enterprise-certificate-proxy v0.3.6 // indirect
github.com/googleapis/gax-go/v2 v2.14.2 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 // indirect
go.opentelemetry.io/otel v1.36.0 // indirect
go.opentelemetry.io/otel/metric v1.36.0 // indirect
go.opentelemetry.io/otel/trace v1.36.0 // indirect
golang.org/x/crypto v0.39.0 // indirect
golang.org/x/net v0.41.0 // indirect
golang.org/x/sys v0.33.0 // indirect
golang.org/x/text v0.26.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250519155744-55703ea1f237 // indirect
google.golang.org/grpc v1.73.0 // indirect
google.golang.org/protobuf v1.36.6 // indirect
)
Expected behavior
The token value is printed out.
Actual behavior
2025/08/01 16:58:44 impersonate: status code 400: {
"error": {
"code": 400,
"message": "Invalid JSON payload received. Unexpected token.\nassertion=eyJhbGciOi\n^",
"status": "INVALID_ARGUMENT"
}
}
Additional context
Examining auth/credentials/impersonate/user.go
, method exchangeToken
, you can see that the payload sent to the OAuth2 token endpoint here is a form, but no Content-Type
header is set, which appears to cause the server to attempt to interpret the payload as JSON. If I step through with a debugger and set the header before sending the request, then the request succeeds.
google-cloud-go/auth/credentials/impersonate/user.go
Lines 173 to 186 in 77cdb83
func (u userTokenProvider) exchangeToken(ctx context.Context, signedJWT string) (*auth.Token, error) { | |
v := url.Values{} | |
v.Set("grant_type", "assertion") | |
v.Set("assertion_type", "http://oauth.net/grant_type/jwt/1.0/bearer") | |
v.Set("assertion", signedJWT) | |
req, err := http.NewRequestWithContext(ctx, "POST", fmt.Sprintf("%s/token", oauth2Endpoint), strings.NewReader(v.Encode())) | |
if err != nil { | |
return nil, err | |
} | |
u.logger.DebugContext(ctx, "impersonated user token exchange request", "request", internallog.HTTPRequest(req, []byte(v.Encode()))) | |
resp, body, err := internal.DoRequest(u.client, req) | |
if err != nil { | |
return nil, fmt.Errorf("impersonate: unable to exchange token: %w", err) | |
} |
Metadata
Metadata
Assignees
Labels
priority: p1Important issue which blocks shipping the next release. Will be fixed prior to next release.Important issue which blocks shipping the next release. Will be fixed prior to next release.type: bugError or flaw in code with unintended results or allowing sub-optimal usage patterns.Error or flaw in code with unintended results or allowing sub-optimal usage patterns.