googleapis/mcp-toolbox · critical

no refresh JWT found in the response

Error message

no refresh JWT found in the response

What it means

The login response contained a valid accessJWT but data.refreshJWT was empty, so doLogin rejects the response. Dgraph is expected to return both tokens from /login; a missing refresh token means the session cannot be renewed and indicates an abnormal or partial authentication response. doLogin fails rather than storing an unrenewable token pair.

Source

Thrown at internal/sources/dgraph/dgraph.go:334

		return err
	}

	var r struct {
		Data struct {
			AccessJWT  string `json:"accessJWT"`
			RefreshJWT string `json:"refreshJWT"`
		} `json:"data"`
	}

	if err := json.Unmarshal(resp, &r); err != nil {
		return fmt.Errorf("failed to unmarshal response: %v", err)
	}

	if r.Data.AccessJWT == "" {
		return fmt.Errorf("no access JWT found in the response")
	}
	if r.Data.RefreshJWT == "" {
		return fmt.Errorf("no refresh JWT found in the response")
	}

	hc.AccessJwt = r.Data.AccessJWT
	hc.RefreshToken = r.Data.RefreshJWT
	return nil
}

func (hc *DgraphClient) healthCheck() error {
	url, err := getUrl(hc.baseUrl, "/health", nil)
	if err != nil {
		return err
	}
	req, err := http.NewRequest(http.MethodGet, url, nil)
	if err != nil {
		return fmt.Errorf("error creating request: %w", err)
	}

	resp, err := hc.httpClient.Do(req)

View on GitHub (pinned to 8cc6e09de2)

Solutions

  1. Inspect the raw /login response to confirm refreshJWT is genuinely absent rather than a parsing-struct tag mismatch.
  2. Verify the Dgraph version matches the response schema {"data":{"accessJWT":...,"refreshJWT":...}}; upgrade or adjust the parsing struct accordingly.
  3. Remove any intermediary proxy that could rewrite or filter the login response fields.
  4. Re-run login with valid user credentials (not a refresh token) to force Dgraph to issue a fresh token pair.
  5. If only an access token is ever issued, consider treating accessJWT-only as acceptable by relaxing the check in a fork — at the cost of losing session refresh.

Example fix

// before
if r.Data.RefreshJWT == "" {
  return fmt.Errorf("no refresh JWT found in the response")
}
// after (fork: tolerate missing refresh token)
if r.Data.RefreshJWT == "" {
  hc.AccessJwt = r.Data.AccessJWT
  return nil // session valid but not renewable
}
Defensive patterns

Strategy: type-guard

Validate before calling

// verify the raw response actually contains refreshJWT before login flow proceeds
var probe map[string]json.RawMessage
if err := json.Unmarshal(resp, &probe); err != nil {
  return err
}
if _, ok := probe["refreshJWT"]; !ok && probe["data"] == nil {
  log.Println("warning: login response missing refreshJWT")
}

Type guard

func hasBothTokens(r loginResponse) bool {
  return r.Data.AccessJWT != "" && r.Data.RefreshJWT != ""
}
if !hasBothTokens(r) { /* handle missing refresh token */ }

Try / catch

if err := doLogin(...); err != nil {
  if strings.Contains(err.Error(), "no refresh JWT") {
    // re-login with user/password instead of refresh token, or check for response-rewriting proxies
    log.Printf("incomplete dgraph login response: %v", err)
    return
  }
}

Prevention

When it happens

Trigger: Dgraph /login returns JSON with accessJWT set but refreshJWT absent or empty — abnormal server-side login behavior, non-standard login endpoints/proxies stripping the field, or Dgraph versions/configs that do not issue refresh tokens (e.g. when logging in with a refresh token under unusual conditions).

Common situations: Proxy or middleware rewriting the /login response; version drift where the response schema changed; ACL misconfiguration issuing only an access token; custom login handlers on the Dgraph side.

Related errors


AI-assisted analysis of googleapis/mcp-toolbox@8cc6e09de2 (2026-09-05). Data as JSON: /api/errors/3fe47d27aa7bb298. Report an issue: GitHub.