[GH-ISSUE #9212] passkey plugin types break exactOptionalPropertyTypes: true compatibility (regression in 1.6.0 from #8843) #28635

Open
opened 2026-04-17 20:03:37 -05:00 by GiteaMirror · 0 comments
Owner

Originally created by @denishamann on GitHub (Apr 15, 2026).
Original GitHub issue: https://github.com/better-auth/better-auth/issues/9212

Is this suited for github?

  • Yes, this is suited for github

Reproduction

Minimal reproduction (self-contained, no repo needed)

  1. Create a fresh TypeScript project with this tsconfig.json:

    {
      "compilerOptions": {
        "strict": true,
        "exactOptionalPropertyTypes": true,
        "module": "ESNext",
        "moduleResolution": "Bundler",
        "target": "ES2022"
      }
    }
    
  2. Install:

    pnpm add better-auth@1.6.4 @better-auth/passkey@1.6.4
    
  3. Create auth.ts:

    import { passkey } from "@better-auth/passkey";
    import { betterAuth } from "better-auth";
    
    export const auth = betterAuth({
      plugins: [
        passkey({
          rpID: "localhost",
          rpName: "App",
          origin: "http://localhost:3000",
        }),
      ],
    });
    
  4. Run tsc --noEmit.

Reproduces on: @better-auth/passkey 1.6.0, 1.6.1, 1.6.2, 1.6.3, 1.6.4.
Does NOT reproduce on: @better-auth/passkey 1.5.6.

Bisect: the regression was introduced by #8843 (merged 2026-04-06, shipped in 1.6.0), which added requireResourceOwnership middleware to the use: [...] arrays of passkey endpoints. The generated type declarations
in node_modules/@better-auth/passkey/dist/index-*.d.mts now emit use: (...)[] | undefined (optional) instead of use: (...)[] (required). Under exactOptionalPropertyTypes: true, | undefined on a non-optional
property is not assignable.

Current vs. Expected behavior

Current: tsc --noEmit fails with the following on the passkey(...) plugin instantiation:

error TS2322: Type '{ id: "passkey"; version: string; endpoints: { generatePasskeyRegistrationOptions: StrictEndpoint<"/passkey/generate-register-options", { method: "GET"; use: ((inputContext:
MiddlewareInputContext<MiddlewareOptions>) => Promise<...>)[] | undefined; query: ZodOptional<...>; metadata: { ...; }; }, PublicKeyCredentialC...' is not assignable to type 'BetterAuthPlugin'.
  Types of property 'endpoints' are incompatible.
    Property 'generatePasskeyRegistrationOptions' is incompatible with index signature.
      Type 'StrictEndpoint<"/passkey/generate-register-options", { method: "GET"; use: ...[] | undefined; ... }>' is not assignable to type 'Endpoint'.
        Types of property 'options' are incompatible.
          Type 'EndpointOptions' with 'exactOptionalPropertyTypes: true'.
            Types of property 'use' are incompatible.
              Type '... | undefined' is not assignable to type 'any[]'.
                Type 'undefined' is not assignable to type 'any[]'.

Same error on the client: passkeyClient() in createAuthClient({ plugins: [...] }).

Cascade impact: because the plugin doesn't satisfy BetterAuthPlugin, the entire betterAuth(...) return type degrades. Downstream, this breaks:

  • auth.api.signInMagicLink (and every other plugin-added API endpoint) disappears from the inferred type
  • authClient.passkey.addPasskey, authClient.passkey.listUserPasskeys, authClient.passkey.deletePasskey, authClient.signIn.passkey() - all disappear from inferred type
  • additionalFields (e.g., a role field) no longer appears on Session.user inferred type

All downstream errors resolve as soon as the root passkey(...) assignment typechecks.

Expected: passkey(...) returns a value assignable to BetterAuthPlugin under exactOptionalPropertyTypes: true, consistent with how #6502 fixed the same class of issue for the oidc-provider plugin.

What version of Better Auth are you using?

1.6.4 (also reproduces on 1.6.0, 1.6.1, 1.6.2, 1.6.3)

System info

