Skip to content

sys_oauth_resource.identifier declares an uncited maxLength: 1024, and now over-declares relative to every column that references it #12313

Description

@os-warren

Filed unassigned by the #11701 dev while discharging that card's narrowing condition. Not fixed there: narrowing this column is a contract change on a different published object and would move it off #12198's hash shadow, so it needs its own ruling.

The observation

sys_oauth_resource.identifier (packages/platform-objects/src/identity/sys-oauth-resource.object.ts) declares maxLength: 1024. Two things are true of that number:

  1. It cites no producer. Every bound driver-sql: the platform-objects schema does not sync onto MySQL — unbounded string fields become TEXT, which MySQL refuses to index #11374 declared carries a [#11374] comment naming where it came from (sys_session.token → "better-auth 1.7.1's own MySQL schema … varchar(255)"; sys_oauth_consent.client_id → "a referencing column takes the referenced column's bound"; sys_account.issuer → "transitively from sys_sso_provider.issuer"). This one has no comment at all. git log -S puts it in 4109153 (fix(plugin-auth,platform-objects): close @better-auth/oauth-provider 1.7 schema drift — restore platform SSO #3080), the @better-auth/oauth-provider 1.7 schema-drift close — a parity fix that added the object wholesale, not a sourced-bound pass. It reads as generous slack chosen for "a URI", never derived.

  2. Measured, the producing contract cannot fill it. better-auth 1.7.1 is the sole writer (managedBy: 'better-auth', protection.lock: 'full'). Its own MySQL migration generator (better-auth/dist/db/get-migration.mjs, getType) emits this column as varchar(255) (the field.unique branch — oauthResource.identifier is { type: "string", required: true, unique: true }), and the referring oauthClientResource.resourceId as varchar(36) (the field.references branch). On an upstream MySQL deployment a resource identifier longer than 255 characters cannot be registered at all.

Why it matters now rather than before

#11701 narrowed sys_oauth_client_resource.resource_id from 1024 to 768 so its declared non-unique index could exist on MySQL at all. That leaves the pair asymmetric in the declaration, not just in practice:

column declared physical (MySQL, measured 8.0.46)
sys_oauth_resource.identifier (referent) 1024 text + UNIQUE on a varbinary(32) hash shadow (#12198)
sys_oauth_client_resource.resource_id (referrer) 768 varchar(768), index with SUB_PART = NULL

So on PostgreSQL or SQLite an operator can register a resource whose identifier is 900 characters — the referent's declared contract admits it — and then no client can ever be granted that resource, because the referring column refuses it. Nothing upstream can produce such a value, which is exactly why #11701's narrowing was ruled safe; but the two declarations still disagree about what a legitimate resource identifier is, and only one of them is sourced.

Dispositions worth weighing (not ruled)

  • A — narrow identifier to 768 to match its referrer. Cheapest; keeps the pair consistent; but ⚠️ it also takes sys_oauth_resource off fix(driver-sql): carry an over-long UNIQUE index on a hash-shadow column (MySQL utf8mb4) #12198's hash shadow (768 × 4 = 3072 bytes is exactly the last direct width), changing physical schema on an object that just landed on that route, and reducing the population that route demonstrates.
  • B — narrow both to a sourced 255, matching what upstream can actually store. Most honest against the producer; largest declared-domain reduction, and it rejects values in (255, 768] that the current referrer would accept.
  • C — leave 1024 and document why, i.e. accept the asymmetry and add the citation this column is missing. Cheapest by far, and defensible if the band is agreed unreachable — but it keeps a number nothing derives.

No recommendation carried here — #11701's ruling deliberately scoped itself to the referring column, and picking among these is a fresh decision.

Evidence trail

  • Upstream field declarations: @better-auth/oauth-provider@1.7.1/dist/authorize-*.mjs (resourceId.references = { model: "oauthResource", field: "identifier" }) and dist/oauth-*.d.mts.
  • Upstream width emission: better-auth@1.7.1/dist/db/get-migration.mjs, getType's mysql string branch.
  • Physical readings above are from information_schema.COLUMNS / .STATISTICS on live MySQL 8.0.46 (utf8mb4/InnoDB, STRICT_TRANS_TABLES), read as a separate query rather than from emitted DDL.

Related to #11701 (which narrowed the referrer) and #12198 (which put the referent on a hash shadow).

Generated by Claude Code

Activity

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

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions