Skip to main content

Authentication Switch Request

During the connection phase the server may ask the client to switch to a different auth method. If the authPlugins connection config option is set, it must be an object where each key is the name of a potential authentication plugin requested by the server, and the corresponding value must be a function that optionally receives the connection config options and returns another function, which in turn, optionally receives the switch request data.

The plugin is loaded with a ({user,password,...}) signature, and each call has a (pluginData) signature. Each call should make the plugin return any additional authentication data (Buffer) that should be sent back to the server, either synchronously or asynchronously using a Promise, or should yield an error accordingly.

Example: (imaginary ssh-key-auth plugin) pseudo code

const conn = mysql.createConnection({
user: 'test_user',
password: 'test',
database: 'test_database',
authPlugins: {
'ssh-key-auth': function ({ password }) {
return function (pluginData) {
return getPrivate(key)
.then((key) => {
const response = encrypt(key, password, pluginData);
// continue handshake by sending response data
return response;
})
.catch((err) => {
// throw error to propagate error to connect/changeUser handlers
});
};
},
},
});

There is also a deprecated API where if a authSwitchHandler connection config option is set it must be a function that receives switch request data and responds via a callback. In this case, the first invocation always has a ({pluginName, pluginData}) signature, following calls - ({pluginData}). The client replies with an opaque blob matching the requested plugin via callback(null, data: Buffer).

const conn = mysql.createConnection({
user: 'test_user',
password: 'test',
database: 'test_database',
authSwitchHandler: function ({ pluginName, pluginData }, cb) {
if (pluginName === 'ssh-key-auth') {
getPrivateKey((key) => {
const response = encrypt(key, pluginData);
// continue handshake by sending response data
// respond with error to propagate error to connect/changeUser handlers
cb(null, response);
});
} else {
const err = new Error(
`Unknown AuthSwitchRequest plugin name ${pluginName}`
);
err.fatal = true;
cb(err);
}
},
});

The initial handshake is always performed using mysql_native_password plugin. This will be possible to override in future versions.

Note that if the mysql_native_password method is requested it will be handled internally according to Authentication::Native41 and no authPlugins function or the authSwitchHandler will be invoked.

These MAY be called multiple times if the plugin algorithm requires multiple roundtrips of data exchange between client and server.

Cleartext Authentication​

The mysql_clear_password authentication plugin sends the password to the server in plaintext. This is required by some authentication schemes (e.g. PAM, LDAP, or AWS RDS IAM), but poses a security risk if the connection is not encrypted — a malicious server or man-in-the-middle could capture credentials.

For this reason, mysql_clear_password is disabled by default. If the server requests it and the client has not explicitly opted in, the connection will fail with a MYSQL_CLEAR_PASSWORD_NOT_ENABLED error.

Enabling cleartext authentication​

Set enableCleartextPlugin: true in your connection options:

const conn = mysql.createConnection({
host: 'example.com',
user: 'my_user',
password: 'my_password',
ssl: { rejectUnauthorized: true },
enableCleartextPlugin: true,
});
caution

Only enable this over a secure connection (TLS/SSL or a Unix domain socket). Never enable it over an unencrypted network connection.

Alternatively, providing a custom mysql_clear_password function via the authPlugins option implicitly enables cleartext authentication without the enableCleartextPlugin flag:

const conn = mysql.createConnection({
host: 'example.com',
user: 'my_user',
ssl: { rejectUnauthorized: true },
authPlugins: {
mysql_clear_password: () => () => Buffer.from(password + '\0'),
},
});

Multi-factor authentication​

If the user requires multi-factor authentication in the server, the client will receive a AuthNextFactor request, which is similar in structure to the regular authentication switch request and contains the name and possible initial data for the additional authentication factor plugin (up to 3). Additional passwords can be provided using the connection config options - password2 and password3. Again, for each authentication factor, multiple roundtrips of data exchange can be required by the plugin algoritm.

const conn = mysql.createConnection({
user: 'test_user',
password: 'secret1',
password2: 'secret2',
password3: 'secret3',
database: 'test_database',
authPlugins: {
// password1 === password
'auth-plugin1': function ({ password1 }) {
return function (serverPluginData) {
return clientPluginData(password1, serverPluginData);
};
},
'auth-plugin2': function ({ password2 }) {
return function (serverPluginData) {
return clientPluginData(password2, serverPluginData);
};
},
'auth-plugin3': function ({ password3 }) {
return function (serverPluginData) {
return clientPluginData(password3, serverPluginData);
};
},
},
});