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,
});
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);
};
},
},
});