Enhancement
Summary
The authentication_jwt plugin requires the auth switch response in a specific wire format ([1-byte capability] [MySQL length-encoded JWT string]), but this format is not documented. The JWT Authentication docs only cover MySQL 9.2 CLI with --authentication-openid-connect-client-id-token-file. Programmatic clients (Node.js, Python, Go, custom JDBC plugins) have no way to know the expected format without reading the FE source code.
The Problem
When connecting programmatically with a authentication_jwt user, the client handles the authentication_openid_connect_client auth switch. Sending raw JWT bytes as the response produces a misleading error:
Invalid serialized unsecured/JWS/JWE object: Missing second delimiter
The JWT is well-formed (3 parts, 2 dots, valid base64). The error occurs because JWTAuthenticationProvider.authenticate() expects a specific format:
// JWTAuthenticationProvider.java lines 50-53
ByteBuffer authBuffer = ByteBuffer.wrap(authResponse);
MysqlCodec.readInt1(authBuffer); // 1 byte: capability flag
byte[] idToken = MysqlCodec.readLenEncodedString(authBuffer); // MySQL length-encoded string
If raw JWT bytes are sent (e.g., eyJ0eXAiOi...), the first byte e (0x65 = 101) is interpreted as the string length. Only 101 bytes of the ~1300-byte token are read, truncating it past the first dot — hence "Missing second delimiter."
Expected Auth Switch Response Format
[1 byte] Capability flag (0x00)
[length-encoded str] JWT token in MySQL length-encoded string format:
- Token < 251 bytes: [1-byte length] [token bytes]
- Token < 65536 bytes: [0xFC] [2-byte LE length] [token bytes]
- Token < 16MB: [0xFD] [3-byte LE length] [token bytes]
Working Example (Node.js mysql2)
const mysql = require('mysql2/promise');
function encodeLenEncString(str) {
const buf = Buffer.from(str, 'utf8');
if (buf.length < 251) return Buffer.concat([Buffer.from([buf.length]), buf]);
const header = Buffer.alloc(3);
header[0] = 0xfc;
header.writeUInt16LE(buf.length, 1);
return Buffer.concat([header, buf]);
}
const conn = await mysql.createConnection({
host: 'fe-host',
port: 9030,
user: 'my_jwt_user',
authPlugins: {
authentication_openid_connect_client: () => (data) => {
return Buffer.concat([
Buffer.from([0x00]), // capability byte
encodeLenEncString(jwtToken) // length-encoded JWT
]);
},
},
});
const [rows] = await conn.query('SELECT CURRENT_USER()');
// Returns: 'my_jwt_user'@'%'
Steps to Reproduce (raw JWT — fails)
- Create a JWT user:
CREATE USER testjwt IDENTIFIED WITH authentication_jwt AS '{
"jwks_url": "https://login.microsoftonline.com/<tenant>/discovery/v2.0/keys",
"principal_field": "preferred_username",
"required_issuer": "https://login.microsoftonline.com/<tenant>/v2.0",
"required_audience": "<client_id>"
}';
- Connect with raw JWT bytes as auth switch response:
authPlugins: {
authentication_openid_connect_client: () => (data) => Buffer.from(jwt, 'utf8') // RAW — fails
}
- Error:
Invalid serialized unsecured/JWS/JWE object: Missing second delimiter
Steps to Reproduce (length-encoded — works)
- Connect with properly formatted response (capability byte + length-encoded JWT):
authPlugins: {
authentication_openid_connect_client: () => (data) => {
return Buffer.concat([Buffer.from([0x00]), encodeLenEncString(jwt)]); // WORKS
}
}
SELECT CURRENT_USER() returns the JWT user.
Suggestion
Add a section to the JWT Authentication page titled "Connecting from programmatic clients" documenting:
- StarRocks sends an auth switch to plugin
authentication_openid_connect_client
- Client must respond with:
[1-byte capability flag] [MySQL length-encoded JWT string]
- Code examples for Node.js (mysql2) and Python (pymysql)
Alternatively, consider improving the error message — instead of the Nimbus JOSE "Missing second delimiter" error, StarRocks could detect that the first byte looks like an ASCII character (not a valid length prefix) and return: "Auth response format error: expected [capability byte][length-encoded JWT], received raw bytes. See <docs-link>."
Environment
- StarRocks version: 3.5.15 (
select current_version() → 3.5.15-5abb1cb)
- Also verified: Code unchanged on
main branch as of 2026-04-12
- Client: Node.js mysql2 v3.22.0
- IdP: Azure AD (Entra ID), JWT size ~1292 bytes
- Use case: Healthcare analytics platform integrating Azure AD SSO with StarRocks JWT authentication
Impact
Any developer integrating StarRocks authentication_jwt with a programmatic client (web app backends, custom JDBC drivers, BI tool plugins, data pipeline connectors) will hit this undocumented format requirement. The error message provides no clue about the expected format. We spent 2 days debugging this before reading the FE source code.
Happy to contribute a docs PR if that would be helpful.
Enhancement
Summary
The
authentication_jwtplugin requires the auth switch response in a specific wire format ([1-byte capability] [MySQL length-encoded JWT string]), but this format is not documented. The JWT Authentication docs only cover MySQL 9.2 CLI with--authentication-openid-connect-client-id-token-file. Programmatic clients (Node.js, Python, Go, custom JDBC plugins) have no way to know the expected format without reading the FE source code.The Problem
When connecting programmatically with a
authentication_jwtuser, the client handles theauthentication_openid_connect_clientauth switch. Sending raw JWT bytes as the response produces a misleading error:The JWT is well-formed (3 parts, 2 dots, valid base64). The error occurs because
JWTAuthenticationProvider.authenticate()expects a specific format:If raw JWT bytes are sent (e.g.,
eyJ0eXAiOi...), the first bytee(0x65 = 101) is interpreted as the string length. Only 101 bytes of the ~1300-byte token are read, truncating it past the first dot — hence "Missing second delimiter."Expected Auth Switch Response Format
Working Example (Node.js mysql2)
Steps to Reproduce (raw JWT — fails)
Invalid serialized unsecured/JWS/JWE object: Missing second delimiterSteps to Reproduce (length-encoded — works)
SELECT CURRENT_USER()returns the JWT user.Suggestion
Add a section to the JWT Authentication page titled "Connecting from programmatic clients" documenting:
authentication_openid_connect_client[1-byte capability flag] [MySQL length-encoded JWT string]Alternatively, consider improving the error message — instead of the Nimbus JOSE "Missing second delimiter" error, StarRocks could detect that the first byte looks like an ASCII character (not a valid length prefix) and return:
"Auth response format error: expected [capability byte][length-encoded JWT], received raw bytes. See <docs-link>."Environment
select current_version()→3.5.15-5abb1cb)mainbranch as of 2026-04-12Impact
Any developer integrating StarRocks
authentication_jwtwith a programmatic client (web app backends, custom JDBC drivers, BI tool plugins, data pipeline connectors) will hit this undocumented format requirement. The error message provides no clue about the expected format. We spent 2 days debugging this before reading the FE source code.Happy to contribute a docs PR if that would be helpful.