grpc/grpc-go · error

empty accessToken in response (%v)

Error message

empty accessToken in response (%v)

What it means

Returned by tokenInfoFromResponse in sts/sts.go:329 when the STS response parsed as valid JSON but the access_token field is empty. Per RFC 8693 the issued_token/access_token is REQUIRED, so gRPC treats an empty value as a protocol violation even on HTTP 200.

Source

Thrown at credentials/sts/sts.go:329

	resp.Body.Close()
	if err != nil {
		return nil, err
	}

	if resp.StatusCode == http.StatusOK {
		return body, nil
	}
	logger.Warningf("http status %d, body: %s", resp.StatusCode, string(body))
	return nil, fmt.Errorf("http status %d, body: %s", resp.StatusCode, string(body))
}

func tokenInfoFromResponse(respBody []byte) (*tokenInfo, error) {
	respData := &responseParameters{}
	if err := json.Unmarshal(respBody, respData); err != nil {
		return nil, fmt.Errorf("json.Unmarshal(%v): %v", respBody, err)
	}
	if respData.AccessToken == "" {
		return nil, fmt.Errorf("empty accessToken in response (%v)", string(respBody))
	}
	return &tokenInfo{
		tokenType:  respData.TokenType,
		token:      respData.AccessToken,
		expiryTime: time.Now().Add(time.Duration(respData.ExpiresIn) * time.Second),
	}, nil
}

// requestParameters stores all STS request attributes defined in
// https://tools.ietf.org/html/rfc8693#section-2.1.
type requestParameters struct {
	// REQUIRED. The value "urn:ietf:params:oauth:grant-type:token-exchange"
	// indicates that a token exchange is being performed.
	GrantType string `json:"grant_type"`
	// OPTIONAL. Indicates the location of the target service or resource where
	// the client intends to use the requested security token.
	Resource string `json:"resource,omitempty"`
	// OPTIONAL. The logical name of the target service where the client intends

View on GitHub (pinned to 03255a9237)

Solutions

  1. Inspect the response body shown in the error to see which fields were returned.
  2. Verify SubjectTokenType is a type the STS server can actually exchange for an access token.
  3. Confirm RequestedTokenType and Audience are supported by the issuer.
  4. Check the STS server logs / contact the token broker owner if 200-with-empty-token persists.

Example fix

// before
opts := sts.Options{
    SubjectTokenType: "urn:ietf:params:oauth:token-type:unknown",
}

// after
opts := sts.Options{
    SubjectTokenType: "urn:ietf:params:oauth:token-type:jwt",
    RequestedTokenType: "urn:ietf:params:oauth:token-type:access_token",
}
Defensive patterns

Strategy: validation

Validate before calling

// Ensure requested/subject token types are ones the issuer will exchange for an access token.
// Validate config before dial; the only runtime guard is parsing the error.
if opts.SubjectTokenType == "" { return errors.New("SubjectTokenType required") }
if opts.RequestedTokenType != "" && opts.RequestedTokenType != "urn:ietf:params:oauth:token-type:access_token" {
    return fmt.Errorf("unsupported requested token type %q", opts.RequestedTokenType)
}

Try / catch

if strings.Contains(err.Error(), "empty accessToken in response") {
    // issuer returned 200 with no access_token; verify SubjectTokenType/Audience/RequestedTokenType
}

Prevention

When it happens

Trigger: The STS server returns 200 with a JSON body missing the access_token field (or an empty string), e.g. returns only issued_token_type/token_type, or an error-shaped JSON that nonetheless carried 200.

Common situations: Subject/actor token accepted but no token issued (rare server bug); audience/scope accepted structurally but issuance skipped; STS implementation that returns 200 with an error payload; subject token type not actually exchangeable.

Related errors


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