{
  "system": {
    "platform": "darwin",
    "arch": "x64",
    "version": "Darwin Kernel Version 25.4.0: Thu Mar 19 19:27:54 PDT 2026; root:xnu-12377.101.15~1/RELEASE_X86_64",
    "release": "25.4.0",
    "cpuCount": 12,
    "cpuModel": "Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz",
    "totalMemory": "16.00 GB",
    "freeMemory": "2.60 GB"
  },
  "node": {
    "version": "v24.14.1",
    "env": "development"
  },
  "packageManager": {
    "name": "pnpm",
    "version": "10.33.0"
  },
  "frameworks": [
    {
      "name": "react",
      "version": "^19.2.5"
    }
  ],
  "databases": [
    {
      "name": "postgres",
      "version": "^3.4.9"
    },
    {
      "name": "drizzle",
      "version": "^0.45.2"
    }
  ],
  "betterAuth": {
    "version": "^1.6.4",
    "config": null
  }
}

Which area(s) are affected? (Select all that apply)

Types, Package

Auth config (if applicable)

import { betterAuth } from "better-auth"
export const auth = betterAuth({
  emailAndPassword: {  
    enabled: true
  },
});

Additional context

Related/priors:

  • #6491 (tracking issue for exactOptionalPropertyTypes: true) - closed, locked. Was closed after #6502 fixed the oidc-provider plugin, but other plugins remained broken.
  • #1578 (twoFactor() incompatibility) - closed, locked.
  • #6127 (anonymous plugin), #4804 (organization plugin), #8302 (dash plugin) - all closed, locked. Since these are locked, new regressions in related plugins cannot be reported as comments - hence a new issue for
    passkey.

Suggested fix direction: mirror #6502 - ensure the middleware use field on createAuthEndpoint declarations is always an explicit array (not array | undefined) in the passkey plugin, so the resulting endpoint
type satisfies EndpointOptions.use: any[] under exactOptionalPropertyTypes: true.

Workaround currently used: pin both better-auth and @better-auth/passkey to 1.5.6 (exact, not ^1.5.6 which pnpm will resolve to 1.6.x).

I tested the reproduction against @better-auth/passkey@1.6.4 and better-auth@1.6.4 on 2026-04-15. Happy to provide a minimal repo or test a fix PR if helpful.

