hashicorp/nomad · error

unable to get validation keys from OIDC provider: %v

Error message

unable to get validation keys from OIDC provider: %v

What it means

usingOIDC fails when jwt.NewOIDCDiscoveryKeySet cannot complete OIDC discovery — fetching `<oidc_discovery_url>/.well-known/openid-configuration` and then the JWKS it references. This is typically a network/TLS problem or an endpoint that is not a valid OIDC provider.

Source

Thrown at lib/auth/jwt/validator.go:124

	if err != nil {
		return nil, fmt.Errorf("unable to get validation keys from JWKS: %v", err)
	}
	return keySet, nil
}

func usingOIDC(ctx context.Context, oidcurl string, oidccapem []string) (jwt.KeySet, error) {
	// Measure the OIDC endpoint performance.
	defer metrics.MeasureSince([]string{"nomad", "acl", "jwt", "oidc_jwt"}, time.Now())

	// TODO why do we have DiscoverCaPem as an array but JWKSCaPem as a single string?
	pem := ""
	if len(oidccapem) > 0 {
		pem = oidccapem[0]
	}

	keySet, err := jwt.NewOIDCDiscoveryKeySet(ctx, oidcurl, pem)
	if err != nil {
		return nil, fmt.Errorf("unable to get validation keys from OIDC provider: %v", err)
	}
	return keySet, nil
}

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Verify `curl <oidc_discovery_url>/.well-known/openid-configuration` returns valid discovery JSON from a Nomad server.
  2. Set OidcDiscoveryCACert to the PEM of the CA that signed the provider's certificate if using a private/self-signed CA.
  3. Fix the OidcDiscoveryURL (include issuer path, e.g. `https://idp.example.com/realms/prod`).
  4. Check provider availability and Nomad server egress/firewall rules.

Example fix

// before
cfg := &structs.ACLAuthMethodConfig{
  OidcDiscoveryURL: "https://idp.internal:8443",
}
// after: CA pinned for private endpoint
cfg := &structs.ACLAuthMethodConfig{
  OidcDiscoveryURL:     "https://idp.internal:8443/realms/main",
  OidcDiscoveryCACert:  "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----",
}
Defensive patterns

Strategy: validation

Validate before calling

discURL := strings.TrimSuffix(oidcURL, "/") + "/.well-known/openid-configuration"
resp, err := http.Get(discURL)
if err != nil { return fmt.Errorf("discovery unreachable: %w", err) }
if resp.StatusCode != 200 { return fmt.Errorf("discovery returned %d", resp.StatusCode) }
var doc struct{ Issuer string `json:"issuer"`; JwksURI string `json:"jwks_uri"` }
json.NewDecoder(resp.Body).Decode(&doc)
if doc.Issuer == "" || doc.JwksURI == "" { return fmt.Errorf("not a valid OIDC discovery doc") }

Try / catch

keySet, err := usingOIDC(ctx, oidcURL, caPEMs)
if err != nil {
  return fmt.Errorf("verify OidcDiscoveryURL and OidcDiscoveryCACert: %w", err)
}

Prevention

When it happens

Trigger: Validate → usingOIDC when the auth method uses OidcDiscoveryURL and discovery document or key fetch fails, including when OidcDiscoveryCACert cannot validate the provider's TLS chain.

Common situations: Internal OIDC provider with private CA and no OidcDiscoveryCACert set; discovery URL missing the realm/tenant path; provider temporarily down; egress blocked from Nomad servers; provider does not publish openid-configuration at the expected path.

Related errors


AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04). Data as JSON: /api/errors/545b6504a103461c. Report an issue: GitHub.