{"record":{"id":"15f35b034287aeae","repo":"nats-io/nats-server","slug":"auth-callout-signing-key-is-unknown","errorCode":null,"errorMessage":"auth callout signing key is unknown","messagePattern":"auth callout signing key is unknown","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/auth_callout.go","lineNumber":148,"sourceCode":"\t\t// check the audience to be the server ID\n\t\tif cr.Audience != s.info.ID {\n\t\t\treturn nil, errors.New(\"auth callout violation: auth callout response is not for server\")\n\t\t}\n\n\t\t// check if had an error message from the auth account\n\t\tif cr.Error != _EMPTY_ {\n\t\t\treturn nil, fmt.Errorf(\"auth callout service returned an error: %v\", cr.Error)\n\t\t}\n\n\t\t// if response is encrypted none of this is needed\n\t\tif isOperatorMode && !encrypted {\n\t\t\tpkStr := cr.Issuer\n\t\t\tif cr.IssuerAccount != _EMPTY_ {\n\t\t\t\tpkStr = cr.IssuerAccount\n\t\t\t}\n\t\t\tif pkStr != account {\n\t\t\t\tif _, ok := acc.hasIssuer(pkStr); !ok {\n\t\t\t\t\treturn nil, errors.New(\"auth callout signing key is unknown\")\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn jwt.DecodeUserClaims(cr.Jwt)\n\t}\n\n\t// getIssuerAccount returns the issuer (as per JWT) - it also asserts that\n\t// only in operator mode we expect to receive `issuer_account`.\n\tgetIssuerAccount := func(arc *jwt.UserClaims, account string) (string, error) {\n\t\t// Make sure correct issuer.\n\t\tvar issuer string\n\t\tif opts.AuthCallout != nil {\n\t\t\tissuer = opts.AuthCallout.Issuer\n\t\t} else {\n\t\t\t// Operator mode is who we send the request on unless switching accounts.\n\t\t\tissuer = acc.Name\n\t\t}","sourceCodeStart":130,"sourceCodeEnd":166,"githubUrl":"https://github.com/nats-io/nats-server/blob/3a66a489d262bf89b71a71c955c94920394532f3/server/auth_callout.go#L130-L166","documentation":"This error occurs when the auth callout response is signed by a key (Issuer, or IssuerAccount if set) that is not the expected account and is not a known signing key of that account. The server verifies that whoever signed the authorization response is authorized (via account issuer keys) to do so; an unknown signer is a security violation.","triggerScenarios":"The AuthorizationResponse carries an Issuer (or IssuerAccount) public key that differs from the target account and is not present in the account's issuer keys (acc.hasIssuer fails).","commonSituations":"Rotating or adding auth callout signing keys without updating the account's issuer list, using a separate signing key not registered via nsc, or pointing the callout at the wrong account.","solutions":["Add the callout service's signing public key to the account's trusted signing/issuer keys (nsc edit account --signing-key or equivalent)","Ensure cr.IssuerAccount, when set, matches an account that is a valid issuer for the target account","Re-sign the authorization response with a key already registered on the account","Push the updated account JWT to the server after adding the issuer key"],"exampleFix":"// before\nnsc add operator -n ops   // service signs with a key unknown to account\n// after\nnsc edit account AUTH --signing-key <callout-service-public-key>\nnsc push -A","handlingStrategy":"validation","validationCode":"// before deploying: verify the signing key is a registered account signing key\nacctJWT, _ := fetchAccountJWT(accountPub)\nclaims, _ := jwt.DecodeAccountClaims(acctJWT)\nfound := false\nfor k := range claims.SigningKeys {\n    if k == calloutSigningPubKey {\n        found = true\n    }\n}\nif !found {\n    return fmt.Errorf(\"callout signing key %s not registered on account\", calloutSigningPubKey)\n}","typeGuard":null,"tryCatchPattern":"user, err := s.lookupAccountAuthorization(...)\nif err != nil && strings.Contains(err.Error(), \"signing key is unknown\") {\n    log.Errorf(\"callout response signed by unregistered key %s\", cr.Issuer)\n    return nil, ErrAuthorization\n}","preventionTips":["Register every callout signing key as an account signing key (nsc edit account --signing-key)","Push updated account JWTs to the server after key changes","Track key rotations and update the account before rotating the callout key"],"tags":["auth","jwt","callout","signing-keys","security","nats"],"backgroundTag":"unknown-jwt-signing-key","analyzedSha":"3a66a489d262bf89b71a71c955c94920394532f3","analyzedAt":"2026-09-02T04:41:54.247Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}