Originally created by @denishamann on GitHub (Apr 15, 2026). Original GitHub issue: https://github.com/better-auth/better-auth/issues/9212 ### Is this suited for github? - [x] Yes, this is suited for github ### Reproduction **Minimal reproduction (self-contained, no repo needed)** 1. Create a fresh TypeScript project with this `tsconfig.json`: ```json { "compilerOptions": { "strict": true, "exactOptionalPropertyTypes": true, "module": "ESNext", "moduleResolution": "Bundler", "target": "ES2022" } } ``` 2. Install: ```bash pnpm add better-auth@1.6.4 @better-auth/passkey@1.6.4 ``` 3. Create `auth.ts`: ```typescript import { passkey } from "@better-auth/passkey"; import { betterAuth } from "better-auth"; export const auth = betterAuth({ plugins: [ passkey({ rpID: "localhost", rpName: "App", origin: "http://localhost:3000", }), ], }); ``` 4. Run `tsc --noEmit`. **Reproduces on**: `@better-auth/passkey` 1.6.0, 1.6.1, 1.6.2, 1.6.3, 1.6.4. **Does NOT reproduce on**: `@better-auth/passkey` 1.5.6. **Bisect**: the regression was introduced by #8843 (merged 2026-04-06, shipped in 1.6.0), which added `requireResourceOwnership` middleware to the `use: [...]` arrays of passkey endpoints. The generated type declarations in `node_modules/@better-auth/passkey/dist/index-*.d.mts` now emit `use: (...)[] | undefined` (optional) instead of `use: (...)[]` (required). Under `exactOptionalPropertyTypes: true`, `| undefined` on a non-optional property is not assignable. ### Current vs. Expected behavior **Current**: `tsc --noEmit` fails with the following on the `passkey(...)` plugin instantiation: ``` error TS2322: Type '{ id: "passkey"; version: string; endpoints: { generatePasskeyRegistrationOptions: StrictEndpoint<"/passkey/generate-register-options", { method: "GET"; use: ((inputContext: MiddlewareInputContext<MiddlewareOptions>) => Promise<...>)[] | undefined; query: ZodOptional<...>; metadata: { ...; }; }, PublicKeyCredentialC...' is not assignable to type 'BetterAuthPlugin'. Types of property 'endpoints' are incompatible. Property 'generatePasskeyRegistrationOptions' is incompatible with index signature. Type 'StrictEndpoint<"/passkey/generate-register-options", { method: "GET"; use: ...[] | undefined; ... }>' is not assignable to type 'Endpoint'. Types of property 'options' are incompatible. Type 'EndpointOptions' with 'exactOptionalPropertyTypes: true'. Types of property 'use' are incompatible. Type '... | undefined' is not assignable to type 'any[]'. Type 'undefined' is not assignable to type 'any[]'. ``` Same error on the client: `passkeyClient()` in `createAuthClient({ plugins: [...] })`. **Cascade impact**: because the plugin doesn't satisfy `BetterAuthPlugin`, the entire `betterAuth(...)` return type degrades. Downstream, this breaks: - `auth.api.signInMagicLink` (and every other plugin-added API endpoint) disappears from the inferred type - `authClient.passkey.addPasskey`, `authClient.passkey.listUserPasskeys`, `authClient.passkey.deletePasskey`, `authClient.signIn.passkey()` - all disappear from inferred type - `additionalFields` (e.g., a `role` field) no longer appears on `Session.user` inferred type All downstream errors resolve as soon as the root `passkey(...)` assignment typechecks. **Expected**: `passkey(...)` returns a value assignable to `BetterAuthPlugin` under `exactOptionalPropertyTypes: true`, consistent with how #6502 fixed the same class of issue for the `oidc-provider` plugin. ### What version of Better Auth are you using? 1.6.4 (also reproduces on 1.6.0, 1.6.1, 1.6.2, 1.6.3) ### System info ```bash { "system": { "platform": "darwin", "arch": "x64", "version": "Darwin Kernel Version 25.4.0: Thu Mar 19 19:27:54 PDT 2026; root:xnu-12377.101.15~1/RELEASE_X86_64", "release": "25.4.0", "cpuCount": 12, "cpuModel": "Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz", "totalMemory": "16.00 GB", "freeMemory": "2.60 GB" }, "node": { "version": "v24.14.1", "env": "development" }, "packageManager": { "name": "pnpm", "version": "10.33.0" }, "frameworks": [ { "name": "react", "version": "^19.2.5" } ], "databases": [ { "name": "postgres", "version": "^3.4.9" }, { "name": "drizzle", "version": "^0.45.2" } ], "betterAuth": { "version": "^1.6.4", "config": null } } ``` ### Which area(s) are affected? (Select all that apply) Types, Package ### Auth config (if applicable) ```typescript import { betterAuth } from "better-auth" export const auth = betterAuth({ emailAndPassword: { enabled: true }, }); ``` ### Additional context **Related/priors**: - #6491 (tracking issue for `exactOptionalPropertyTypes: true`) - closed, locked. Was closed after #6502 fixed the `oidc-provider` plugin, but other plugins remained broken. - #1578 (`twoFactor()` incompatibility) - closed, locked. - #6127 (`anonymous` plugin), #4804 (`organization` plugin), #8302 (`dash` plugin) - all closed, locked. Since these are locked, new regressions in related plugins cannot be reported as comments - hence a new issue for passkey. **Suggested fix direction**: mirror #6502 - ensure the middleware `use` field on `createAuthEndpoint` declarations is always an explicit array (not `array | undefined`) in the passkey plugin, so the resulting endpoint type satisfies `EndpointOptions.use: any[]` under `exactOptionalPropertyTypes: true`. **Workaround currently used**: pin both `better-auth` and `@better-auth/passkey` to `1.5.6` (exact, not `^1.5.6` which pnpm will resolve to 1.6.x). I tested the reproduction against `@better-auth/passkey@1.6.4` and `better-auth@1.6.4` on 2026-04-15. Happy to provide a minimal repo or test a fix PR if helpful.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#28635