{"record":{"id":"b0fbc7b12df2980c","repo":"hashicorp/nomad","slug":"unable-to-read-iss-property-of-provided-token","errorCode":null,"errorMessage":"unable to read iss property of provided token","messagePattern":"unable to read iss property of provided token","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"lib/auth/jwt/validator.go","lineNumber":80,"sourceCode":"\tvalidator, err := jwt.NewValidator(keySet)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\n\tclaims, err := validator.Validate(ctx, token, expected)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"unable to verify signature of JWT token: %v\", err)\n\t}\n\n\t// validate issuer manually, because we allow users to specify an array\n\tif len(methodConf.BoundIssuer) > 0 {\n\t\tif _, ok := claims[\"iss\"]; !ok {\n\t\t\treturn nil, fmt.Errorf(\n\t\t\t\t\"auth method specifies BoundIssuers but the provided token does not contain issuer information\",\n\t\t\t)\n\t\t}\n\t\tif iss, ok := claims[\"iss\"].(string); !ok {\n\t\t\treturn nil, fmt.Errorf(\"unable to read iss property of provided token\")\n\t\t} else if !slices.Contains(methodConf.BoundIssuer, iss) {\n\t\t\treturn nil, fmt.Errorf(\"invalid JWT issuer: %v\", claims[\"iss\"])\n\t\t}\n\t}\n\n\treturn claims, nil\n}\n\nfunc usingStaticKeys(keys []string) (jwt.KeySet, error) {\n\tvar parsedKeys []crypto.PublicKey\n\tfor _, v := range keys {\n\t\tkey, err := jwt.ParsePublicKeyPEM([]byte(v))\n\t\tparsedKeys = append(parsedKeys, key)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"unable to parse public key for JWT auth: %v\", err)\n\t\t}\n\t}\n\treturn jwt.NewStaticKeySet(parsedKeys)","sourceCodeStart":62,"sourceCodeEnd":98,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/lib/auth/jwt/validator.go#L62-L98","documentation":"Fires in JWT validation: the token's iss claim is present but is not a string (e.g. an unexpected type), and since BoundIssuer matching expects a string issuer, the claim cannot be read and login fails.","triggerScenarios":"Login where claims[\"iss\"] is present but fails the .(string) type assertion — a non-standard token with iss as non-string type.","commonSituations":"Custom/misbehaving IdP emitting iss as a non-string; hand-rolled tokens for testing with numeric iss values.","solutions":["Fix the IdP to emit iss as a standard string (per RFC 7519)","Regenerate test tokens with a standard library ensuring string iss","Validate the token structure with jwt.io or a decoder before configuring the auth method"],"exampleFix":"// before (non-standard)\n{\"iss\": 12345}\n// after\n{\"iss\": \"https://idp.example.com\"}","handlingStrategy":"validation","validationCode":"payload := decodeJWTPayload(rawToken)\nif iss, ok := payload[\"iss\"]; ok {\n    if _, isStr := iss.(string); !isStr {\n        return errors.New(\"iss claim must be a string per RFC 7519\")\n    }\n}","typeGuard":"func issAsString(claims map[string]interface{}) (string, bool) {\n    iss, ok := claims[\"iss\"]\n    if !ok { return \"\", false }\n    s, ok := iss.(string)\n    return s, ok\n}","tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"unable to read iss property\") {\n    return fmt.Errorf(\"token iss claim is not a string; regenerate token with a standards-compliant library: %w\", err)\n}","preventionTips":["Generate tokens only with standard JWT libraries that serialize iss as a string","Decode test tokens and assert iss is a string before wiring up the auth method","Fix custom IdP implementations to follow RFC 7519 issuer claim typing"],"tags":["auth","jwt","issuer-validation"],"backgroundTag":"jwt-issuer-claim-invalid-type","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"}