{"record":{"id":"40ce707b5a1c08a5","repo":"hashicorp/nomad","slug":"jwt-auth-method-requires-either-oidcdiscoveryurl","errorCode":null,"errorMessage":"JWT auth method requires either OIDCDiscoveryURL, or JWKS URL, or JWTValidationPubKeys set","messagePattern":"JWT auth method requires either OIDCDiscoveryURL, or JWKS URL, or JWTValidationPubKeys set","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nomad/structs/acl.go","lineNumber":1596,"sourceCode":"\t\treturn errors.New(\"missing auth method Config\")\n\t}\n\tmErr := &multierror.Error{}\n\n\tswitch methodType {\n\tcase ACLAuthMethodTypeOIDC:\n\t\tif a.OIDCDiscoveryURL == \"\" {\n\t\t\tmErr = multierror.Append(mErr, errors.New(\"missing OIDCDiscoveryURL\"))\n\t\t}\n\t\tif a.OIDCClientID == \"\" {\n\t\t\tmErr = multierror.Append(mErr, errors.New(\"missing OIDCClientID\"))\n\t\t}\n\t\tif err := a.OIDCClientAssertion.Validate(); err != nil {\n\t\t\tmErr = multierror.Append(mErr, fmt.Errorf(\"invalid client assertion config: %w\", err))\n\t\t}\n\n\tcase ACLAuthMethodTypeJWT:\n\t\tif a.OIDCDiscoveryURL == \"\" && a.JWKSURL == \"\" && len(a.JWTValidationPubKeys) == 0 {\n\t\t\tmErr = multierror.Append(mErr, errors.New(\n\t\t\t\t\"JWT auth method requires either OIDCDiscoveryURL, or JWKS URL, or JWTValidationPubKeys set\"),\n\t\t\t)\n\t\t}\n\t}\n\n\treturn helper.FlattenMultierror(mErr)\n}\n\nfunc (a *ACLAuthMethodConfig) Copy() *ACLAuthMethodConfig {\n\tif a == nil {\n\t\treturn nil\n\t}\n\n\tc := new(ACLAuthMethodConfig)\n\t*c = *a\n\n\tc.JWTValidationPubKeys = slices.Clone(a.JWTValidationPubKeys)\n\tc.OIDCScopes = slices.Clone(a.OIDCScopes)","sourceCodeStart":1578,"sourceCodeEnd":1614,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/nomad/structs/acl.go#L1578-L1614","documentation":"ACLAuthMethodConfig.Validate rule for JWT methods: none of OIDCDiscoveryURL, JWKSURL, or JWTValidationPubKeys is set, so Nomad has no way to obtain verification keys for the JWTs and cannot validate signatures.","triggerScenarios":"Upserting an auth method with Type \"jwt\" while OIDCDiscoveryURL, JWKSURL, and JWTValidationPubKeys are all empty.","commonSituations":"JWT method created as a placeholder before keys were provisioned; typo'd field names in JSON payloads; teams deleting pubkeys during rotation without adding a JWKS URL first.","solutions":["Set Config.JWKSURL to the provider's JWKS endpoint (most common for external JWT issuers)","Or set OIDCDiscoveryURL if the issuer supports OIDC discovery","Or provide Config.JWTValidationPubKeys with one or more PEM public keys"],"exampleFix":"// before\nConfig: &api.ACLAuthMethodConfig{BoundAudiences: [\"nomad\"]}\n// after\nConfig: &api.ACLAuthMethodConfig{BoundAudiences: [\"nomad\"], JWKSURL: \"https://example.com/.well-known/jwks.json\"}","handlingStrategy":"validation","validationCode":"func jwtValidationSourceSet(c *structs.ACLAuthMethodConfig) bool {\n  return c != nil && (c.OIDCDiscoveryURL != \"\" || c.JWKSURL != \"\" || len(c.JWTValidationPubKeys) > 0)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Prefer JWKSURL for external issuers","During key rotation, add the new source before removing the old","Validate one signature source exists before apply"],"tags":["nomad","acl","jwt","validation"],"backgroundTag":"jwt-validation-source-missing","analyzedSha":"482b49bf1aec006f089bcfc7e632d8f6ac303e5e","analyzedAt":"2026-09-04T07:54:14.808Z","contentChangedAt":"2026-09-04T07:54:14.808Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}