Skip to content

x/oauth2: DeviceAuth doesn't populate RetrieveError error codes #75759

@andig

Description

@andig

If this device auth request fails

client_id=xyz&code_challenge=foo&code_challenge_method=S256&scope=authenticate_user+openid

with an error message like this

{"error": "invalid_request", "error_description": "The request is missing a required parameter"}

The returned oauth2.RetrieveError is empty, i.e. does not contain the error message.

This is due to retrieveDeviceAuth missing the error parsing after

if code := r.StatusCode; code < 200 || code > 299 {
	return nil, &RetrieveError{
		Response: r,
		Body:     body,
	}
}

In contrast, regular flow uses internal.doTokenRoundTrip:

switch content {
case "application/x-www-form-urlencoded", "text/plain":
	// some endpoints return a query string
	vals, err := url.ParseQuery(string(body))
	if err != nil {
		if failureStatus {
			return nil, retrieveError
		}
		return nil, fmt.Errorf("oauth2: cannot parse response: %v", err)
	}
	retrieveError.ErrorCode = vals.Get("error")
	retrieveError.ErrorDescription = vals.Get("error_description")
	retrieveError.ErrorURI = vals.Get("error_uri")
	token = &Token{
		AccessToken:  vals.Get("access_token"),
		TokenType:    vals.Get("token_type"),
		RefreshToken: vals.Get("refresh_token"),
		Raw:          vals,
	}
	e := vals.Get("expires_in")
	expires, _ := strconv.Atoi(e)
	if expires != 0 {
		token.Expiry = time.Now().Add(time.Duration(expires) * time.Second)
	}
default:
	var tj tokenJSON
	if err = json.Unmarshal(body, &tj); err != nil {
		if failureStatus {
			return nil, retrieveError
		}
		return nil, fmt.Errorf("oauth2: cannot parse json: %v", err)
	}
	retrieveError.ErrorCode = tj.ErrorCode
	retrieveError.ErrorDescription = tj.ErrorDescription
	retrieveError.ErrorURI = tj.ErrorURI
	token = &Token{
		AccessToken:  tj.AccessToken,
		TokenType:    tj.TokenType,
		RefreshToken: tj.RefreshToken,
		Expiry:       tj.expiry(),
		ExpiresIn:    int64(tj.ExpiresIn),
		Raw:          make(map[string]any),
	}
	json.Unmarshal(body, &token.Raw) // no error checks for optional fields
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    BugReportIssues describing a possible bug in the Go implementation.NeedsFixThe path to resolution is known, but the work has not been done.

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions