# Better Auth Changelog - February 21-28, 2026

February 28, 2026

This changelog is generated by Notra for demonstration purposes. Notra is not affiliated with Better Auth.

## Highlights

### Critical: OTP race condition allows reuse across concurrent requests

Concurrent POST requests could verify the same OTP multiple times before deletion, bypassing single-use constraints and enabling account takeover. Fixed using atomic delete-before-verify across all OTP endpoints (email-otp, sign-in, password reset). [#8067](https://github.com/better-auth/better-auth/pull/8067) (Author: [@Oluwatobi-Mustapha](https://github.com/Oluwatobi-Mustapha/))

### API Keys now scoped to organizations with multi-config support

The api-key plugin now lives at `@better-auth/api-key` and supports multiple configurations per instance. Keys can be owned by organizations instead of just users. Schema changes: `userId` becomes `referenceId`, plus new `configId` and `references` fields. [#4210](https://github.com/better-auth/better-auth/pull/4210) (Author: [@ping-maxwell](https://github.com/ping-maxwell/))

### User enumeration prevention during signup

When email verification or manual signup is enabled, duplicate email attempts now return success without creating a session. Eliminates timing attacks that leak registered accounts. Optional `onExistingUserSignUp` callback for notifying account owners. [#8091](https://github.com/better-auth/better-auth/pull/8091) (Author: [@bytaesu](https://github.com/bytaesu/))

### ID token persistence in getAccessToken auto-refresh

`getAccessToken` was returning a new `idToken` from token refresh but not persisting it, leaving identity claims stale in storage. Now saved alongside access and refresh tokens. [#8211](https://github.com/better-auth/better-auth/pull/8211) (Author: [@GautamBytes](https://github.com/GautamBytes/))

### Built-in Cloudflare D1 database support

Added Kysely dialect for Cloudflare D1. BetterAuth now runs natively on Workers without custom adapters. Auto-detection via batch/exec/prepare method checks. [#7519](https://github.com/better-auth/better-auth/pull/7519) (Author: [@bytaesu](https://github.com/bytaesu/))

## More Updates

### Security

- **Keep auth_time stable across ID token refresh** [#8134](https://github.com/better-auth/better-auth/pull/8134) \- Per OpenID Connect Core 1.0, auth_time must not change when tokens refresh. Captures original login time and carries it through token rotation. Requires migration: add nullable authTime column to oauthRefreshToken. (Author: [@grant0417](https://github.com/grant0417/))

### Features & Enhancements

- **POST /update-session endpoint** [#8084](https://github.com/better-auth/better-auth/pull/8084) \- Update custom session fields and refresh the session cookie. (Author: [@himself65](https://github.com/himself65/))
- **CLI upgrade command** [#8204](https://github.com/better-auth/better-auth/pull/8204) \- `npx auth upgrade` scans package.json for better-auth deps, fetches latest versions, shows a table, and installs pinned versions. (Author: [@himself65](https://github.com/himself65/))

### Bug Fixes

- **Session changes broadcast to other tabs** [#8177](https://github.com/better-auth/better-auth/pull/8177) \- Sign-out and user updates now post to other open tabs so useSession stays in sync. Fixes dead-code broadcast function. (Author: [@Abhinav-kodes](https://github.com/Abhinav-kodes/))
- **Drizzle adapter date handling crash** [#8105](https://github.com/better-auth/better-auth/pull/8105) \- Removed input transformation that stringified dates before insert. Dates now convert only on read. (Author: [@ping-maxwell](https://github.com/ping-maxwell/))
- **Drizzle camelCase key mapping** [#8176](https://github.com/better-auth/better-auth/pull/8176) \- Schema introspection now handles camelCase column names on PostgreSQL. (Author: [@jonathan-teamstatus](https://github.com/jonathan-teamstatus/))

### Infrastructure

- **Prisma v7 migration** [#8166](https://github.com/better-auth/better-auth/pull/8166) \- Updated prisma-adapter and CLI. Changed: datasourceUrl now passed to PrismaClient constructor; call `prisma generate` explicitly after db push. (Author: [@himself65](https://github.com/himself65/))

### Documentation

- **New documentation and landing page** [#8195](https://github.com/better-auth/better-auth/pull/8195) \- Moved landing site into main repository. (Author: [@ping-maxwell](https://github.com/ping-maxwell/))
