AlexxIT/go2rtc · warning

either email/password or refresh token is required

Error message

either email/password or refresh token is required

What it means

The ring API handler requires credentials to construct a Ring client, but the request contained neither email/password nor a refresh token. The handler returns HTTP 400 with this static message to tell the caller which parameters are mandatory.

Solutions

  1. Send either email+password or refresh_token in the request
  2. Fix the form field names to match what the handler reads
  3. Add client-side validation that blocks submission when both are empty

Example fix

// before
curl -X POST http://host/api/ring
// after
curl -X POST http://host/api/ring -d 'refresh_token=YOUR_TOKEN'
Defensive patterns

Strategy: validation

Validate before calling

func hasRingCredentials(email, password, refreshToken string) bool {
	return (email != "" && password != "") || refreshToken != ""
}
if !hasRingCredentials(email, password, refreshToken) { /* return 400 before calling the API */ }

Prevention

When it happens

Trigger: POST to the ring endpoint with an empty body or only unrelated form fields, so both the email/password branch and the refresh_token branch are skipped and the else clause fires.

Common situations: Client forgot the form fields; field name mismatch (e.g. sending refresh-token instead of refresh_token); curl call without -d parameters; frontend form submitted empty.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of AlexxIT/go2rtc@c245815e75 (2026-09-07). Data as JSON: /api/errors/41d4dee687ec2d0f. Report an issue: GitHub.

Appendix: source

Thrown at internal/ring/ring.go:74

		}
	} else if refreshToken := query.Get("refresh_token"); refreshToken != "" {
		// Refresh Token Flow
		if refreshToken == "" {
			http.Error(w, "either email/password or refresh_token is required", http.StatusBadRequest)
			return
		}

		var err error
		ringAPI, err = ring.NewRestClient(ring.RefreshTokenAuth{
			RefreshToken: refreshToken,
		}, nil)

		if err != nil {
			http.Error(w, err.Error(), http.StatusInternalServerError)
			return
		}
	} else {
		http.Error(w, "either email/password or refresh token is required", http.StatusBadRequest)
		return
	}

	devices, err := ringAPI.FetchRingDevices()
	if err != nil {
		http.Error(w, err.Error(), http.StatusInternalServerError)
		return
	}

	cleanQuery := url.Values{}
	cleanQuery.Set("refresh_token", ringAPI.RefreshToken)

	var items []*api.Source
	for _, camera := range devices.AllCameras {
		cleanQuery.Set("camera_id", fmt.Sprint(camera.ID))
		cleanQuery.Set("device_id", camera.DeviceID)

		// Stream source

View on GitHub (pinned to c245815e75)