Skip to content

Allow mapping authentication query columns to user attributes - #756

Open
jnbdz wants to merge 1 commit into
eclipse-vertx:masterfrom
SiteNetSoft:issue-694-row-mapping
Open

jnbdz wants to merge 1 commit into
eclipse-vertx:masterfrom
SiteNetSoft:issue-694-row-mapping

Conversation

@jnbdz

@jnbdz jnbdz commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

The SQL authentication provider discards every column of the authentication query except the password (row.getString(0)), so callers that need more user data right after login — typically the user id for a session or token — have to run a second query for the row they just fetched.

Following the guidance in #694, this adds a SqlAuthentication.create(client, options, attributeMapper) overload where the mapper is a Function<Row, JsonObject> living on the auth type (options stay data-only). The mapper receives the authenticated row and the returned JSON object is merged into the authenticated User attributes:

AuthenticationProvider provider = SqlAuthentication.create(sqlClient,
  new SqlAuthenticationOptions()
    .setAuthenticationQuery("SELECT password, email FROM users WHERE username = ?"),
  row -> new JsonObject().put("email", row.getString("email")));

Behavior notes:

  • the password is still expected in the first column, existing create overloads are unchanged
  • a null mapper result is ignored
  • a mapper that throws fails the authentication future
  • the mapper only runs after the password has been verified

Includes a test in MySQLTest (the DDL gains a nullable email column), an example and documentation.

Fixes #694

The SQL authentication provider discards every column of the
authentication query except the password, forcing a second query to
load user data such as its id right after authentication.

Add a SqlAuthentication.create overload taking a mapping function that
receives the authenticated row and returns a JSON object to merge into
the user attributes. The password remains expected in the first column
and options stay data only, following the guidance in the issue.

Fixes eclipse-vertx#694
@tsegismont
tsegismont force-pushed the issue-694-row-mapping branch from 489f880 to 7ee6b4c Compare September 15, 2026 14:42

@tsegismont tsegismont left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @jnbdz

In addition to the comments inline, I think we should put the additional information into the user principal, not the attributes.

In vertx-auth, principal() holds identity data (who the user is) while attributes() holds
authentication metadata (decoded tokens, expiration timestamps, claims).

Every credential-based auth provider in the project (LDAP, htpasswd, htdigest, properties, OTP, WebAuthn, and SQL itself) puts all user data into principal() and leaves attributes() empty.

Only JWT and OAuth2 use attributes(), and exclusively for decoded token structures and timing metadata (accessToken, idToken, exp, iat, nbf, rootClaim, etc.).

Database columns like email or display_name describe the user's identity, they belong in principal().

Merging them into attributes() is inconsistent with the rest of the codebase
and risks colliding with framework-managed keys that control User.expired(), User.subject(), User.get(), and authorization provider lookups.

* @param attributeMapper maps the authenticated row to extra user attributes, may return {@code null}
* @return the auth provider
*/
static SqlAuthentication create(SqlClient client, SqlAuthenticationOptions options, Function<Row, JsonObject> attributeMapper) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add @GenIgnore(GenIgnore.PERMITTED_TYPE)

}

/**
* Create a JDBC auth provider implementation that enriches the authenticated user with

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* Create a JDBC auth provider implementation that enriches the authenticated user with
* Create a SQL auth provider implementation that enriches the authenticated user with

Could you please also fix the other mentions of JDBC?

Comment on lines +62 to +63
* The authentication query is expected to return the password in the first column, any other
* column is available to the given {@code attributeMapper}. The JSON object returned by the

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please reword this part to make it clear that all columns returned by the authentication query are present? Including the hashed password in the first column. And that the user provided function should handle this information with care

// metadata "amr"
user.principal().put("amr", Collections.singletonList("pwd"));
if (attributeMapper != null) {
JsonObject attributes = attributeMapper.apply(row);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The mapper call should be wrapped with try/catch, log failures and return a failed future Failure in authentication

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Return full user information on authentication query

2 participants