External credential validation

Describe the problem/error/question

Hi, all. I'm creating an external credential validator using the n8n API's show credential data schema. However, the schema that is returned shows reference to fields such as grantType or useDynamicClientRegistration or .... but those fields do not exist in the schema, nor can they be added to the request. I have looked at the source code and I see those fields have default values, but when I try to add them to the request it fails. (all examples shown below)

So my question is - where do we get the values of those fields / how to we change them? Or should we consider only the default values for them and adjust the schema accordingly?

Relevant code snippets

Returned schema from n8n API:

{
    "additionalProperties": false,
    "type": "object",
    "properties": {
        "serverUrl": {
            "type": "string"
        },
        "authUrl": {
            "type": "string"
        },
        "accessTokenUrl": {
            "type": "string"
        },
        "clientId": {
            "type": "string"
        },
        "clientSecret": {
            "type": "string"
        },
        "sendAdditionalBodyProperties": {
            "type": "boolean"
        },
        "additionalBodyProperties": {
            "type": "json"
        },
        "oauthTokenData": {
            "type": "json"
        },
        "notice": {
            "type": "notice"
        }
    },
    "allOf": [
        {
            "if": {
                "properties": {
                    "useDynamicClientRegistration": {
                        "enum": [
                            true
                        ]
                    }
                }
            },
            "then": {
                "allOf": [
                    {
                        "required": [
                            "serverUrl"
                        ]
                    },
                    {
                        "required": [
                            "clientId"
                        ]
                    },
                    {
                        "required": [
                            "clientSecret"
                        ]
                    }
                ]
            },
            "else": {
                "allOf": [
                    {
                        "not": {
                            "required": [
                                "serverUrl"
                            ]
                        }
                    },
                    {
                        "not": {
                            "required": [
                                "clientId"
                            ]
                        }
                    },
                    {
                        "not": {
                            "required": [
                                "clientSecret"
                            ]
                        }
                    }
                ]
            }
        },
        {
            "if": {
                "properties": {
                    "grantType": {
                        "enum": [
                            "clientCredentials"
                        ]
                    }
                }
            },
            "then": {
                "allOf": [
                    {
                        "required": [
                            "sendAdditionalBodyProperties"
                        ]
                    },
                    {
                        "required": [
                            "additionalBodyProperties"
                        ]
                    }
                ]
            },
            "else": {
                "allOf": [
                    {
                        "not": {
                            "required": [
                                "sendAdditionalBodyProperties"
                            ]
                        }
                    },
                    {
                        "not": {
                            "required": [
                                "additionalBodyProperties"
                            ]
                        }
                    }
                ]
            }
        }
    ],
    "required": []
}

Credential creation with full values:

  curl http://localhost:5678/api/v1/credentials \
  --request POST \
  --header 'Content-Type: application/json' \
  --header 'X-N8N-API-KEY: my-key' \
  --data '{
  "name": "Test ServiceNow OAuth2 Credentials",
  "type": "serviceNowOAuth2Api",
  "data": {
    "clientId": "your-oauth-client-id",
    "clientSecret": "your-oauth-client-secret",
    "subdomain": "dev99890",
    "serverUrl": "",
    "sendAdditionalBodyProperties": true,
    "additionalBodyProperties": {}
  }
}'

Response from n8n:

{
  "name":"Test ServiceNow OAuth2 Credentials",
  "type":"serviceNowOAuth2Api",
  "id":"874fAeU7kTycoIgj",
  "updatedAt":"2026-02-18T17:05:34.139Z",
  "createdAt":"2026-02-18T17:05:34.139Z",
  "isManaged":false,
  "isGlobal":false
}

Credential creation attempting default values change:

  curl http://localhost:5678/api/v1/credentials \
  --request POST \
  --header 'Content-Type: application/json' \
  --header 'X-N8N-API-KEY: my-key' \
  --data '{
  "name": "Test ServiceNow OAuth2 Credentials",
  "type": "serviceNowOAuth2Api",
  "data": {
    "clientId": "your-oauth-client-id",
    "clientSecret": "your-oauth-client-secret",
    "subdomain": "dev99890",
    "serverUrl": "",
    "grantType": "authorizationCode"
  }
}'

Response from n8n:

{
  "message":"request.body.data is not allowed to have the additional property \"grantType\""
}

Credential creation ignoring grantType requirement:

  curl http://localhost:5678/api/v1/credentials \
  --request POST \
  --header 'Content-Type: application/json' \
  --header 'X-N8N-API-KEY: my-key' \
  --data '{
  "name": "Test ServiceNow OAuth2 Credentials",
  "type": "serviceNowOAuth2Api",
  "data": {
    "clientId": "your-oauth-client-id",
    "clientSecret": "your-oauth-client-secret",
    "subdomain": "dev99890",
    "serverUrl": ""
  }
}'


Response from n8n:

{"message":"request.body.data does not match allOf schema [subschema 1] with 4 error[s]:,request.body.data does not match allOf schema [subschema 0] with 1 error[s]:,request.body.data requires property \"sendAdditionalBodyProperties\",request.body.data does not match allOf schema [subschema 1] with 1 error[s]:,request.body.data requires property \"additionalBodyProperties\""}

So, as you can see, the credential creation passes when all fields are given. Which makes sense because of the branch requirement for grantType. However, I can’t change the grantType by specifying it here. So the question is where, and how does it impact the external credential validation.

Information on your n8n setup

  • n8n version: 1.122.3
  • Database (default: SQLite): sqlite
  • n8n EXECUTIONS_PROCESS setting (default: own, main): own
  • Running n8n via (Docker, npm, n8n cloud, desktop app): docker
  • Operating system: windows + wsl

Hi @tnazifov

it is locked inside n8n’s system files. it’s like a factory setting that you cannot see it or change it.

how does it affect you?

even though you can’t see it, the system still reads it.

because n8n defaults to “Client Credentials” mode internally, it enforces the strict rules for that mode.

basically, it’s like a form where a checkbox is ticked by default, but the checkbox is invisible. you keep getting an error saying “fill in the details for the checked box,” even though you didn’t check it.

just send the empty fields it wants (additionalBodyProperties, etc). that satisfies the invisible rule.

hope this helped you!

1 Like

Well, that’s a great comparison you used. But the error says - “if checkbox is checked, this field is required”. Point being, if the box is checked by default and can’t be changed, then that field is required all the time. There’s really no point in telling the user “if”, like I don’t see a point in sending a schema that’s branching off of hidden and hardcoded fields. Especially if there’s nowhere where you’re explaining the user about that checkbox.

But, yeah, thanks for your answer, it confirmed what I suspected. We should simply disregard those branches in schema and require all fields by default.

1 Like