Skip to content

@zenstackhq/better-auth adapter serializes Better Auth string[] fields before ZenStack validation #2615

@pkudinov

Description

@pkudinov

What happened?

When using @zenstackhq/better-auth with Better Auth's OAuth provider, dynamic client registration fails for models that contain native array fields.

In our setup, Better Auth's OAuth provider declares several fields as type: "string[]", and the ZenStack Better Auth schema generator emits matching ZenStack native array fields such as:

model OauthClient {
  redirectUris           String[]
  scopes                 String[]
  grantTypes             String[]
  responseTypes          String[]
  postLogoutRedirectUris String[]
}

However, at runtime, @zenstackhq/better-auth creates the Better Auth adapter without setting or forwarding supportsArrays:

const adapterOptions = {
  config: {
    adapterId: "zenstack",
    adapterName: "ZenStack Adapter",
    usePlural: config.usePlural ?? false,
    debugLogs: config.debugLogs ?? false,
    transaction: ...
  },
  adapter: createCustomAdapter(db)
};

Better Auth core defaults supportsArrays to false. For schema fields with type: "string[]" or type: "number[]", the adapter factory then JSON.stringifys array values before calling the underlying adapter.

That means ZenStack receives strings for fields whose generated schema expects arrays, and validation fails before the DB write.

Example failure from dynamic OAuth client registration:

Invalid input: expected array, received string
path: scopes

Invalid input: expected array, received string
path: redirectUris

Invalid input: expected array, received string
path: grantTypes

Invalid input: expected array, received string
path: responseTypes

Versions

@zenstackhq/better-auth: 3.5.6
better-auth: 1.5.4
@better-auth/core: 1.5.4
@better-auth/oauth-provider: 1.5.4
PostgreSQL provider

I also looked at the recent schema-generator changes in #2614. They look useful for schema generation/import behavior, but this runtime issue appears separate because the adapter config passed to createAdapterFactory still doesn't declare array support.

Minimal reproduction shape

  1. Configure Better Auth with ZenStack adapter and the OAuth provider.
  2. Generate/port the Better Auth OAuth provider schema into ZenStack models, where OAuth provider string[] fields become String[].
  3. Call OAuth dynamic client registration with array fields:
{
  "redirect_uris": ["http://localhost:3000/callback"],
  "scope": "openid profile email",
  "grant_types": ["authorization_code", "refresh_token"],
  "response_types": ["code"]
}
  1. The create call fails because Better Auth transformed those arrays into JSON strings before db.oauthClient.create(...).

Expected behavior

For providers/schemas that support native arrays, the ZenStack Better Auth adapter should preserve array values when Better Auth schema fields are string[] / number[].

A possible fix would be to set or forward Better Auth's supportsArrays adapter option, likely defaulting to true for PostgreSQL/native-array ZenStack schemas, or exposing it explicitly through AdapterConfig.

Alternatively, if the adapter intentionally does not support native arrays, the schema generator should not emit String[] for Better Auth array fields, because the generated schema and runtime adapter behavior currently disagree.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions