ory/kratos · error

api_key auth strategy requires a string value

Error message

api_key auth strategy requires a string value

What it means

authStrategy requires the api_key strategy's "value" (the secret) to be a string. If config["value"] is missing or of another JSON/YAML type, the builder returns this error and the webhook cannot be constructed.

Solutions

  1. Quote the value so it parses as a string: value: "12345"
  2. Ensure the env var referenced for the secret is set and non-empty
  3. Add the missing value key to the api_key auth config
  4. Confirm the strategy is api_key and not basic_auth (which uses user/password)

Example fix

// before
auth:
  type: api_key
  name: X-Api-Key
  value: 12345678
// after
auth:
  type: api_key
  name: X-Api-Key
  value: "12345678"
Defensive patterns

Strategy: validation

Validate before calling

// Go: check api_key secret before building
func validateAPIKeyValue(cfg map[string]interface{}) error {
	v, ok := cfg["value"].(string)
	if !ok || v == "" {
		return errors.New("api_key auth requires a non-empty string value")
	}
	return nil
}

Type guard

func hasAPIKeyValue(cfg map[string]interface{}) bool {
	v, ok := cfg["value"].(string)
	return ok && v != ""
}

Try / catch

b, err := request.NewBuilder(cfg)
if err != nil {
	if strings.Contains(err.Error(), "requires a string value") {
		return fmt.Errorf("api_key auth 'value' must be a quoted string secret")
	}
	return err
}

Prevention

When it happens

Trigger: api_key auth config where "value" is absent, a number (value: 12345), a bool, or an object — e.g. secrets read from env templating that expanded to a numeric literal.

Common situations: API keys that are all digits parsed as YAML integers; forgetting to quote the secret in YAML; env var substitution returning empty (value: ) making it null.

Related errors


AI-assisted analysis of ory/kratos@b86338da04 (2026-09-07). Data as JSON: /api/errors/ae6fd930c80b1178. Report an issue: GitHub.

Appendix: source

Thrown at request/auth.go:40

		in    string
	}
	AuthStrategy interface {
		apply(req *retryablehttp.Request)
	}
)

func authStrategy(typ string, config map[string]any) (AuthStrategy, error) {
	switch typ {
	case "":
		return NewNoopAuthStrategy(), nil
	case "api_key":
		name, ok := config["name"].(string)
		if !ok {
			return nil, fmt.Errorf("api_key auth strategy requires a string name")
		}
		value, ok := config["value"].(string)
		if !ok {
			return nil, fmt.Errorf("api_key auth strategy requires a string value")
		}
		in, _ := config["in"].(string) // in is optional
		return NewAPIKeyStrategy(in, name, value), nil
	case "basic_auth":
		user, ok := config["user"].(string)
		if !ok {
			return nil, fmt.Errorf("basic_auth auth strategy requires a string user")
		}
		password, ok := config["password"].(string)
		if !ok {
			return nil, fmt.Errorf("basic_auth auth strategy requires a string password")
		}
		return NewBasicAuthStrategy(user, password), nil
	}

	return nil, fmt.Errorf("unsupported auth type: %s", typ)
}

View on GitHub (pinned to b86338da04)