#
tokens: 49707/50000 129/1091 files (page 2/49)
lines: off (toggle) GitHub
raw markdown copy
This is page 2 of 49. Use http://codebase.md/better-auth/better-auth?page={x} to view the full context.

# Directory Structure

```
├── .gitattributes
├── .github
│   ├── CODEOWNERS
│   ├── FUNDING.yml
│   ├── ISSUE_TEMPLATE
│   │   ├── bug_report.yml
│   │   └── feature_request.yml
│   ├── renovate.json5
│   └── workflows
│       ├── ci.yml
│       ├── e2e.yml
│       ├── preview.yml
│       └── release.yml
├── .gitignore
├── .npmrc
├── .nvmrc
├── .vscode
│   └── settings.json
├── banner-dark.png
├── banner.png
├── biome.json
├── bump.config.ts
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── demo
│   ├── expo-example
│   │   ├── .env.example
│   │   ├── .gitignore
│   │   ├── app.config.ts
│   │   ├── assets
│   │   │   ├── bg-image.jpeg
│   │   │   ├── fonts
│   │   │   │   └── SpaceMono-Regular.ttf
│   │   │   ├── icon.png
│   │   │   └── images
│   │   │       ├── adaptive-icon.png
│   │   │       ├── favicon.png
│   │   │       ├── logo.png
│   │   │       ├── partial-react-logo.png
│   │   │       ├── react-logo.png
│   │   │       ├── [email protected]
│   │   │       ├── [email protected]
│   │   │       └── splash.png
│   │   ├── babel.config.js
│   │   ├── components.json
│   │   ├── expo-env.d.ts
│   │   ├── index.ts
│   │   ├── metro.config.js
│   │   ├── nativewind-env.d.ts
│   │   ├── package.json
│   │   ├── README.md
│   │   ├── src
│   │   │   ├── app
│   │   │   │   ├── _layout.tsx
│   │   │   │   ├── api
│   │   │   │   │   └── auth
│   │   │   │   │       └── [...route]+api.ts
│   │   │   │   ├── dashboard.tsx
│   │   │   │   ├── forget-password.tsx
│   │   │   │   ├── index.tsx
│   │   │   │   └── sign-up.tsx
│   │   │   ├── components
│   │   │   │   ├── icons
│   │   │   │   │   └── google.tsx
│   │   │   │   └── ui
│   │   │   │       ├── avatar.tsx
│   │   │   │       ├── button.tsx
│   │   │   │       ├── card.tsx
│   │   │   │       ├── dialog.tsx
│   │   │   │       ├── input.tsx
│   │   │   │       ├── separator.tsx
│   │   │   │       └── text.tsx
│   │   │   ├── global.css
│   │   │   └── lib
│   │   │       ├── auth-client.ts
│   │   │       ├── auth.ts
│   │   │       ├── icons
│   │   │       │   ├── iconWithClassName.ts
│   │   │       │   └── X.tsx
│   │   │       └── utils.ts
│   │   ├── tailwind.config.js
│   │   └── tsconfig.json
│   └── nextjs
│       ├── .env.example
│       ├── .gitignore
│       ├── app
│       │   ├── (auth)
│       │   │   ├── forget-password
│       │   │   │   └── page.tsx
│       │   │   ├── reset-password
│       │   │   │   └── page.tsx
│       │   │   ├── sign-in
│       │   │   │   ├── loading.tsx
│       │   │   │   └── page.tsx
│       │   │   └── two-factor
│       │   │       ├── otp
│       │   │       │   └── page.tsx
│       │   │       └── page.tsx
│       │   ├── accept-invitation
│       │   │   └── [id]
│       │   │       ├── invitation-error.tsx
│       │   │       └── page.tsx
│       │   ├── admin
│       │   │   └── page.tsx
│       │   ├── api
│       │   │   └── auth
│       │   │       └── [...all]
│       │   │           └── route.ts
│       │   ├── apps
│       │   │   └── register
│       │   │       └── page.tsx
│       │   ├── client-test
│       │   │   └── page.tsx
│       │   ├── dashboard
│       │   │   ├── change-plan.tsx
│       │   │   ├── client.tsx
│       │   │   ├── organization-card.tsx
│       │   │   ├── page.tsx
│       │   │   ├── upgrade-button.tsx
│       │   │   └── user-card.tsx
│       │   ├── device
│       │   │   ├── approve
│       │   │   │   └── page.tsx
│       │   │   ├── denied
│       │   │   │   └── page.tsx
│       │   │   ├── layout.tsx
│       │   │   ├── page.tsx
│       │   │   └── success
│       │   │       └── page.tsx
│       │   ├── favicon.ico
│       │   ├── features.tsx
│       │   ├── fonts
│       │   │   ├── GeistMonoVF.woff
│       │   │   └── GeistVF.woff
│       │   ├── globals.css
│       │   ├── layout.tsx
│       │   ├── oauth
│       │   │   └── authorize
│       │   │       ├── concet-buttons.tsx
│       │   │       └── page.tsx
│       │   ├── page.tsx
│       │   └── pricing
│       │       └── page.tsx
│       ├── components
│       │   ├── account-switch.tsx
│       │   ├── blocks
│       │   │   └── pricing.tsx
│       │   ├── logo.tsx
│       │   ├── one-tap.tsx
│       │   ├── sign-in-btn.tsx
│       │   ├── sign-in.tsx
│       │   ├── sign-up.tsx
│       │   ├── theme-provider.tsx
│       │   ├── theme-toggle.tsx
│       │   ├── tier-labels.tsx
│       │   ├── ui
│       │   │   ├── accordion.tsx
│       │   │   ├── alert-dialog.tsx
│       │   │   ├── alert.tsx
│       │   │   ├── aspect-ratio.tsx
│       │   │   ├── avatar.tsx
│       │   │   ├── badge.tsx
│       │   │   ├── breadcrumb.tsx
│       │   │   ├── button.tsx
│       │   │   ├── calendar.tsx
│       │   │   ├── card.tsx
│       │   │   ├── carousel.tsx
│       │   │   ├── chart.tsx
│       │   │   ├── checkbox.tsx
│       │   │   ├── collapsible.tsx
│       │   │   ├── command.tsx
│       │   │   ├── context-menu.tsx
│       │   │   ├── copy-button.tsx
│       │   │   ├── dialog.tsx
│       │   │   ├── drawer.tsx
│       │   │   ├── dropdown-menu.tsx
│       │   │   ├── form.tsx
│       │   │   ├── hover-card.tsx
│       │   │   ├── input-otp.tsx
│       │   │   ├── input.tsx
│       │   │   ├── label.tsx
│       │   │   ├── menubar.tsx
│       │   │   ├── navigation-menu.tsx
│       │   │   ├── pagination.tsx
│       │   │   ├── password-input.tsx
│       │   │   ├── popover.tsx
│       │   │   ├── progress.tsx
│       │   │   ├── radio-group.tsx
│       │   │   ├── resizable.tsx
│       │   │   ├── scroll-area.tsx
│       │   │   ├── select.tsx
│       │   │   ├── separator.tsx
│       │   │   ├── sheet.tsx
│       │   │   ├── skeleton.tsx
│       │   │   ├── slider.tsx
│       │   │   ├── sonner.tsx
│       │   │   ├── switch.tsx
│       │   │   ├── table.tsx
│       │   │   ├── tabs.tsx
│       │   │   ├── tabs2.tsx
│       │   │   ├── textarea.tsx
│       │   │   ├── toast.tsx
│       │   │   ├── toaster.tsx
│       │   │   ├── toggle-group.tsx
│       │   │   ├── toggle.tsx
│       │   │   └── tooltip.tsx
│       │   └── wrapper.tsx
│       ├── components.json
│       ├── hooks
│       │   └── use-toast.ts
│       ├── lib
│       │   ├── auth-client.ts
│       │   ├── auth-types.ts
│       │   ├── auth.ts
│       │   ├── email
│       │   │   ├── invitation.tsx
│       │   │   ├── resend.ts
│       │   │   └── reset-password.tsx
│       │   ├── metadata.ts
│       │   ├── shared.ts
│       │   └── utils.ts
│       ├── middleware.ts
│       ├── next.config.ts
│       ├── package.json
│       ├── postcss.config.mjs
│       ├── public
│       │   ├── __og.png
│       │   ├── _og.png
│       │   ├── favicon
│       │   │   ├── android-chrome-192x192.png
│       │   │   ├── android-chrome-512x512.png
│       │   │   ├── apple-touch-icon.png
│       │   │   ├── favicon-16x16.png
│       │   │   ├── favicon-32x32.png
│       │   │   ├── favicon.ico
│       │   │   ├── light
│       │   │   │   ├── android-chrome-192x192.png
│       │   │   │   ├── android-chrome-512x512.png
│       │   │   │   ├── apple-touch-icon.png
│       │   │   │   ├── favicon-16x16.png
│       │   │   │   ├── favicon-32x32.png
│       │   │   │   ├── favicon.ico
│       │   │   │   └── site.webmanifest
│       │   │   └── site.webmanifest
│       │   ├── logo.svg
│       │   └── og.png
│       ├── README.md
│       ├── tailwind.config.ts
│       ├── tsconfig.json
│       └── turbo.json
├── docker-compose.yml
├── docs
│   ├── .env.example
│   ├── .gitignore
│   ├── app
│   │   ├── api
│   │   │   ├── ai-chat
│   │   │   │   └── route.ts
│   │   │   ├── analytics
│   │   │   │   ├── conversation
│   │   │   │   │   └── route.ts
│   │   │   │   ├── event
│   │   │   │   │   └── route.ts
│   │   │   │   └── feedback
│   │   │   │       └── route.ts
│   │   │   ├── chat
│   │   │   │   └── route.ts
│   │   │   ├── og
│   │   │   │   └── route.tsx
│   │   │   ├── og-release
│   │   │   │   └── route.tsx
│   │   │   ├── search
│   │   │   │   └── route.ts
│   │   │   └── support
│   │   │       └── route.ts
│   │   ├── blog
│   │   │   ├── _components
│   │   │   │   ├── _layout.tsx
│   │   │   │   ├── blog-list.tsx
│   │   │   │   ├── changelog-layout.tsx
│   │   │   │   ├── default-changelog.tsx
│   │   │   │   ├── fmt-dates.tsx
│   │   │   │   ├── icons.tsx
│   │   │   │   ├── stat-field.tsx
│   │   │   │   └── support.tsx
│   │   │   ├── [[...slug]]
│   │   │   │   └── page.tsx
│   │   │   └── layout.tsx
│   │   ├── changelogs
│   │   │   ├── _components
│   │   │   │   ├── _layout.tsx
│   │   │   │   ├── changelog-layout.tsx
│   │   │   │   ├── default-changelog.tsx
│   │   │   │   ├── fmt-dates.tsx
│   │   │   │   ├── grid-pattern.tsx
│   │   │   │   ├── icons.tsx
│   │   │   │   └── stat-field.tsx
│   │   │   ├── [[...slug]]
│   │   │   │   └── page.tsx
│   │   │   └── layout.tsx
│   │   ├── community
│   │   │   ├── _components
│   │   │   │   ├── header.tsx
│   │   │   │   └── stats.tsx
│   │   │   └── page.tsx
│   │   ├── docs
│   │   │   ├── [[...slug]]
│   │   │   │   ├── page.client.tsx
│   │   │   │   └── page.tsx
│   │   │   ├── layout.tsx
│   │   │   └── lib
│   │   │       └── get-llm-text.ts
│   │   ├── global.css
│   │   ├── layout.config.tsx
│   │   ├── layout.tsx
│   │   ├── llms.txt
│   │   │   ├── [...slug]
│   │   │   │   └── route.ts
│   │   │   └── route.ts
│   │   ├── not-found.tsx
│   │   ├── page.tsx
│   │   ├── reference
│   │   │   └── route.ts
│   │   ├── sitemap.xml
│   │   ├── static.json
│   │   │   └── route.ts
│   │   └── v1
│   │       ├── _components
│   │       │   └── v1-text.tsx
│   │       ├── bg-line.tsx
│   │       └── page.tsx
│   ├── assets
│   │   ├── Geist.ttf
│   │   └── GeistMono.ttf
│   ├── components
│   │   ├── ai-chat-modal.tsx
│   │   ├── anchor-scroll-fix.tsx
│   │   ├── api-method-tabs.tsx
│   │   ├── api-method.tsx
│   │   ├── banner.tsx
│   │   ├── blocks
│   │   │   └── features.tsx
│   │   ├── builder
│   │   │   ├── beam.tsx
│   │   │   ├── code-tabs
│   │   │   │   ├── code-editor.tsx
│   │   │   │   ├── code-tabs.tsx
│   │   │   │   ├── index.tsx
│   │   │   │   ├── tab-bar.tsx
│   │   │   │   └── theme.ts
│   │   │   ├── index.tsx
│   │   │   ├── sign-in.tsx
│   │   │   ├── sign-up.tsx
│   │   │   ├── social-provider.tsx
│   │   │   ├── store.ts
│   │   │   └── tabs.tsx
│   │   ├── display-techstack.tsx
│   │   ├── divider-text.tsx
│   │   ├── docs
│   │   │   ├── docs.client.tsx
│   │   │   ├── docs.tsx
│   │   │   ├── layout
│   │   │   │   ├── nav.tsx
│   │   │   │   ├── theme-toggle.tsx
│   │   │   │   ├── toc-thumb.tsx
│   │   │   │   └── toc.tsx
│   │   │   ├── page.client.tsx
│   │   │   ├── page.tsx
│   │   │   ├── shared.tsx
│   │   │   └── ui
│   │   │       ├── button.tsx
│   │   │       ├── collapsible.tsx
│   │   │       ├── popover.tsx
│   │   │       └── scroll-area.tsx
│   │   ├── endpoint.tsx
│   │   ├── features.tsx
│   │   ├── floating-ai-search.tsx
│   │   ├── fork-button.tsx
│   │   ├── generate-apple-jwt.tsx
│   │   ├── generate-secret.tsx
│   │   ├── github-stat.tsx
│   │   ├── icons.tsx
│   │   ├── landing
│   │   │   ├── gradient-bg.tsx
│   │   │   ├── grid-pattern.tsx
│   │   │   ├── hero.tsx
│   │   │   ├── section-svg.tsx
│   │   │   ├── section.tsx
│   │   │   ├── spotlight.tsx
│   │   │   └── testimonials.tsx
│   │   ├── logo-context-menu.tsx
│   │   ├── logo.tsx
│   │   ├── markdown-renderer.tsx
│   │   ├── markdown.tsx
│   │   ├── mdx
│   │   │   ├── add-to-cursor.tsx
│   │   │   └── database-tables.tsx
│   │   ├── message-feedback.tsx
│   │   ├── mobile-search-icon.tsx
│   │   ├── nav-bar.tsx
│   │   ├── nav-link.tsx
│   │   ├── nav-mobile.tsx
│   │   ├── promo-card.tsx
│   │   ├── resource-card.tsx
│   │   ├── resource-grid.tsx
│   │   ├── resource-section.tsx
│   │   ├── ripple.tsx
│   │   ├── search-dialog.tsx
│   │   ├── side-bar.tsx
│   │   ├── sidebar-content.tsx
│   │   ├── techstack-icons.tsx
│   │   ├── theme-provider.tsx
│   │   ├── theme-toggler.tsx
│   │   └── ui
│   │       ├── accordion.tsx
│   │       ├── alert-dialog.tsx
│   │       ├── alert.tsx
│   │       ├── aside-link.tsx
│   │       ├── aspect-ratio.tsx
│   │       ├── avatar.tsx
│   │       ├── background-beams.tsx
│   │       ├── background-boxes.tsx
│   │       ├── badge.tsx
│   │       ├── breadcrumb.tsx
│   │       ├── button.tsx
│   │       ├── calendar.tsx
│   │       ├── callout.tsx
│   │       ├── card.tsx
│   │       ├── carousel.tsx
│   │       ├── chart.tsx
│   │       ├── checkbox.tsx
│   │       ├── code-block.tsx
│   │       ├── collapsible.tsx
│   │       ├── command.tsx
│   │       ├── context-menu.tsx
│   │       ├── dialog.tsx
│   │       ├── drawer.tsx
│   │       ├── dropdown-menu.tsx
│   │       ├── dynamic-code-block.tsx
│   │       ├── fade-in.tsx
│   │       ├── form.tsx
│   │       ├── hover-card.tsx
│   │       ├── input-otp.tsx
│   │       ├── input.tsx
│   │       ├── label.tsx
│   │       ├── menubar.tsx
│   │       ├── navigation-menu.tsx
│   │       ├── pagination.tsx
│   │       ├── popover.tsx
│   │       ├── progress.tsx
│   │       ├── radio-group.tsx
│   │       ├── resizable.tsx
│   │       ├── scroll-area.tsx
│   │       ├── select.tsx
│   │       ├── separator.tsx
│   │       ├── sheet.tsx
│   │       ├── sidebar.tsx
│   │       ├── skeleton.tsx
│   │       ├── slider.tsx
│   │       ├── sonner.tsx
│   │       ├── sparkles.tsx
│   │       ├── switch.tsx
│   │       ├── table.tsx
│   │       ├── tabs.tsx
│   │       ├── textarea.tsx
│   │       ├── toggle-group.tsx
│   │       ├── toggle.tsx
│   │       ├── tooltip-docs.tsx
│   │       ├── tooltip.tsx
│   │       └── use-copy-button.tsx
│   ├── components.json
│   ├── content
│   │   ├── blogs
│   │   │   ├── 0-supabase-auth-to-planetscale-migration.mdx
│   │   │   ├── 1-3.mdx
│   │   │   ├── authjs-joins-better-auth.mdx
│   │   │   └── seed-round.mdx
│   │   ├── changelogs
│   │   │   ├── 1-2.mdx
│   │   │   └── 1.0.mdx
│   │   └── docs
│   │       ├── adapters
│   │       │   ├── community-adapters.mdx
│   │       │   ├── drizzle.mdx
│   │       │   ├── mongo.mdx
│   │       │   ├── mssql.mdx
│   │       │   ├── mysql.mdx
│   │       │   ├── other-relational-databases.mdx
│   │       │   ├── postgresql.mdx
│   │       │   ├── prisma.mdx
│   │       │   └── sqlite.mdx
│   │       ├── authentication
│   │       │   ├── apple.mdx
│   │       │   ├── atlassian.mdx
│   │       │   ├── cognito.mdx
│   │       │   ├── discord.mdx
│   │       │   ├── dropbox.mdx
│   │       │   ├── email-password.mdx
│   │       │   ├── facebook.mdx
│   │       │   ├── figma.mdx
│   │       │   ├── github.mdx
│   │       │   ├── gitlab.mdx
│   │       │   ├── google.mdx
│   │       │   ├── huggingface.mdx
│   │       │   ├── kakao.mdx
│   │       │   ├── kick.mdx
│   │       │   ├── line.mdx
│   │       │   ├── linear.mdx
│   │       │   ├── linkedin.mdx
│   │       │   ├── microsoft.mdx
│   │       │   ├── naver.mdx
│   │       │   ├── notion.mdx
│   │       │   ├── other-social-providers.mdx
│   │       │   ├── paypal.mdx
│   │       │   ├── reddit.mdx
│   │       │   ├── roblox.mdx
│   │       │   ├── salesforce.mdx
│   │       │   ├── slack.mdx
│   │       │   ├── spotify.mdx
│   │       │   ├── tiktok.mdx
│   │       │   ├── twitch.mdx
│   │       │   ├── twitter.mdx
│   │       │   ├── vk.mdx
│   │       │   └── zoom.mdx
│   │       ├── basic-usage.mdx
│   │       ├── comparison.mdx
│   │       ├── concepts
│   │       │   ├── api.mdx
│   │       │   ├── cli.mdx
│   │       │   ├── client.mdx
│   │       │   ├── cookies.mdx
│   │       │   ├── database.mdx
│   │       │   ├── email.mdx
│   │       │   ├── hooks.mdx
│   │       │   ├── oauth.mdx
│   │       │   ├── plugins.mdx
│   │       │   ├── rate-limit.mdx
│   │       │   ├── session-management.mdx
│   │       │   ├── typescript.mdx
│   │       │   └── users-accounts.mdx
│   │       ├── examples
│   │       │   ├── astro.mdx
│   │       │   ├── next-js.mdx
│   │       │   ├── nuxt.mdx
│   │       │   ├── remix.mdx
│   │       │   └── svelte-kit.mdx
│   │       ├── guides
│   │       │   ├── auth0-migration-guide.mdx
│   │       │   ├── browser-extension-guide.mdx
│   │       │   ├── clerk-migration-guide.mdx
│   │       │   ├── create-a-db-adapter.mdx
│   │       │   ├── next-auth-migration-guide.mdx
│   │       │   ├── optimizing-for-performance.mdx
│   │       │   ├── saml-sso-with-okta.mdx
│   │       │   ├── supabase-migration-guide.mdx
│   │       │   └── your-first-plugin.mdx
│   │       ├── installation.mdx
│   │       ├── integrations
│   │       │   ├── astro.mdx
│   │       │   ├── convex.mdx
│   │       │   ├── elysia.mdx
│   │       │   ├── expo.mdx
│   │       │   ├── express.mdx
│   │       │   ├── fastify.mdx
│   │       │   ├── hono.mdx
│   │       │   ├── lynx.mdx
│   │       │   ├── nestjs.mdx
│   │       │   ├── next.mdx
│   │       │   ├── nitro.mdx
│   │       │   ├── nuxt.mdx
│   │       │   ├── remix.mdx
│   │       │   ├── solid-start.mdx
│   │       │   ├── svelte-kit.mdx
│   │       │   ├── tanstack.mdx
│   │       │   └── waku.mdx
│   │       ├── introduction.mdx
│   │       ├── meta.json
│   │       ├── plugins
│   │       │   ├── 2fa.mdx
│   │       │   ├── admin.mdx
│   │       │   ├── anonymous.mdx
│   │       │   ├── api-key.mdx
│   │       │   ├── autumn.mdx
│   │       │   ├── bearer.mdx
│   │       │   ├── captcha.mdx
│   │       │   ├── community-plugins.mdx
│   │       │   ├── device-authorization.mdx
│   │       │   ├── dodopayments.mdx
│   │       │   ├── dub.mdx
│   │       │   ├── email-otp.mdx
│   │       │   ├── generic-oauth.mdx
│   │       │   ├── have-i-been-pwned.mdx
│   │       │   ├── jwt.mdx
│   │       │   ├── last-login-method.mdx
│   │       │   ├── magic-link.mdx
│   │       │   ├── mcp.mdx
│   │       │   ├── multi-session.mdx
│   │       │   ├── oauth-proxy.mdx
│   │       │   ├── oidc-provider.mdx
│   │       │   ├── one-tap.mdx
│   │       │   ├── one-time-token.mdx
│   │       │   ├── open-api.mdx
│   │       │   ├── organization.mdx
│   │       │   ├── passkey.mdx
│   │       │   ├── phone-number.mdx
│   │       │   ├── polar.mdx
│   │       │   ├── siwe.mdx
│   │       │   ├── sso.mdx
│   │       │   ├── stripe.mdx
│   │       │   └── username.mdx
│   │       └── reference
│   │           ├── contributing.mdx
│   │           ├── faq.mdx
│   │           ├── options.mdx
│   │           ├── resources.mdx
│   │           ├── security.mdx
│   │           └── telemetry.mdx
│   ├── hooks
│   │   └── use-mobile.ts
│   ├── ignore-build.sh
│   ├── lib
│   │   ├── blog.ts
│   │   ├── chat
│   │   │   └── inkeep-qa-schema.ts
│   │   ├── constants.ts
│   │   ├── export-search-indexes.ts
│   │   ├── inkeep-analytics.ts
│   │   ├── is-active.ts
│   │   ├── metadata.ts
│   │   ├── source.ts
│   │   └── utils.ts
│   ├── next.config.js
│   ├── package.json
│   ├── postcss.config.js
│   ├── proxy.ts
│   ├── public
│   │   ├── avatars
│   │   │   └── beka.jpg
│   │   ├── blogs
│   │   │   ├── authjs-joins.png
│   │   │   ├── seed-round.png
│   │   │   └── supabase-ps.png
│   │   ├── branding
│   │   │   ├── better-auth-brand-assets.zip
│   │   │   ├── better-auth-logo-dark.png
│   │   │   ├── better-auth-logo-dark.svg
│   │   │   ├── better-auth-logo-light.png
│   │   │   ├── better-auth-logo-light.svg
│   │   │   ├── better-auth-logo-wordmark-dark.png
│   │   │   ├── better-auth-logo-wordmark-dark.svg
│   │   │   ├── better-auth-logo-wordmark-light.png
│   │   │   └── better-auth-logo-wordmark-light.svg
│   │   ├── extension-id.png
│   │   ├── favicon
│   │   │   ├── android-chrome-192x192.png
│   │   │   ├── android-chrome-512x512.png
│   │   │   ├── apple-touch-icon.png
│   │   │   ├── favicon-16x16.png
│   │   │   ├── favicon-32x32.png
│   │   │   ├── favicon.ico
│   │   │   ├── light
│   │   │   │   ├── android-chrome-192x192.png
│   │   │   │   ├── android-chrome-512x512.png
│   │   │   │   ├── apple-touch-icon.png
│   │   │   │   ├── favicon-16x16.png
│   │   │   │   ├── favicon-32x32.png
│   │   │   │   ├── favicon.ico
│   │   │   │   └── site.webmanifest
│   │   │   └── site.webmanifest
│   │   ├── images
│   │   │   └── blogs
│   │   │       └── better auth (1).png
│   │   ├── logo.png
│   │   ├── logo.svg
│   │   ├── LogoDark.webp
│   │   ├── LogoLight.webp
│   │   ├── og.png
│   │   ├── open-api-reference.png
│   │   ├── people-say
│   │   │   ├── code-with-antonio.jpg
│   │   │   ├── dagmawi-babi.png
│   │   │   ├── dax.png
│   │   │   ├── dev-ed.png
│   │   │   ├── egoist.png
│   │   │   ├── guillermo-rauch.png
│   │   │   ├── jonathan-wilke.png
│   │   │   ├── josh-tried-coding.jpg
│   │   │   ├── kitze.jpg
│   │   │   ├── lazar-nikolov.png
│   │   │   ├── nizzy.png
│   │   │   ├── omar-mcadam.png
│   │   │   ├── ryan-vogel.jpg
│   │   │   ├── saltyatom.jpg
│   │   │   ├── sebastien-chopin.png
│   │   │   ├── shreyas-mididoddi.png
│   │   │   ├── tech-nerd.png
│   │   │   ├── theo.png
│   │   │   ├── vybhav-bhargav.png
│   │   │   └── xavier-pladevall.jpg
│   │   ├── plus.svg
│   │   ├── release-og
│   │   │   ├── 1-2.png
│   │   │   ├── 1-3.png
│   │   │   └── changelog-og.png
│   │   └── v1-og.png
│   ├── README.md
│   ├── scripts
│   │   ├── endpoint-to-doc
│   │   │   ├── index.ts
│   │   │   ├── input.ts
│   │   │   ├── output.mdx
│   │   │   └── readme.md
│   │   └── sync-orama.ts
│   ├── source.config.ts
│   ├── tailwind.config.js
│   ├── tsconfig.json
│   └── turbo.json
├── e2e
│   ├── integration
│   │   ├── package.json
│   │   ├── playwright.config.ts
│   │   ├── solid-vinxi
│   │   │   ├── .gitignore
│   │   │   ├── app.config.ts
│   │   │   ├── e2e
│   │   │   │   ├── test.spec.ts
│   │   │   │   └── utils.ts
│   │   │   ├── package.json
│   │   │   ├── public
│   │   │   │   └── favicon.ico
│   │   │   ├── src
│   │   │   │   ├── app.tsx
│   │   │   │   ├── entry-client.tsx
│   │   │   │   ├── entry-server.tsx
│   │   │   │   ├── global.d.ts
│   │   │   │   ├── lib
│   │   │   │   │   ├── auth-client.ts
│   │   │   │   │   └── auth.ts
│   │   │   │   └── routes
│   │   │   │       ├── [...404].tsx
│   │   │   │       ├── api
│   │   │   │       │   └── auth
│   │   │   │       │       └── [...all].ts
│   │   │   │       └── index.tsx
│   │   │   └── tsconfig.json
│   │   ├── test-utils
│   │   │   ├── package.json
│   │   │   └── src
│   │   │       └── playwright.ts
│   │   └── vanilla-node
│   │       ├── e2e
│   │       │   ├── app.ts
│   │       │   ├── domain.spec.ts
│   │       │   ├── postgres-js.spec.ts
│   │       │   ├── test.spec.ts
│   │       │   └── utils.ts
│   │       ├── index.html
│   │       ├── package.json
│   │       ├── src
│   │       │   ├── main.ts
│   │       │   └── vite-env.d.ts
│   │       ├── tsconfig.json
│   │       └── vite.config.ts
│   └── smoke
│       ├── package.json
│       ├── test
│       │   ├── bun.spec.ts
│       │   ├── cloudflare.spec.ts
│       │   ├── deno.spec.ts
│       │   ├── fixtures
│       │   │   ├── bun-simple.ts
│       │   │   ├── cloudflare
│       │   │   │   ├── .gitignore
│       │   │   │   ├── drizzle
│       │   │   │   │   ├── 0000_clean_vector.sql
│       │   │   │   │   └── meta
│       │   │   │   │       ├── _journal.json
│       │   │   │   │       └── 0000_snapshot.json
│       │   │   │   ├── drizzle.config.ts
│       │   │   │   ├── package.json
│       │   │   │   ├── src
│       │   │   │   │   ├── auth-schema.ts
│       │   │   │   │   ├── db.ts
│       │   │   │   │   └── index.ts
│       │   │   │   ├── test
│       │   │   │   │   ├── apply-migrations.ts
│       │   │   │   │   ├── env.d.ts
│       │   │   │   │   └── index.test.ts
│       │   │   │   ├── tsconfig.json
│       │   │   │   ├── vitest.config.ts
│       │   │   │   ├── worker-configuration.d.ts
│       │   │   │   └── wrangler.json
│       │   │   ├── deno-simple.ts
│       │   │   ├── tsconfig-exact-optional-property-types
│       │   │   │   ├── package.json
│       │   │   │   ├── src
│       │   │   │   │   ├── index.ts
│       │   │   │   │   └── user-additional-fields.ts
│       │   │   │   └── tsconfig.json
│       │   │   ├── tsconfig-verbatim-module-syntax-node10
│       │   │   │   ├── package.json
│       │   │   │   ├── src
│       │   │   │   │   └── index.ts
│       │   │   │   └── tsconfig.json
│       │   │   └── vite
│       │   │       ├── package.json
│       │   │       ├── src
│       │   │       │   ├── client.ts
│       │   │       │   └── server.ts
│       │   │       ├── tsconfig.json
│       │   │       └── vite.config.ts
│       │   ├── ssr.ts
│       │   ├── typecheck.spec.ts
│       │   └── vite.spec.ts
│       └── tsconfig.json
├── LICENSE.md
├── package.json
├── packages
│   ├── better-auth
│   │   ├── package.json
│   │   ├── README.md
│   │   ├── src
│   │   │   ├── __snapshots__
│   │   │   │   └── init.test.ts.snap
│   │   │   ├── adapters
│   │   │   │   ├── adapter-factory
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── test
│   │   │   │   │   │   ├── __snapshots__
│   │   │   │   │   │   │   └── adapter-factory.test.ts.snap
│   │   │   │   │   │   └── adapter-factory.test.ts
│   │   │   │   │   └── types.ts
│   │   │   │   ├── create-test-suite.ts
│   │   │   │   ├── drizzle-adapter
│   │   │   │   │   ├── drizzle-adapter.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   └── test
│   │   │   │   │       ├── .gitignore
│   │   │   │   │       ├── adapter.drizzle.mysql.test.ts
│   │   │   │   │       ├── adapter.drizzle.pg.test.ts
│   │   │   │   │       ├── adapter.drizzle.sqlite.test.ts
│   │   │   │   │       └── generate-schema.ts
│   │   │   │   ├── index.ts
│   │   │   │   ├── kysely-adapter
│   │   │   │   │   ├── bun-sqlite-dialect.ts
│   │   │   │   │   ├── dialect.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── kysely-adapter.ts
│   │   │   │   │   ├── node-sqlite-dialect.ts
│   │   │   │   │   ├── test
│   │   │   │   │   │   ├── adapter.kysely.mssql.test.ts
│   │   │   │   │   │   ├── adapter.kysely.mysql.test.ts
│   │   │   │   │   │   ├── adapter.kysely.pg.test.ts
│   │   │   │   │   │   ├── adapter.kysely.sqlite.test.ts
│   │   │   │   │   │   └── node-sqlite-dialect.test.ts
│   │   │   │   │   └── types.ts
│   │   │   │   ├── memory-adapter
│   │   │   │   │   ├── adapter.memory.test.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   └── memory-adapter.ts
│   │   │   │   ├── mongodb-adapter
│   │   │   │   │   ├── adapter.mongo-db.test.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   └── mongodb-adapter.ts
│   │   │   │   ├── prisma-adapter
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── prisma-adapter.ts
│   │   │   │   │   └── test
│   │   │   │   │       ├── .gitignore
│   │   │   │   │       ├── base.prisma
│   │   │   │   │       ├── generate-auth-config.ts
│   │   │   │   │       ├── generate-prisma-schema.ts
│   │   │   │   │       ├── get-prisma-client.ts
│   │   │   │   │       ├── prisma.mysql.test.ts
│   │   │   │   │       ├── prisma.pg.test.ts
│   │   │   │   │       ├── prisma.sqlite.test.ts
│   │   │   │   │       └── push-prisma-schema.ts
│   │   │   │   ├── test-adapter.ts
│   │   │   │   ├── test.ts
│   │   │   │   ├── tests
│   │   │   │   │   ├── auth-flow.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── normal.ts
│   │   │   │   │   ├── number-id.ts
│   │   │   │   │   ├── performance.ts
│   │   │   │   │   └── transactions.ts
│   │   │   │   └── utils.ts
│   │   │   ├── api
│   │   │   │   ├── check-endpoint-conflicts.test.ts
│   │   │   │   ├── index.test.ts
│   │   │   │   ├── index.ts
│   │   │   │   ├── middlewares
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── origin-check.test.ts
│   │   │   │   │   └── origin-check.ts
│   │   │   │   ├── rate-limiter
│   │   │   │   │   ├── index.ts
│   │   │   │   │   └── rate-limiter.test.ts
│   │   │   │   ├── routes
│   │   │   │   │   ├── account.test.ts
│   │   │   │   │   ├── account.ts
│   │   │   │   │   ├── callback.ts
│   │   │   │   │   ├── email-verification.test.ts
│   │   │   │   │   ├── email-verification.ts
│   │   │   │   │   ├── error.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── ok.ts
│   │   │   │   │   ├── reset-password.test.ts
│   │   │   │   │   ├── reset-password.ts
│   │   │   │   │   ├── session-api.test.ts
│   │   │   │   │   ├── session.ts
│   │   │   │   │   ├── sign-in.test.ts
│   │   │   │   │   ├── sign-in.ts
│   │   │   │   │   ├── sign-out.test.ts
│   │   │   │   │   ├── sign-out.ts
│   │   │   │   │   ├── sign-up.test.ts
│   │   │   │   │   ├── sign-up.ts
│   │   │   │   │   ├── update-user.test.ts
│   │   │   │   │   └── update-user.ts
│   │   │   │   ├── to-auth-endpoints.test.ts
│   │   │   │   └── to-auth-endpoints.ts
│   │   │   ├── auth.test.ts
│   │   │   ├── auth.ts
│   │   │   ├── call.test.ts
│   │   │   ├── client
│   │   │   │   ├── client-ssr.test.ts
│   │   │   │   ├── client.test.ts
│   │   │   │   ├── config.ts
│   │   │   │   ├── fetch-plugins.ts
│   │   │   │   ├── index.ts
│   │   │   │   ├── lynx
│   │   │   │   │   ├── index.ts
│   │   │   │   │   └── lynx-store.ts
│   │   │   │   ├── parser.ts
│   │   │   │   ├── path-to-object.ts
│   │   │   │   ├── plugins
│   │   │   │   │   ├── index.ts
│   │   │   │   │   └── infer-plugin.ts
│   │   │   │   ├── proxy.ts
│   │   │   │   ├── query.ts
│   │   │   │   ├── react
│   │   │   │   │   ├── index.ts
│   │   │   │   │   └── react-store.ts
│   │   │   │   ├── session-atom.ts
│   │   │   │   ├── solid
│   │   │   │   │   ├── index.ts
│   │   │   │   │   └── solid-store.ts
│   │   │   │   ├── svelte
│   │   │   │   │   └── index.ts
│   │   │   │   ├── test-plugin.ts
│   │   │   │   ├── types.ts
│   │   │   │   ├── url.test.ts
│   │   │   │   ├── vanilla.ts
│   │   │   │   └── vue
│   │   │   │       ├── index.ts
│   │   │   │       └── vue-store.ts
│   │   │   ├── cookies
│   │   │   │   ├── check-cookies.ts
│   │   │   │   ├── cookie-utils.ts
│   │   │   │   ├── cookies.test.ts
│   │   │   │   └── index.ts
│   │   │   ├── crypto
│   │   │   │   ├── buffer.ts
│   │   │   │   ├── hash.ts
│   │   │   │   ├── index.ts
│   │   │   │   ├── jwt.ts
│   │   │   │   ├── password.test.ts
│   │   │   │   ├── password.ts
│   │   │   │   └── random.ts
│   │   │   ├── db
│   │   │   │   ├── db.test.ts
│   │   │   │   ├── field.ts
│   │   │   │   ├── get-migration.ts
│   │   │   │   ├── get-schema.ts
│   │   │   │   ├── get-tables.test.ts
│   │   │   │   ├── get-tables.ts
│   │   │   │   ├── index.ts
│   │   │   │   ├── internal-adapter.test.ts
│   │   │   │   ├── internal-adapter.ts
│   │   │   │   ├── schema.ts
│   │   │   │   ├── secondary-storage.test.ts
│   │   │   │   ├── to-zod.ts
│   │   │   │   ├── utils.ts
│   │   │   │   └── with-hooks.ts
│   │   │   ├── index.ts
│   │   │   ├── init.test.ts
│   │   │   ├── init.ts
│   │   │   ├── integrations
│   │   │   │   ├── next-js.ts
│   │   │   │   ├── node.ts
│   │   │   │   ├── react-start.ts
│   │   │   │   ├── solid-start.ts
│   │   │   │   └── svelte-kit.ts
│   │   │   ├── oauth2
│   │   │   │   ├── index.ts
│   │   │   │   ├── link-account.test.ts
│   │   │   │   ├── link-account.ts
│   │   │   │   ├── state.ts
│   │   │   │   └── utils.ts
│   │   │   ├── plugins
│   │   │   │   ├── access
│   │   │   │   │   ├── access.test.ts
│   │   │   │   │   ├── access.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   └── types.ts
│   │   │   │   ├── additional-fields
│   │   │   │   │   ├── additional-fields.test.ts
│   │   │   │   │   └── client.ts
│   │   │   │   ├── admin
│   │   │   │   │   ├── access
│   │   │   │   │   │   ├── index.ts
│   │   │   │   │   │   └── statement.ts
│   │   │   │   │   ├── admin.test.ts
│   │   │   │   │   ├── admin.ts
│   │   │   │   │   ├── client.ts
│   │   │   │   │   ├── error-codes.ts
│   │   │   │   │   ├── has-permission.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── schema.ts
│   │   │   │   │   └── types.ts
│   │   │   │   ├── anonymous
│   │   │   │   │   ├── anon.test.ts
│   │   │   │   │   ├── client.ts
│   │   │   │   │   └── index.ts
│   │   │   │   ├── api-key
│   │   │   │   │   ├── api-key.test.ts
│   │   │   │   │   ├── client.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── rate-limit.ts
│   │   │   │   │   ├── routes
│   │   │   │   │   │   ├── create-api-key.ts
│   │   │   │   │   │   ├── delete-all-expired-api-keys.ts
│   │   │   │   │   │   ├── delete-api-key.ts
│   │   │   │   │   │   ├── get-api-key.ts
│   │   │   │   │   │   ├── index.ts
│   │   │   │   │   │   ├── list-api-keys.ts
│   │   │   │   │   │   ├── update-api-key.ts
│   │   │   │   │   │   └── verify-api-key.ts
│   │   │   │   │   ├── schema.ts
│   │   │   │   │   └── types.ts
│   │   │   │   ├── bearer
│   │   │   │   │   ├── bearer.test.ts
│   │   │   │   │   └── index.ts
│   │   │   │   ├── captcha
│   │   │   │   │   ├── captcha.test.ts
│   │   │   │   │   ├── constants.ts
│   │   │   │   │   ├── error-codes.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── types.ts
│   │   │   │   │   ├── utils.ts
│   │   │   │   │   └── verify-handlers
│   │   │   │   │       ├── captchafox.ts
│   │   │   │   │       ├── cloudflare-turnstile.ts
│   │   │   │   │       ├── google-recaptcha.ts
│   │   │   │   │       ├── h-captcha.ts
│   │   │   │   │       └── index.ts
│   │   │   │   ├── custom-session
│   │   │   │   │   ├── client.ts
│   │   │   │   │   ├── custom-session.test.ts
│   │   │   │   │   └── index.ts
│   │   │   │   ├── device-authorization
│   │   │   │   │   ├── client.ts
│   │   │   │   │   ├── device-authorization.test.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   └── schema.ts
│   │   │   │   ├── email-otp
│   │   │   │   │   ├── client.ts
│   │   │   │   │   ├── email-otp.test.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   └── utils.ts
│   │   │   │   ├── generic-oauth
│   │   │   │   │   ├── client.ts
│   │   │   │   │   ├── generic-oauth.test.ts
│   │   │   │   │   └── index.ts
│   │   │   │   ├── haveibeenpwned
│   │   │   │   │   ├── haveibeenpwned.test.ts
│   │   │   │   │   └── index.ts
│   │   │   │   ├── index.ts
│   │   │   │   ├── jwt
│   │   │   │   │   ├── adapter.ts
│   │   │   │   │   ├── client.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── jwt.test.ts
│   │   │   │   │   ├── schema.ts
│   │   │   │   │   ├── sign.ts
│   │   │   │   │   ├── types.ts
│   │   │   │   │   └── utils.ts
│   │   │   │   ├── last-login-method
│   │   │   │   │   ├── client.ts
│   │   │   │   │   ├── custom-prefix.test.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   └── last-login-method.test.ts
│   │   │   │   ├── magic-link
│   │   │   │   │   ├── client.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── magic-link.test.ts
│   │   │   │   │   └── utils.ts
│   │   │   │   ├── mcp
│   │   │   │   │   ├── authorize.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   └── mcp.test.ts
│   │   │   │   ├── multi-session
│   │   │   │   │   ├── client.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   └── multi-session.test.ts
│   │   │   │   ├── oauth-proxy
│   │   │   │   │   ├── index.ts
│   │   │   │   │   └── oauth-proxy.test.ts
│   │   │   │   ├── oidc-provider
│   │   │   │   │   ├── authorize.ts
│   │   │   │   │   ├── client.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── oidc.test.ts
│   │   │   │   │   ├── schema.ts
│   │   │   │   │   ├── types.ts
│   │   │   │   │   ├── ui.ts
│   │   │   │   │   └── utils.ts
│   │   │   │   ├── one-tap
│   │   │   │   │   ├── client.ts
│   │   │   │   │   └── index.ts
│   │   │   │   ├── one-time-token
│   │   │   │   │   ├── client.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── one-time-token.test.ts
│   │   │   │   │   └── utils.ts
│   │   │   │   ├── open-api
│   │   │   │   │   ├── generator.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── logo.ts
│   │   │   │   │   └── open-api.test.ts
│   │   │   │   ├── organization
│   │   │   │   │   ├── access
│   │   │   │   │   │   ├── index.ts
│   │   │   │   │   │   └── statement.ts
│   │   │   │   │   ├── adapter.ts
│   │   │   │   │   ├── call.ts
│   │   │   │   │   ├── client.test.ts
│   │   │   │   │   ├── client.ts
│   │   │   │   │   ├── error-codes.ts
│   │   │   │   │   ├── has-permission.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── organization-hook.test.ts
│   │   │   │   │   ├── organization.test.ts
│   │   │   │   │   ├── organization.ts
│   │   │   │   │   ├── permission.ts
│   │   │   │   │   ├── routes
│   │   │   │   │   │   ├── crud-access-control.test.ts
│   │   │   │   │   │   ├── crud-access-control.ts
│   │   │   │   │   │   ├── crud-invites.ts
│   │   │   │   │   │   ├── crud-members.test.ts
│   │   │   │   │   │   ├── crud-members.ts
│   │   │   │   │   │   ├── crud-org.test.ts
│   │   │   │   │   │   ├── crud-org.ts
│   │   │   │   │   │   └── crud-team.ts
│   │   │   │   │   ├── schema.ts
│   │   │   │   │   ├── team.test.ts
│   │   │   │   │   └── types.ts
│   │   │   │   ├── passkey
│   │   │   │   │   ├── client.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   └── passkey.test.ts
│   │   │   │   ├── phone-number
│   │   │   │   │   ├── client.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── phone-number-error.ts
│   │   │   │   │   └── phone-number.test.ts
│   │   │   │   ├── siwe
│   │   │   │   │   ├── client.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── schema.ts
│   │   │   │   │   ├── siwe.test.ts
│   │   │   │   │   └── types.ts
│   │   │   │   ├── sso
│   │   │   │   │   ├── client.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   └── sso.test.ts
│   │   │   │   ├── two-factor
│   │   │   │   │   ├── backup-codes
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── client.ts
│   │   │   │   │   ├── constant.ts
│   │   │   │   │   ├── error-code.ts
│   │   │   │   │   ├── index.ts
│   │   │   │   │   ├── otp
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── schema.ts
│   │   │   │   │   ├── totp
│   │   │   │   │   │   └── index.ts
│   │   │   │   │   ├── two-factor.test.ts
│   │   │   │   │   ├── types.ts
│   │   │   │   │   ├── utils.ts
│   │   │   │   │   └── verify-two-factor.ts
│   │   │   │   └── username
│   │   │   │       ├── client.ts
│   │   │   │       ├── error-codes.ts
│   │   │   │       ├── index.ts
│   │   │   │       ├── schema.ts
│   │   │   │       └── username.test.ts
│   │   │   ├── social-providers
│   │   │   │   └── index.ts
│   │   │   ├── social.test.ts
│   │   │   ├── test-utils
│   │   │   │   ├── headers.ts
│   │   │   │   ├── index.ts
│   │   │   │   ├── state.ts
│   │   │   │   └── test-instance.ts
│   │   │   ├── types
│   │   │   │   ├── adapter.ts
│   │   │   │   ├── api.ts
│   │   │   │   ├── helper.ts
│   │   │   │   ├── index.ts
│   │   │   │   ├── models.ts
│   │   │   │   ├── plugins.ts
│   │   │   │   └── types.test.ts
│   │   │   └── utils
│   │   │       ├── await-object.ts
│   │   │       ├── boolean.ts
│   │   │       ├── clone.ts
│   │   │       ├── constants.ts
│   │   │       ├── date.ts
│   │   │       ├── ensure-utc.ts
│   │   │       ├── get-request-ip.ts
│   │   │       ├── hashing.ts
│   │   │       ├── hide-metadata.ts
│   │   │       ├── id.ts
│   │   │       ├── import-util.ts
│   │   │       ├── index.ts
│   │   │       ├── is-atom.ts
│   │   │       ├── is-promise.ts
│   │   │       ├── json.ts
│   │   │       ├── merger.ts
│   │   │       ├── middleware-response.ts
│   │   │       ├── misc.ts
│   │   │       ├── password.ts
│   │   │       ├── plugin-helper.ts
│   │   │       ├── shim.ts
│   │   │       ├── time.ts
│   │   │       ├── url.ts
│   │   │       └── wildcard.ts
│   │   ├── tsconfig.json
│   │   ├── tsdown.config.ts
│   │   └── vitest.config.ts
│   ├── cli
│   │   ├── CHANGELOG.md
│   │   ├── package.json
│   │   ├── README.md
│   │   ├── src
│   │   │   ├── commands
│   │   │   │   ├── generate.ts
│   │   │   │   ├── info.ts
│   │   │   │   ├── init.ts
│   │   │   │   ├── login.ts
│   │   │   │   ├── mcp.ts
│   │   │   │   ├── migrate.ts
│   │   │   │   └── secret.ts
│   │   │   ├── generators
│   │   │   │   ├── auth-config.ts
│   │   │   │   ├── drizzle.ts
│   │   │   │   ├── index.ts
│   │   │   │   ├── kysely.ts
│   │   │   │   ├── prisma.ts
│   │   │   │   └── types.ts
│   │   │   ├── index.ts
│   │   │   └── utils
│   │   │       ├── add-svelte-kit-env-modules.ts
│   │   │       ├── check-package-managers.ts
│   │   │       ├── format-ms.ts
│   │   │       ├── get-config.ts
│   │   │       ├── get-package-info.ts
│   │   │       ├── get-tsconfig-info.ts
│   │   │       └── install-dependencies.ts
│   │   ├── test
│   │   │   ├── __snapshots__
│   │   │   │   ├── auth-schema-mysql-enum.txt
│   │   │   │   ├── auth-schema-mysql-number-id.txt
│   │   │   │   ├── auth-schema-mysql-passkey-number-id.txt
│   │   │   │   ├── auth-schema-mysql-passkey.txt
│   │   │   │   ├── auth-schema-mysql.txt
│   │   │   │   ├── auth-schema-number-id.txt
│   │   │   │   ├── auth-schema-pg-enum.txt
│   │   │   │   ├── auth-schema-pg-passkey.txt
│   │   │   │   ├── auth-schema-sqlite-enum.txt
│   │   │   │   ├── auth-schema-sqlite-number-id.txt
│   │   │   │   ├── auth-schema-sqlite-passkey-number-id.txt
│   │   │   │   ├── auth-schema-sqlite-passkey.txt
│   │   │   │   ├── auth-schema-sqlite.txt
│   │   │   │   ├── auth-schema.txt
│   │   │   │   ├── migrations.sql
│   │   │   │   ├── schema-mongodb.prisma
│   │   │   │   ├── schema-mysql-custom.prisma
│   │   │   │   ├── schema-mysql.prisma
│   │   │   │   ├── schema-numberid.prisma
│   │   │   │   └── schema.prisma
│   │   │   ├── generate-all-db.test.ts
│   │   │   ├── generate.test.ts
│   │   │   ├── get-config.test.ts
│   │   │   ├── info.test.ts
│   │   │   └── migrate.test.ts
│   │   ├── tsconfig.json
│   │   ├── tsconfig.test.json
│   │   └── tsdown.config.ts
│   ├── core
│   │   ├── package.json
│   │   ├── src
│   │   │   ├── async_hooks
│   │   │   │   └── index.ts
│   │   │   ├── context
│   │   │   │   ├── index.ts
│   │   │   │   └── transaction.ts
│   │   │   ├── db
│   │   │   │   ├── adapter
│   │   │   │   │   └── index.ts
│   │   │   │   ├── index.ts
│   │   │   │   ├── plugin.ts
│   │   │   │   ├── schema
│   │   │   │   │   ├── account.ts
│   │   │   │   │   ├── rate-limit.ts
│   │   │   │   │   ├── session.ts
│   │   │   │   │   ├── shared.ts
│   │   │   │   │   ├── user.ts
│   │   │   │   │   └── verification.ts
│   │   │   │   └── type.ts
│   │   │   ├── env
│   │   │   │   ├── color-depth.ts
│   │   │   │   ├── env-impl.ts
│   │   │   │   ├── index.ts
│   │   │   │   ├── logger.test.ts
│   │   │   │   └── logger.ts
│   │   │   ├── error
│   │   │   │   ├── codes.ts
│   │   │   │   └── index.ts
│   │   │   ├── index.ts
│   │   │   ├── middleware
│   │   │   │   └── index.ts
│   │   │   ├── oauth2
│   │   │   │   ├── client-credentials-token.ts
│   │   │   │   ├── create-authorization-url.ts
│   │   │   │   ├── index.ts
│   │   │   │   ├── oauth-provider.ts
│   │   │   │   ├── refresh-access-token.ts
│   │   │   │   ├── utils.ts
│   │   │   │   └── validate-authorization-code.ts
│   │   │   ├── social-providers
│   │   │   │   ├── apple.ts
│   │   │   │   ├── atlassian.ts
│   │   │   │   ├── cognito.ts
│   │   │   │   ├── discord.ts
│   │   │   │   ├── dropbox.ts
│   │   │   │   ├── facebook.ts
│   │   │   │   ├── figma.ts
│   │   │   │   ├── github.ts
│   │   │   │   ├── gitlab.ts
│   │   │   │   ├── google.ts
│   │   │   │   ├── huggingface.ts
│   │   │   │   ├── index.ts
│   │   │   │   ├── kakao.ts
│   │   │   │   ├── kick.ts
│   │   │   │   ├── line.ts
│   │   │   │   ├── linear.ts
│   │   │   │   ├── linkedin.ts
│   │   │   │   ├── microsoft-entra-id.ts
│   │   │   │   ├── naver.ts
│   │   │   │   ├── notion.ts
│   │   │   │   ├── paypal.ts
│   │   │   │   ├── reddit.ts
│   │   │   │   ├── roblox.ts
│   │   │   │   ├── salesforce.ts
│   │   │   │   ├── slack.ts
│   │   │   │   ├── spotify.ts
│   │   │   │   ├── tiktok.ts
│   │   │   │   ├── twitch.ts
│   │   │   │   ├── twitter.ts
│   │   │   │   ├── vk.ts
│   │   │   │   └── zoom.ts
│   │   │   ├── types
│   │   │   │   ├── context.ts
│   │   │   │   ├── cookie.ts
│   │   │   │   ├── helper.ts
│   │   │   │   ├── index.ts
│   │   │   │   ├── init-options.ts
│   │   │   │   ├── plugin-client.ts
│   │   │   │   └── plugin.ts
│   │   │   └── utils
│   │   │       ├── error-codes.ts
│   │   │       └── index.ts
│   │   ├── tsconfig.json
│   │   └── tsdown.config.ts
│   ├── expo
│   │   ├── CHANGELOG.md
│   │   ├── package.json
│   │   ├── README.md
│   │   ├── src
│   │   │   ├── client.ts
│   │   │   ├── expo.test.ts
│   │   │   └── index.ts
│   │   ├── tsconfig.json
│   │   └── tsdown.config.ts
│   ├── sso
│   │   ├── package.json
│   │   ├── src
│   │   │   ├── client.ts
│   │   │   ├── index.ts
│   │   │   ├── oidc.test.ts
│   │   │   └── saml.test.ts
│   │   ├── tsconfig.json
│   │   └── tsdown.config.ts
│   ├── stripe
│   │   ├── CHANGELOG.md
│   │   ├── package.json
│   │   ├── src
│   │   │   ├── client.ts
│   │   │   ├── hooks.ts
│   │   │   ├── index.ts
│   │   │   ├── schema.ts
│   │   │   ├── stripe.test.ts
│   │   │   ├── types.ts
│   │   │   └── utils.ts
│   │   ├── tsconfig.json
│   │   ├── tsdown.config.ts
│   │   └── vitest.config.ts
│   └── telemetry
│       ├── package.json
│       ├── src
│       │   ├── detectors
│       │   │   ├── detect-auth-config.ts
│       │   │   ├── detect-database.ts
│       │   │   ├── detect-framework.ts
│       │   │   ├── detect-project-info.ts
│       │   │   ├── detect-runtime.ts
│       │   │   └── detect-system-info.ts
│       │   ├── index.ts
│       │   ├── project-id.ts
│       │   ├── telemetry.test.ts
│       │   ├── types.ts
│       │   └── utils
│       │       ├── hash.ts
│       │       ├── id.ts
│       │       ├── import-util.ts
│       │       └── package-json.ts
│       ├── tsconfig.json
│       └── tsdown.config.ts
├── pnpm-lock.yaml
├── pnpm-workspace.yaml
├── README.md
├── SECURITY.md
├── tsconfig.json
└── turbo.json
```

# Files

--------------------------------------------------------------------------------
/demo/nextjs/turbo.json:
--------------------------------------------------------------------------------

```json
{
  "$schema": "https://turborepo.org/schema.json",
  "extends": ["//"],
  "tasks": {
    "build": {
      "env": [
        "TURSO_DATABASE_URL",
        "TURSO_AUTH_TOKEN",
        "RESEND_API_KEY",
        "BETTER_AUTH_EMAIL",
        "BETTER_AUTH_SECRET",
        "BETTER_AUTH_URL",
        "GITHUB_CLIENT_SECRET",
        "GITHUB_CLIENT_ID",
        "GOOGLE_CLIENT_ID",
        "GOOGLE_CLIENT_SECRET",
        "DISCORD_CLIENT_ID",
        "DISCORD_CLIENT_SECRET",
        "MICROSOFT_CLIENT_ID",
        "MICROSOFT_CLIENT_SECRET",
        "STRIPE_KEY",
        "STRIPE_WEBHOOK_SECRET"
      ]
    }
  }
}

```

--------------------------------------------------------------------------------
/packages/better-auth/src/utils/json.ts:
--------------------------------------------------------------------------------

```typescript
import { logger } from "@better-auth/core/env";

export function safeJSONParse<T>(data: unknown): T | null {
	function reviver(_: string, value: any): any {
		if (typeof value === "string") {
			const iso8601Regex = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z$/;
			if (iso8601Regex.test(value)) {
				const date = new Date(value);
				if (!isNaN(date.getTime())) {
					return date;
				}
			}
		}
		return value;
	}
	try {
		if (typeof data !== "string") {
			return data as T;
		}
		return JSON.parse(data, reviver);
	} catch (e) {
		logger.error("Error parsing JSON", { error: e });
		return null;
	}
}

```

--------------------------------------------------------------------------------
/docs/app/blog/layout.tsx:
--------------------------------------------------------------------------------

```typescript
import { Metadata } from "next";

export const metadata: Metadata = {
	title: "Blog - Better Auth",
	description: "Latest updates, articles, and insights about Better Auth",
};

interface BlogLayoutProps {
	children: React.ReactNode;
}

export default function BlogLayout({ children }: BlogLayoutProps) {
	return (
		<div
			className="relative flex min-h-screen flex-col"
			style={{
				scrollbarWidth: "none",
				scrollbarColor: "transparent transparent",
				//@ts-expect-error
				"&::-webkit-scrollbar": {
					display: "none",
				},
			}}
		>
			<main className="flex-1">{children}</main>
		</div>
	);
}

```

--------------------------------------------------------------------------------
/docs/app/community/_components/header.tsx:
--------------------------------------------------------------------------------

```typescript
export default function CommunityHeader() {
	return (
		<div className="h-full flex flex-col justify-center items-center text-white">
			<div className="max-w-6xl mx-auto px-4 py-16">
				<div className="text-center">
					<h1 className="text-4xl tracking-tighter md:text-5xl mt-3 font-normal mb-6 text-stone-800 dark:text-white">
						Open Source Community
					</h1>
					<p className="dark:text-gray-400 max-w-md mx-auto text-stone-800">
						join <span className="italic font-bold">better-auth</span> community
						to get help, share ideas, and stay up to date.
					</p>
				</div>
			</div>
		</div>
	);
}

```

--------------------------------------------------------------------------------
/packages/better-auth/src/cookies/check-cookies.ts:
--------------------------------------------------------------------------------

```typescript
import { parseCookies } from "../cookies";
import type { AuthContext } from "@better-auth/core";

export const checkAuthCookie = async (
	request: Request | Headers,
	auth: {
		$context: Promise<AuthContext>;
	},
) => {
	const headers = request instanceof Headers ? request : request.headers;
	const cookies = headers.get("cookie");
	if (!cookies) {
		return null;
	}
	const ctx = await auth.$context;
	const cookieName = ctx.authCookies.sessionToken.name;
	const parsedCookie = parseCookies(cookies);
	const sessionToken = parsedCookie.get(cookieName);
	if (sessionToken) {
		return sessionToken;
	}
	return null;
};

```

--------------------------------------------------------------------------------
/packages/better-auth/src/plugins/two-factor/schema.ts:
--------------------------------------------------------------------------------

```typescript
import type { BetterAuthPluginDBSchema } from "@better-auth/core/db";

export const schema = {
	user: {
		fields: {
			twoFactorEnabled: {
				type: "boolean",
				required: false,
				defaultValue: false,
				input: false,
			},
		},
	},
	twoFactor: {
		fields: {
			secret: {
				type: "string",
				required: true,
				returned: false,
			},
			backupCodes: {
				type: "string",
				required: true,
				returned: false,
			},
			userId: {
				type: "string",
				required: true,
				returned: false,
				references: {
					model: "user",
					field: "id",
				},
			},
		},
	},
} satisfies BetterAuthPluginDBSchema;

```

--------------------------------------------------------------------------------
/docs/public/branding/better-auth-logo-dark.svg:
--------------------------------------------------------------------------------

```
<svg width="500" height="500" viewBox="0 0 500 500" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="500" height="500" fill="black"/>
<rect x="69" y="121" width="86.9879" height="259" fill="white"/>
<rect x="337.575" y="121" width="92.4247" height="259" fill="white"/>
<rect x="427.282" y="121" width="83.4555" height="174.52" transform="rotate(90 427.282 121)" fill="white"/>
<rect x="430" y="296.544" width="83.4555" height="177.238" transform="rotate(90 430 296.544)" fill="white"/>
<rect x="252.762" y="204.455" width="92.0888" height="96.7741" transform="rotate(90 252.762 204.455)" fill="white"/>
</svg>

```

--------------------------------------------------------------------------------
/docs/public/branding/better-auth-logo-light.svg:
--------------------------------------------------------------------------------

```
<svg width="500" height="500" viewBox="0 0 500 500" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="500" height="500" fill="white"/>
<rect x="69" y="121" width="86.9879" height="259" fill="black"/>
<rect x="337.575" y="121" width="92.4247" height="259" fill="black"/>
<rect x="427.282" y="121" width="83.4555" height="174.52" transform="rotate(90 427.282 121)" fill="black"/>
<rect x="430" y="296.544" width="83.4555" height="177.238" transform="rotate(90 430 296.544)" fill="black"/>
<rect x="252.762" y="204.455" width="92.0888" height="96.7741" transform="rotate(90 252.762 204.455)" fill="black"/>
</svg>

```

--------------------------------------------------------------------------------
/demo/nextjs/tsconfig.json:
--------------------------------------------------------------------------------

```json
{
  "compilerOptions": {
    "target": "ES2017",
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": true,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "bundler",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "preserve",
    "incremental": true,
    "plugins": [
      {
        "name": "next"
      }
    ],
    "paths": {
      "@/*": ["./*"]
    }
  },
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
  "exclude": ["node_modules", "components/ui/**/*.tsx"]
}

```

--------------------------------------------------------------------------------
/docs/app/llms.txt/[...slug]/route.ts:
--------------------------------------------------------------------------------

```typescript
import { type NextRequest, NextResponse } from "next/server";
import { source } from "@/lib/source";
import { notFound } from "next/navigation";
import { getLLMText } from "@/app/docs/lib/get-llm-text";

export const revalidate = false;

export async function GET(
	_req: NextRequest,
	{ params }: { params: Promise<{ slug: string[] }> },
) {
	const slug = (await params).slug;
	const page = source.getPage(slug);
	if (!page) notFound();

	return new NextResponse(await getLLMText(page), {
		headers: {
			"Content-Type": "text/markdown",
		},
	});
}

export function generateStaticParams() {
	return source.generateParams();
}

```

--------------------------------------------------------------------------------
/docs/components/landing/section-svg.tsx:
--------------------------------------------------------------------------------

```typescript
import { Plus } from "lucide-react";

const SectionSvg = ({ crossesOffset }: { crossesOffset: string }) => {
	return (
		<>
			<Plus
				className={`hidden absolute -top-[0.3125rem] h-6 w-6 ${
					crossesOffset && crossesOffset
				} pointer-events-none lg:block lg:left-[3.275rem] text-neutral-300 dark:text-neutral-600 translate-y-[.5px]`}
			/>

			<Plus
				className={`hidden absolute -top-[0.3125rem] h-6 w-6 right-[1.4625rem] ${
					crossesOffset && crossesOffset
				} pointer-events-none lg:block lg:right-[2.7750rem] text-neutral-300 dark:text-neutral-600 translate-y-[.5px]`}
			/>
		</>
	);
};

export default SectionSvg;

```

--------------------------------------------------------------------------------
/docs/components/builder/code-tabs/tab-bar.tsx:
--------------------------------------------------------------------------------

```typescript
import { CodeTab } from "./code-tabs";

interface File {
	id: string;
	name: string;
	content: string;
}

interface TabBarProps {
	files: File[];
	activeFileId: string;
	onTabClick: (fileId: string) => void;
	onTabClose: (fileId: string) => void;
}

export function TabBar({
	files,
	activeFileId,
	onTabClick,
	onTabClose,
}: TabBarProps) {
	return (
		<div className="flex bg-muted border-b border-border">
			{files.map((file) => (
				<CodeTab
					key={file.id}
					fileName={file.name}
					isActive={file.id === activeFileId}
					onClick={() => onTabClick(file.id)}
					onClose={() => onTabClose(file.id)}
				/>
			))}
		</div>
	);
}

```

--------------------------------------------------------------------------------
/packages/cli/src/utils/get-tsconfig-info.ts:
--------------------------------------------------------------------------------

```typescript
import path from "path";
import fs from "fs";

export function stripJsonComments(jsonString: string): string {
	return jsonString
		.replace(/\\"|"(?:\\"|[^"])*"|(\/\/.*|\/\*[\s\S]*?\*\/)/g, (m, g) =>
			g ? "" : m,
		)
		.replace(/,(?=\s*[}\]])/g, "");
}
export function getTsconfigInfo(cwd?: string, flatPath?: string) {
	let tsConfigPath: string;
	if (flatPath) {
		tsConfigPath = flatPath;
	} else {
		tsConfigPath = cwd
			? path.join(cwd, "tsconfig.json")
			: path.join("tsconfig.json");
	}
	try {
		const text = fs.readFileSync(tsConfigPath, "utf-8");
		return JSON.parse(stripJsonComments(text));
	} catch (error) {
		throw error;
	}
}

```

--------------------------------------------------------------------------------
/packages/better-auth/src/crypto/hash.ts:
--------------------------------------------------------------------------------

```typescript
import { constantTimeEqual } from "./buffer";
import { createHash } from "@better-auth/utils/hash";
import { base64 } from "@better-auth/utils/base64";

export async function hashToBase64(
	data: string | ArrayBuffer,
): Promise<string> {
	const buffer = await createHash("SHA-256").digest(data);
	return base64.encode(buffer);
}

export async function compareHash(
	data: string | ArrayBuffer,
	hash: string,
): Promise<boolean> {
	const buffer = await createHash("SHA-256").digest(
		typeof data === "string" ? new TextEncoder().encode(data) : data,
	);
	const hashBuffer = base64.decode(hash);
	return constantTimeEqual(buffer, hashBuffer);
}

```

--------------------------------------------------------------------------------
/packages/better-auth/src/plugins/admin/schema.ts:
--------------------------------------------------------------------------------

```typescript
import { type BetterAuthPluginDBSchema } from "@better-auth/core/db";

export const schema = {
	user: {
		fields: {
			role: {
				type: "string",
				required: false,
				input: false,
			},
			banned: {
				type: "boolean",
				defaultValue: false,
				required: false,
				input: false,
			},
			banReason: {
				type: "string",
				required: false,
				input: false,
			},
			banExpires: {
				type: "date",
				required: false,
				input: false,
			},
		},
	},
	session: {
		fields: {
			impersonatedBy: {
				type: "string",
				required: false,
			},
		},
	},
} satisfies BetterAuthPluginDBSchema;

export type AdminSchema = typeof schema;

```

--------------------------------------------------------------------------------
/demo/expo-example/src/components/ui/separator.tsx:
--------------------------------------------------------------------------------

```typescript
import * as SeparatorPrimitive from "@rn-primitives/separator";
import * as React from "react";
import { cn } from "@/lib/utils";

const Separator = React.forwardRef<
	SeparatorPrimitive.RootRef,
	SeparatorPrimitive.RootProps
>(
	(
		{ className, orientation = "horizontal", decorative = true, ...props },
		ref,
	) => (
		<SeparatorPrimitive.Root
			ref={ref}
			decorative={decorative}
			orientation={orientation}
			className={cn(
				"shrink-0 bg-border",
				orientation === "horizontal" ? "h-[1px] w-full" : "h-full w-[1px]",
				className,
			)}
			{...props}
		/>
	),
);
Separator.displayName = SeparatorPrimitive.Root.displayName;

export { Separator };

```

--------------------------------------------------------------------------------
/docs/components/ui/separator.tsx:
--------------------------------------------------------------------------------

```typescript
"use client";

import * as React from "react";
import * as SeparatorPrimitive from "@radix-ui/react-separator";

import { cn } from "@/lib/utils";

function Separator({
	className,
	orientation = "horizontal",
	decorative = true,
	...props
}: React.ComponentProps<typeof SeparatorPrimitive.Root>) {
	return (
		<SeparatorPrimitive.Root
			data-slot="separator-root"
			decorative={decorative}
			orientation={orientation}
			className={cn(
				"bg-border shrink-0 data-[orientation=horizontal]:h-px data-[orientation=horizontal]:w-full data-[orientation=vertical]:h-full data-[orientation=vertical]:w-px",
				className,
			)}
			{...props}
		/>
	);
}

export { Separator };

```

--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------

```json
{
  "biome.enabled": true,
  "editor.defaultFormatter": "biomejs.biome",
  "[typescript]": {
    "editor.defaultFormatter": "biomejs.biome"
  },
  "[jsonc]": {
    "editor.defaultFormatter": "biomejs.biome"
  },
  "[svelte]": {
    "editor.defaultFormatter": "biomejs.biome"
  },
  "[vue]": {
    "editor.defaultFormatter": "biomejs.biome"
  },
  "[json]": {
    "editor.defaultFormatter": "biomejs.biome"
  },
  "typescript.tsdk": "node_modules/typescript/lib",
  "[astro]": {
    "editor.defaultFormatter": "biomejs.biome"
  },
  "[typescriptreact]": {
    "editor.defaultFormatter": "biomejs.biome"
  },
  "[mdx]": {
    "editor.defaultFormatter": "unifiedjs.vscode-mdx"
  }
}

```

--------------------------------------------------------------------------------
/packages/better-auth/src/plugins/admin/access/statement.ts:
--------------------------------------------------------------------------------

```typescript
import { createAccessControl } from "../../access";

export const defaultStatements = {
	user: [
		"create",
		"list",
		"set-role",
		"ban",
		"impersonate",
		"delete",
		"set-password",
		"get",
		"update",
	],
	session: ["list", "revoke", "delete"],
} as const;

export const defaultAc = createAccessControl(defaultStatements);

export const adminAc = defaultAc.newRole({
	user: [
		"create",
		"list",
		"set-role",
		"ban",
		"impersonate",
		"delete",
		"set-password",
		"get",
		"update",
	],
	session: ["list", "revoke", "delete"],
});

export const userAc = defaultAc.newRole({
	user: [],
	session: [],
});

export const defaultRoles = {
	admin: adminAc,
	user: userAc,
};

```

--------------------------------------------------------------------------------
/packages/better-auth/src/plugins/captcha/constants.ts:
--------------------------------------------------------------------------------

```typescript
import type { Provider } from "./types";

export const defaultEndpoints = [
	"/sign-up/email",
	"/sign-in/email",
	"/forget-password",
];

export const Providers = {
	CLOUDFLARE_TURNSTILE: "cloudflare-turnstile",
	GOOGLE_RECAPTCHA: "google-recaptcha",
	HCAPTCHA: "hcaptcha",
	CAPTCHAFOX: "captchafox",
} as const;

export const siteVerifyMap: Record<Provider, string> = {
	[Providers.CLOUDFLARE_TURNSTILE]:
		"https://challenges.cloudflare.com/turnstile/v0/siteverify",
	[Providers.GOOGLE_RECAPTCHA]:
		"https://www.google.com/recaptcha/api/siteverify",
	[Providers.HCAPTCHA]: "https://api.hcaptcha.com/siteverify",
	[Providers.CAPTCHAFOX]: "https://api.captchafox.com/siteverify",
};

```

--------------------------------------------------------------------------------
/packages/better-auth/src/integrations/node.ts:
--------------------------------------------------------------------------------

```typescript
import { toNodeHandler as toNode } from "better-call/node";
import type { Auth } from "../auth";
import type { IncomingHttpHeaders } from "http";

export const toNodeHandler = (
	auth:
		| {
				handler: Auth["handler"];
		  }
		| Auth["handler"],
) => {
	return "handler" in auth ? toNode(auth.handler) : toNode(auth);
};

export function fromNodeHeaders(nodeHeaders: IncomingHttpHeaders): Headers {
	const webHeaders = new Headers();
	for (const [key, value] of Object.entries(nodeHeaders)) {
		if (value !== undefined) {
			if (Array.isArray(value)) {
				value.forEach((v) => webHeaders.append(key, v));
			} else {
				webHeaders.set(key, value);
			}
		}
	}
	return webHeaders;
}

```

--------------------------------------------------------------------------------
/packages/telemetry/src/project-id.ts:
--------------------------------------------------------------------------------

```typescript
import { generateId } from "./utils/id";
import { hashToBase64 } from "./utils/hash";
import { getNameFromLocalPackageJson } from "./utils/package-json";

let projectIdCached: string | null = null;

export async function getProjectId(
	baseUrl: string | undefined,
): Promise<string> {
	if (projectIdCached) return projectIdCached;

	const projectName = await getNameFromLocalPackageJson();
	if (projectName) {
		projectIdCached = await hashToBase64(
			baseUrl ? baseUrl + projectName : projectName,
		);
		return projectIdCached;
	}

	if (baseUrl) {
		projectIdCached = await hashToBase64(baseUrl);
		return projectIdCached;
	}

	projectIdCached = generateId(32);
	return projectIdCached;
}

```

--------------------------------------------------------------------------------
/packages/better-auth/src/test-utils/headers.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * converts set cookie containing headers to
 * cookie containing headers
 */
export function convertSetCookieToCookie(headers: Headers): Headers {
	const setCookieHeaders: string[] = [];
	headers.forEach((value, name) => {
		if (name.toLowerCase() === "set-cookie") {
			setCookieHeaders.push(value);
		}
	});

	if (setCookieHeaders.length === 0) {
		return headers;
	}

	const existingCookies = headers.get("cookie") || "";
	const cookies = existingCookies ? existingCookies.split("; ") : [];

	setCookieHeaders.forEach((setCookie) => {
		const cookiePair = setCookie.split(";")[0]!;
		cookies.push(cookiePair.trim());
	});

	headers.set("cookie", cookies.join("; "));

	return headers;
}

```

--------------------------------------------------------------------------------
/docs/components/ui/progress.tsx:
--------------------------------------------------------------------------------

```typescript
"use client";

import * as React from "react";
import * as ProgressPrimitive from "@radix-ui/react-progress";

import { cn } from "@/lib/utils";

function Progress({
	className,
	value,
	...props
}: React.ComponentProps<typeof ProgressPrimitive.Root>) {
	return (
		<ProgressPrimitive.Root
			data-slot="progress"
			className={cn(
				"bg-primary/20 relative h-2 w-full overflow-hidden rounded-full",
				className,
			)}
			{...props}
		>
			<ProgressPrimitive.Indicator
				data-slot="progress-indicator"
				className="bg-primary h-full w-full flex-1 transition-all"
				style={{ transform: `translateX(-${100 - (value || 0)}%)` }}
			/>
		</ProgressPrimitive.Root>
	);
}

export { Progress };

```

--------------------------------------------------------------------------------
/demo/nextjs/components/ui/toaster.tsx:
--------------------------------------------------------------------------------

```typescript
"use client";

import { useToast } from "@/hooks/use-toast";
import {
	Toast,
	ToastClose,
	ToastDescription,
	ToastProvider,
	ToastTitle,
	ToastViewport,
} from "@/components/ui/toast";

export function Toaster() {
	const { toasts } = useToast();

	return (
		<ToastProvider>
			{toasts.map(function ({ id, title, description, action, ...props }) {
				return (
					<Toast key={id} {...props}>
						<div className="grid gap-1">
							{title && <ToastTitle>{title}</ToastTitle>}
							{description && (
								<ToastDescription>{description}</ToastDescription>
							)}
						</div>
						{action}
						<ToastClose />
					</Toast>
				);
			})}
			<ToastViewport />
		</ToastProvider>
	);
}

```

--------------------------------------------------------------------------------
/demo/nextjs/components/ui/textarea.tsx:
--------------------------------------------------------------------------------

```typescript
import * as React from "react";

import { cn } from "@/lib/utils";

export interface TextareaProps
	extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {}

const Textarea = ({
	ref,
	className,
	...props
}: TextareaProps & {
	ref: React.RefObject<HTMLTextAreaElement>;
}) => {
	return (
		<textarea
			className={cn(
				"flex min-h-[60px] w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",
				className,
			)}
			ref={ref}
			{...props}
		/>
	);
};
Textarea.displayName = "Textarea";

export { Textarea };

```

--------------------------------------------------------------------------------
/packages/better-auth/src/client/client-ssr.test.ts:
--------------------------------------------------------------------------------

```typescript
// @vitest-environment node
import { expect, it, vi } from "vitest";
import { createAuthClient as createVueClient } from "./vue";

it("should call '/api/auth' for vue client", async () => {
	const customFetchImpl = vi.fn(async (url: string | Request | URL) => {
		expect(url).toBe("/api/auth/get-session");
		return new Response();
	});
	process.env.BETTER_AUTH_URL = "http://localhost:3000";
	// use DisposableStack when Node.js 24 is the minimum requirement
	using _ = {
		[Symbol.dispose]() {
			process.env.BETTER_AUTH_URL = undefined;
		},
	};
	const client = createVueClient({
		fetchOptions: {
			customFetchImpl,
		},
	});
	await client.getSession();
	expect(customFetchImpl).toBeCalled();
});

```

--------------------------------------------------------------------------------
/docs/components/fork-button.tsx:
--------------------------------------------------------------------------------

```typescript
import Link from "next/link";
import { Button } from "./ui/button";
import { GitHubLogoIcon } from "@radix-ui/react-icons";
import { ExternalLink } from "lucide-react";

export function ForkButton({ url }: { url: string }) {
	return (
		<div className="flex items-center gap-2 my-2">
			<Link href={`https://codesandbox.io/p/github/${url}`} target="_blank">
				<Button className="gap-2" variant="outline" size="sm">
					<ExternalLink size={12} />
					Open in Stackblitz
				</Button>
			</Link>
			<Link href={`https://github.com/${url}`} target="_blank">
				<Button className="gap-2" variant="secondary" size="sm">
					<GitHubLogoIcon />
					View on GitHub
				</Button>
			</Link>
		</div>
	);
}

```

--------------------------------------------------------------------------------
/docs/components/mobile-search-icon.tsx:
--------------------------------------------------------------------------------

```typescript
"use client";

import { Search } from "lucide-react";
import { useSearchContext } from "fumadocs-ui/provider";
import { Button } from "@/components/ui/button";
import { cn } from "@/lib/utils";

interface MobileSearchIconProps {
	className?: string;
}

export function MobileSearchIcon({ className }: MobileSearchIconProps) {
	const { setOpenSearch } = useSearchContext();

	const handleSearchClick = () => {
		setOpenSearch(true);
	};

	return (
		<Button
			variant="ghost"
			size="icon"
			aria-label="Search"
			onClick={handleSearchClick}
			className={cn(
				"flex ring-0 shrink-0 md:hidden size-9 hover:bg-transparent",
				className,
			)}
		>
			<Search className="size-4" />
		</Button>
	);
}

```

--------------------------------------------------------------------------------
/packages/stripe/src/client.ts:
--------------------------------------------------------------------------------

```typescript
import type { BetterAuthClientPlugin } from "better-auth";
import type { stripe } from "./index";

export const stripeClient = <
	O extends {
		subscription: boolean;
	},
>(
	options?: O,
) => {
	return {
		id: "stripe-client",
		$InferServerPlugin: {} as ReturnType<
			typeof stripe<
				O["subscription"] extends true
					? {
							stripeClient: any;
							stripeWebhookSecret: string;
							subscription: {
								enabled: true;
								plans: [];
							};
						}
					: {
							stripeClient: any;
							stripeWebhookSecret: string;
						}
			>
		>,
		pathMethods: {
			"/subscription/restore": "POST",
			"/subscription/billing-portal": "POST",
		},
	} satisfies BetterAuthClientPlugin;
};

```

--------------------------------------------------------------------------------
/demo/nextjs/components/ui/separator.tsx:
--------------------------------------------------------------------------------

```typescript
"use client";

import * as React from "react";
import * as SeparatorPrimitive from "@radix-ui/react-separator";

import { cn } from "@/lib/utils";

const Separator = ({
	ref,
	className,
	orientation = "horizontal",
	decorative = true,
	...props
}: React.ComponentPropsWithoutRef<typeof SeparatorPrimitive.Root> & {
	ref: React.RefObject<React.ElementRef<typeof SeparatorPrimitive.Root>>;
}) => (
	<SeparatorPrimitive.Root
		ref={ref}
		decorative={decorative}
		orientation={orientation}
		className={cn(
			"shrink-0 bg-border",
			orientation === "horizontal" ? "h-px w-full" : "h-full w-px",
			className,
		)}
		{...props}
	/>
);
Separator.displayName = SeparatorPrimitive.Root.displayName;

export { Separator };

```

--------------------------------------------------------------------------------
/docs/components/ui/textarea.tsx:
--------------------------------------------------------------------------------

```typescript
import * as React from "react";

import { cn } from "@/lib/utils";

function Textarea({ className, ...props }: React.ComponentProps<"textarea">) {
	return (
		<textarea
			data-slot="textarea"
			className={cn(
				"border-input placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive flex field-sizing-content min-h-16 w-full rounded-md border bg-transparent px-3 py-2 text-base shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
				className,
			)}
			{...props}
		/>
	);
}

export { Textarea };

```

--------------------------------------------------------------------------------
/docs/app/changelogs/_components/grid-pattern.tsx:
--------------------------------------------------------------------------------

```typescript
"use client";

import { cn } from "@/lib/utils";

function GridPatterns() {
	return (
		<div
			className={cn(
				"pointer-events-none",
				"fixed inset-y-0 left-0 z-0",
				"w-1/2 h-full",
				"overflow-hidden",
			)}
			aria-hidden="true"
		>
			<div className="absolute opacity-40 inset-0 w-full h-full bg-[radial-gradient(circle_at_center,rgba(0,0,0,0.04)_1px,transparent_1px)] dark:bg-[radial-gradient(circle_at_center,rgba(255,255,255,0.04)_1px,transparent_1px)] bg-[length:8px_8px]" />
			<div className="absolute top-0 left-0 w-full h-full bg-gradient-to-br opacity-40 from-white/40 via-transparent to-white/10 dark:from-white/10 dark:to-transparent mix-blend-screen" />
		</div>
	);
}

export { GridPatterns };

```

--------------------------------------------------------------------------------
/packages/better-auth/src/types/plugins.ts:
--------------------------------------------------------------------------------

```typescript
import type { UnionToIntersection } from "./helper";

import type { BetterAuthPluginDBSchema } from "@better-auth/core/db";
import type { BetterAuthOptions, BetterAuthPlugin } from "@better-auth/core";

export type InferOptionSchema<S extends BetterAuthPluginDBSchema> =
	S extends Record<string, { fields: infer Fields }>
		? {
				[K in keyof S]?: {
					modelName?: string;
					fields?: {
						[P in keyof Fields]?: string;
					};
				};
			}
		: never;

export type InferPluginErrorCodes<O extends BetterAuthOptions> =
	O["plugins"] extends Array<infer P>
		? UnionToIntersection<
				P extends BetterAuthPlugin
					? P["$ERROR_CODES"] extends Record<string, any>
						? P["$ERROR_CODES"]
						: {}
					: {}
			>
		: {};

```

--------------------------------------------------------------------------------
/packages/better-auth/src/adapters/prisma-adapter/test/generate-auth-config.ts:
--------------------------------------------------------------------------------

```typescript
import fs from "fs/promises";
import type { BetterAuthOptions } from "@better-auth/core";
import path from "path";

export const generateAuthConfigFile = async (_options: BetterAuthOptions) => {
	const options = { ..._options };
	// biome-ignore lint/performance/noDelete: perf doesn't matter here.
	delete options.database;
	let code = `import { betterAuth } from "../../../auth";
import { prismaAdapter } from "../prisma-adapter";		
import { PrismaClient } from "@prisma/client";
const db = new PrismaClient();

export const auth = betterAuth({
    database: prismaAdapter(db, {
	    provider: 'sqlite'
    }),
    ${JSON.stringify(options, null, 2).slice(1, -1)}
})`;

	await fs.writeFile(path.join(import.meta.dirname, "auth.ts"), code);
};

```

--------------------------------------------------------------------------------
/packages/better-auth/src/api/routes/ok.ts:
--------------------------------------------------------------------------------

```typescript
import { HIDE_METADATA } from "../../utils/hide-metadata";
import { createAuthEndpoint } from "@better-auth/core/middleware";

export const ok = createAuthEndpoint(
	"/ok",
	{
		method: "GET",
		metadata: {
			...HIDE_METADATA,
			openapi: {
				description: "Check if the API is working",
				responses: {
					"200": {
						description: "API is working",
						content: {
							"application/json": {
								schema: {
									type: "object",
									properties: {
										ok: {
											type: "boolean",
											description: "Indicates if the API is working",
										},
									},
									required: ["ok"],
								},
							},
						},
					},
				},
			},
		},
	},
	async (ctx) => {
		return ctx.json({
			ok: true,
		});
	},
);

```

--------------------------------------------------------------------------------
/e2e/smoke/test/fixtures/tsconfig-exact-optional-property-types/src/index.ts:
--------------------------------------------------------------------------------

```typescript
import { betterAuth } from "better-auth";
import { organization } from "better-auth/plugins";
import { nextCookies } from "better-auth/next-js";
import Database from "better-sqlite3";
import { createAuthClient } from "better-auth/react";
import {
	inferAdditionalFields,
	organizationClient,
} from "better-auth/client/plugins";

const auth = betterAuth({
	database: new Database("./sqlite.db"),
	trustedOrigins: [],
	emailAndPassword: {
		enabled: true,
	},
	plugins: [organization(), nextCookies()],
	user: {
		additionalFields: {},
	},
});
const authClient = createAuthClient({
	baseURL: "http://localhost:3000",
	plugins: [inferAdditionalFields<typeof auth>(), organizationClient()],
});

authClient.useActiveOrganization();
authClient.useSession();

```

--------------------------------------------------------------------------------
/docs/tsconfig.json:
--------------------------------------------------------------------------------

```json
{
  "compilerOptions": {
    "baseUrl": ".",
    "target": "ESNext",
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "bundler",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "react-jsx",
    "incremental": true,
    "paths": {
      "@/.source": ["./.source/index.ts"],
      "@/*": ["./*"]
    },
    "plugins": [
      {
        "name": "next"
      }
    ]
  },
  "include": [
    "next-env.d.ts",
    "**/*.ts",
    "**/*.tsx",
    ".next/types/**/*.ts",
    ".next/dev/types/**/*.ts"
  ],
  "exclude": ["node_modules"]
}

```

--------------------------------------------------------------------------------
/packages/better-auth/src/types/adapter.ts:
--------------------------------------------------------------------------------

```typescript
import type {
	DBAdapter,
	DBTransactionAdapter,
	Where,
	DBAdapterSchemaCreation,
	DBAdapterInstance,
} from "@better-auth/core/db/adapter";

export type { Where };

/**
 * Adapter Interface
 *
 * @deprecated Use `DBAdapter` from `@better-auth/core/db/adapter` instead.
 */
export type Adapter = DBAdapter;

/**
 * @deprecated Use `DBTransactionAdapter` from `@better-auth/core/db/adapter` instead.
 */
export type TransactionAdapter = DBTransactionAdapter;

/**
 * @deprecated Use `DBAdapterSchemaCreation` from `@better-auth/core/db/adapter` instead.
 */
export type AdapterSchemaCreation = DBAdapterSchemaCreation;

/**
 * @deprecated Use `DBAdapterInstance` from `@better-auth/core/db/adapter` instead.
 */
export type AdapterInstance = DBAdapterInstance;

```

--------------------------------------------------------------------------------
/docs/components/docs/ui/button.tsx:
--------------------------------------------------------------------------------

```typescript
import { cva } from "class-variance-authority";

export const buttonVariants = cva(
	"inline-flex items-center justify-center rounded-md p-2 text-sm font-medium transition-colors duration-100 disabled:pointer-events-none disabled:opacity-50",
	{
		variants: {
			color: {
				primary:
					"bg-fd-primary text-fd-primary-foreground hover:bg-fd-primary/80",
				outline: "border hover:bg-fd-accent hover:text-fd-accent-foreground",
				ghost: "hover:bg-fd-accent hover:text-fd-accent-foreground",
				secondary:
					"border bg-fd-secondary text-fd-secondary-foreground hover:bg-fd-accent hover:text-fd-accent-foreground",
			},
			size: {
				sm: "gap-1 p-0.5 text-xs",
				icon: "p-1.5 [&_svg]:size-5",
				"icon-sm": "p-1.5 [&_svg]:size-4.5",
			},
		},
	},
);

```

--------------------------------------------------------------------------------
/demo/expo-example/src/components/ui/text.tsx:
--------------------------------------------------------------------------------

```typescript
import * as Slot from "@rn-primitives/slot";
import { SlottableTextProps, TextRef } from "@rn-primitives/types";
import * as React from "react";
import { Text as RNText } from "react-native";
import { cn } from "@/lib/utils";

const TextClassContext = React.createContext<string | undefined>(undefined);

const Text = React.forwardRef<TextRef, SlottableTextProps>(
	({ className, asChild = false, ...props }, ref) => {
		const textClass = React.useContext(TextClassContext);
		const Component = asChild ? Slot.Text : RNText;
		return (
			<Component
				className={cn(
					"text-base text-foreground web:select-text",
					textClass,
					className,
				)}
				ref={ref}
				{...props}
			/>
		);
	},
);
Text.displayName = "Text";

export { Text, TextClassContext };

```

--------------------------------------------------------------------------------
/docs/lib/metadata.ts:
--------------------------------------------------------------------------------

```typescript
import type { Metadata } from "next/types";

export function createMetadata(override: Metadata): Metadata {
	return {
		...override,
		openGraph: {
			title: override.title ?? undefined,
			description: override.description ?? undefined,
			url: "https://better-auth.com",
			images: "https://better-auth.com/og.png",
			siteName: "Better Auth",
			...override.openGraph,
		},
		twitter: {
			card: "summary_large_image",
			creator: "@beakcru",
			title: override.title ?? undefined,
			description: override.description ?? undefined,
			images: "https://better-auth.com/og.png",
			...override.twitter,
		},
	};
}

export const baseUrl =
	process.env.NODE_ENV === "development"
		? new URL("http://localhost:3000")
		: new URL(`https://${process.env.VERCEL_URL!}`);

```

--------------------------------------------------------------------------------
/demo/expo-example/src/app/_layout.tsx:
--------------------------------------------------------------------------------

```typescript
import { Slot } from "expo-router";
import "../global.css";
import { SafeAreaProvider } from "react-native-safe-area-context";
import { ImageBackground, View } from "react-native";
import { StyleSheet } from "react-native";

export default function RootLayout() {
	return (
		<SafeAreaProvider>
			<ImageBackground
				className="z-0 flex items-center justify-center"
				source={require("../../assets/bg-image.jpeg")}
				resizeMode="cover"
				style={{
					...(StyleSheet.absoluteFill as any),
					width: "100%",
				}}
			>
				<View
					style={{
						position: "absolute",
						top: 0,
						left: 0,
						right: 0,
						bottom: 0,
						backgroundColor: "black",
						opacity: 0.2,
					}}
				/>
				<Slot />
			</ImageBackground>
		</SafeAreaProvider>
	);
}

```

--------------------------------------------------------------------------------
/packages/better-auth/src/utils/hashing.ts:
--------------------------------------------------------------------------------

```typescript
import { keccak_256 } from "@noble/hashes/sha3.js";
import { utf8ToBytes } from "@noble/hashes/utils.js";

/**
 * TS implementation of ERC-55 ("Mixed-case checksum address encoding") using @noble/hashes
 * @param address - The address to convert to a checksum address
 * @returns The checksummed address
 */
export function toChecksumAddress(address: string) {
	address = address.toLowerCase().replace("0x", "");
	// Hash the address (treat it as UTF-8) and return as a hex string
	const hash = [...keccak_256(utf8ToBytes(address))]
		.map((v) => v.toString(16).padStart(2, "0"))
		.join("");
	let ret = "0x";

	for (let i = 0; i < 40; i++) {
		if (parseInt(hash[i]!, 16) >= 8) {
			ret += address[i]!.toUpperCase();
		} else {
			ret += address[i]!;
		}
	}

	return ret;
}

```

--------------------------------------------------------------------------------
/docs/components/ui/collapsible.tsx:
--------------------------------------------------------------------------------

```typescript
"use client";

import * as CollapsiblePrimitive from "@radix-ui/react-collapsible";

function Collapsible({
	...props
}: React.ComponentProps<typeof CollapsiblePrimitive.Root>) {
	return <CollapsiblePrimitive.Root data-slot="collapsible" {...props} />;
}

function CollapsibleTrigger({
	...props
}: React.ComponentProps<typeof CollapsiblePrimitive.CollapsibleTrigger>) {
	return (
		<CollapsiblePrimitive.CollapsibleTrigger
			data-slot="collapsible-trigger"
			{...props}
		/>
	);
}

function CollapsibleContent({
	...props
}: React.ComponentProps<typeof CollapsiblePrimitive.CollapsibleContent>) {
	return (
		<CollapsiblePrimitive.CollapsibleContent
			data-slot="collapsible-content"
			{...props}
		/>
	);
}

export { Collapsible, CollapsibleTrigger, CollapsibleContent };

```

--------------------------------------------------------------------------------
/packages/better-auth/src/plugins/jwt/adapter.ts:
--------------------------------------------------------------------------------

```typescript
import type { BetterAuthOptions } from "@better-auth/core";
import type { DBAdapter } from "@better-auth/core/db/adapter";
import type { Jwk } from "./types";

export const getJwksAdapter = (adapter: DBAdapter<BetterAuthOptions>) => {
	return {
		getAllKeys: async () => {
			return await adapter.findMany<Jwk>({
				model: "jwks",
			});
		},
		getLatestKey: async () => {
			const key = await adapter.findMany<Jwk>({
				model: "jwks",
				sortBy: {
					field: "createdAt",
					direction: "desc",
				},
				limit: 1,
			});

			return key[0];
		},
		createJwk: async (webKey: Omit<Jwk, "id">) => {
			const jwk = await adapter.create<Omit<Jwk, "id">, Jwk>({
				model: "jwks",
				data: {
					...webKey,
					createdAt: new Date(),
				},
			});

			return jwk;
		},
	};
};

```

--------------------------------------------------------------------------------
/demo/nextjs/components/ui/progress.tsx:
--------------------------------------------------------------------------------

```typescript
"use client";

import * as React from "react";
import * as ProgressPrimitive from "@radix-ui/react-progress";

import { cn } from "@/lib/utils";

const Progress = ({
	ref,
	className,
	value,
	...props
}: React.ComponentPropsWithoutRef<typeof ProgressPrimitive.Root> & {
	ref: React.RefObject<React.ElementRef<typeof ProgressPrimitive.Root>>;
}) => (
	<ProgressPrimitive.Root
		ref={ref}
		className={cn(
			"relative h-2 w-full overflow-hidden rounded-full bg-primary/20",
			className,
		)}
		{...props}
	>
		<ProgressPrimitive.Indicator
			className="h-full w-full flex-1 bg-primary transition-all"
			style={{ transform: `translateX(-${100 - (value || 0)}%)` }}
		/>
	</ProgressPrimitive.Root>
);
Progress.displayName = ProgressPrimitive.Root.displayName;

export { Progress };

```

--------------------------------------------------------------------------------
/demo/nextjs/lib/metadata.ts:
--------------------------------------------------------------------------------

```typescript
import type { Metadata } from "next/types";

export function createMetadata(override: Metadata): Metadata {
	return {
		...override,
		openGraph: {
			title: override.title ?? undefined,
			description: override.description ?? undefined,
			url: "https://demo.better-auth.com",
			images: "https://demo.better-auth.com/og.png",
			siteName: "Better Auth",
			...override.openGraph,
		},
		twitter: {
			card: "summary_large_image",
			creator: "@beakcru",
			title: override.title ?? undefined,
			description: override.description ?? undefined,
			images: "https://demo.better-auth.com/og.png",
			...override.twitter,
		},
	};
}

export const baseUrl =
	process.env.NODE_ENV === "development"
		? new URL("http://localhost:3000")
		: new URL(`https://${process.env.VERCEL_URL!}`);

```

--------------------------------------------------------------------------------
/packages/better-auth/src/plugins/access/types.ts:
--------------------------------------------------------------------------------

```typescript
import type { LiteralString } from "../../types/helper";
import type { AuthorizeResponse, createAccessControl } from "./access";

export type SubArray<T extends unknown[] | readonly unknown[] | any[]> =
	T[number][];

export type Subset<
	K extends keyof R,
	R extends Record<
		string | LiteralString,
		readonly string[] | readonly LiteralString[]
	>,
> = {
	[P in K]: SubArray<R[P]>;
};

export type Statements = {
	readonly [resource: string]: readonly LiteralString[];
};

export type AccessControl<TStatements extends Statements = Statements> =
	ReturnType<typeof createAccessControl<TStatements>>;

export type Role<TStatements extends Statements = Record<string, any>> = {
	authorize: (request: any, connector?: "OR" | "AND") => AuthorizeResponse;
	statements: TStatements;
};

```

--------------------------------------------------------------------------------
/packages/core/src/middleware/index.ts:
--------------------------------------------------------------------------------

```typescript
import { createEndpoint, createMiddleware } from "better-call";
import type { AuthContext } from "../types";

export const optionsMiddleware = createMiddleware(async () => {
	/**
	 * This will be passed on the instance of
	 * the context. Used to infer the type
	 * here.
	 */
	return {} as AuthContext;
});

export const createAuthMiddleware = createMiddleware.create({
	use: [
		optionsMiddleware,
		/**
		 * Only use for post hooks
		 */
		createMiddleware(async () => {
			return {} as {
				returned?: unknown;
				responseHeaders?: Headers;
			};
		}),
	],
});

export const createAuthEndpoint = createEndpoint.create({
	use: [optionsMiddleware],
});

export type AuthEndpoint = ReturnType<typeof createAuthEndpoint>;
export type AuthMiddleware = ReturnType<typeof createAuthMiddleware>;

```

--------------------------------------------------------------------------------
/docs/scripts/sync-orama.ts:
--------------------------------------------------------------------------------

```typescript
import { sync, type OramaDocument } from "fumadocs-core/search/orama-cloud";
import * as fs from "node:fs/promises";
import { CloudManager } from "@oramacloud/client";
import * as process from "node:process";
import "dotenv/config";

const filePath = ".next/server/app/static.json.body";

async function main() {
	const apiKey = process.env.ORAMA_PRIVATE_API_KEY;

	if (!apiKey) {
		console.log("no api key for Orama found, skipping");
		return;
	}

	const content = await fs.readFile(filePath);
	const records = JSON.parse(content.toString()) as OramaDocument[];
	const manager = new CloudManager({ api_key: apiKey });

	await sync(manager, {
		index: process.env.ORAMA_INDEX_ID!,
		documents: records,
		autoDeploy: true,
	});

	console.log(`search updated: ${records.length} records`);
}

void main();

```

--------------------------------------------------------------------------------
/docs/app/api/analytics/conversation/route.ts:
--------------------------------------------------------------------------------

```typescript
import {
	logConversationToAnalytics,
	type InkeepMessage,
} from "@/lib/inkeep-analytics";
import { NextRequest, NextResponse } from "next/server";

export const runtime = "edge";

export async function POST(req: NextRequest) {
	try {
		const { messages }: { messages: InkeepMessage[] } = await req.json();

		if (!messages || !Array.isArray(messages)) {
			return NextResponse.json(
				{ error: "Messages array is required" },
				{ status: 400 },
			);
		}

		const result = await logConversationToAnalytics({
			type: "openai",
			messages,
			properties: {
				source: "better-auth-docs",
				timestamp: new Date().toISOString(),
			},
		});

		return NextResponse.json(result);
	} catch (error) {
		return NextResponse.json(
			{ error: "Failed to log conversation" },
			{ status: 500 },
		);
	}
}

```

--------------------------------------------------------------------------------
/docs/components/ui/sonner.tsx:
--------------------------------------------------------------------------------

```typescript
"use client";

import { useTheme } from "next-themes";
import { Toaster as Sonner, ToasterProps } from "sonner";

const Toaster = ({ ...props }: ToasterProps) => {
	const { theme = "system" } = useTheme();

	return (
		<Sonner
			theme={theme as ToasterProps["theme"]}
			className="toaster group"
			toastOptions={{
				classNames: {
					toast:
						"group toast group-[.toaster]:bg-background group-[.toaster]:text-foreground group-[.toaster]:border-border group-[.toaster]:shadow-lg",
					description: "group-[.toast]:text-muted-foreground",
					actionButton:
						"group-[.toast]:bg-primary group-[.toast]:text-primary-foreground font-medium",
					cancelButton:
						"group-[.toast]:bg-muted group-[.toast]:text-muted-foreground font-medium",
				},
			}}
			{...props}
		/>
	);
};

export { Toaster };

```

--------------------------------------------------------------------------------
/packages/better-auth/src/plugins/api-key/routes/delete-all-expired-api-keys.ts:
--------------------------------------------------------------------------------

```typescript
import { createAuthEndpoint } from "@better-auth/core/middleware";
import type { AuthContext } from "@better-auth/core";

export function deleteAllExpiredApiKeysEndpoint({
	deleteAllExpiredApiKeys,
}: {
	deleteAllExpiredApiKeys(
		ctx: AuthContext,
		byPassLastCheckTime?: boolean,
	): Promise<void>;
}) {
	return createAuthEndpoint(
		"/api-key/delete-all-expired-api-keys",
		{
			method: "POST",
			metadata: {
				SERVER_ONLY: true,
				client: false,
			},
		},
		async (ctx) => {
			try {
				await deleteAllExpiredApiKeys(ctx.context, true);
			} catch (error) {
				ctx.context.logger.error(
					"[API KEY PLUGIN] Failed to delete expired API keys:",
					error,
				);
				return ctx.json({
					success: false,
					error: error,
				});
			}

			return ctx.json({ success: true, error: null });
		},
	);
}

```

--------------------------------------------------------------------------------
/docs/app/api/analytics/feedback/route.ts:
--------------------------------------------------------------------------------

```typescript
import { submitFeedbackToAnalytics } from "@/lib/inkeep-analytics";
import { NextRequest, NextResponse } from "next/server";

export const runtime = "edge";

export async function POST(req: NextRequest) {
	try {
		const { messageId, type, reasons } = await req.json();

		if (!messageId || !type) {
			return NextResponse.json(
				{ error: "messageId and type are required" },
				{ status: 400 },
			);
		}

		if (type !== "positive" && type !== "negative") {
			return NextResponse.json(
				{ error: "type must be 'positive' or 'negative'" },
				{ status: 400 },
			);
		}

		const result = await submitFeedbackToAnalytics({
			messageId,
			type,
			reasons,
		});

		return NextResponse.json(result);
	} catch (error) {
		return NextResponse.json(
			{ error: "Failed to submit feedback" },
			{ status: 500 },
		);
	}
}

```

--------------------------------------------------------------------------------
/demo/nextjs/components/ui/sonner.tsx:
--------------------------------------------------------------------------------

```typescript
"use client";

import { useTheme } from "next-themes";
import { Toaster as Sonner } from "sonner";

type ToasterProps = React.ComponentProps<typeof Sonner>;

const Toaster = ({ ...props }: ToasterProps) => {
	const { theme = "system" } = useTheme();

	return (
		<Sonner
			theme={theme as ToasterProps["theme"]}
			className="toaster group"
			toastOptions={{
				classNames: {
					toast:
						"group toast group-[.toaster]:bg-background group-[.toaster]:text-foreground group-[.toaster]:border-border group-[.toaster]:shadow-lg",
					description: "group-[.toast]:text-muted-foreground",
					actionButton:
						"group-[.toast]:bg-primary group-[.toast]:text-primary-foreground",
					cancelButton:
						"group-[.toast]:bg-muted group-[.toast]:text-muted-foreground",
				},
			}}
			{...props}
		/>
	);
};

export { Toaster };

```

--------------------------------------------------------------------------------
/packages/core/src/utils/error-codes.ts:
--------------------------------------------------------------------------------

```typescript
type UpperLetter =
	| "A"
	| "B"
	| "C"
	| "D"
	| "E"
	| "F"
	| "G"
	| "H"
	| "I"
	| "J"
	| "K"
	| "L"
	| "M"
	| "N"
	| "O"
	| "P"
	| "Q"
	| "R"
	| "S"
	| "T"
	| "U"
	| "V"
	| "W"
	| "X"
	| "Y"
	| "Z";
type SpecialCharacter = "_";

type IsValidUpperSnakeCase<S extends string> = S extends `${infer F}${infer R}`
	? F extends UpperLetter | SpecialCharacter
		? IsValidUpperSnakeCase<R>
		: false
	: true;

type InvalidKeyError<K extends string> =
	`Invalid error code key: "${K}" - must only contain uppercase letters (A-Z) and underscores (_)`;

type ValidateErrorCodes<T> = {
	[K in keyof T]: K extends string
		? IsValidUpperSnakeCase<K> extends false
			? InvalidKeyError<K>
			: T[K]
		: T[K];
};

export function defineErrorCodes<const T extends Record<string, string>>(
	codes: ValidateErrorCodes<T>,
): T {
	return codes as T;
}

```

--------------------------------------------------------------------------------
/packages/stripe/src/utils.ts:
--------------------------------------------------------------------------------

```typescript
import type { StripeOptions } from "./types";

export async function getPlans(options: StripeOptions) {
	return typeof options?.subscription?.plans === "function"
		? await options.subscription?.plans()
		: options.subscription?.plans;
}

export async function getPlanByPriceInfo(
	options: StripeOptions,
	priceId: string,
	priceLookupKey: string | null,
) {
	return await getPlans(options).then((res) =>
		res?.find(
			(plan) =>
				plan.priceId === priceId ||
				plan.annualDiscountPriceId === priceId ||
				(priceLookupKey &&
					(plan.lookupKey === priceLookupKey ||
						plan.annualDiscountLookupKey === priceLookupKey)),
		),
	);
}

export async function getPlanByName(options: StripeOptions, name: string) {
	return await getPlans(options).then((res) =>
		res?.find((plan) => plan.name.toLowerCase() === name.toLowerCase()),
	);
}

```

--------------------------------------------------------------------------------
/packages/cli/CHANGELOG.md:
--------------------------------------------------------------------------------

```markdown
# @better-auth/cli

## 1.3.4

### Patch Changes

- 2bd2fa9: Added support for listing organization members with pagination, sorting, and filtering, and improved client inference for additional organization fields. Also fixed date handling in rate limits and tokens, improved Notion OAuth user extraction, and ensured session is always set in context.

  Organization

  - Added listMembers API with pagination, sorting, and filtering.
  - Added membersLimit param to getFullOrganization.
  - Improved client inference for additional fields in organization schemas.
  - Bug Fixes
  - Fixed date handling by casting DB values to Date objects before using date methods.
  - Fixed Notion OAuth to extract user info correctly.
  - Ensured session is set in context when reading from cookie cach

- Updated dependencies [2bd2fa9]
  - [email protected]

```

--------------------------------------------------------------------------------
/packages/expo/CHANGELOG.md:
--------------------------------------------------------------------------------

```markdown
# @better-auth/expo

## 1.3.4

### Patch Changes

- 2bd2fa9: Added support for listing organization members with pagination, sorting, and filtering, and improved client inference for additional organization fields. Also fixed date handling in rate limits and tokens, improved Notion OAuth user extraction, and ensured session is always set in context.

  Organization

  - Added listMembers API with pagination, sorting, and filtering.
  - Added membersLimit param to getFullOrganization.
  - Improved client inference for additional fields in organization schemas.
  - Bug Fixes
  - Fixed date handling by casting DB values to Date objects before using date methods.
  - Fixed Notion OAuth to extract user info correctly.
  - Ensured session is set in context when reading from cookie cach

- Updated dependencies [2bd2fa9]
  - [email protected]

```

--------------------------------------------------------------------------------
/.github/renovate.json5:
--------------------------------------------------------------------------------

```
{
  $schema: 'https://docs.renovatebot.com/renovate-schema.json',
  extends: [
    'config:recommended',
    'schedule:weekly',
    'group:allNonMajor',
    ':disablePeerDependencies',
    'customManagers:biomeVersions',
    'helpers:pinGitHubActionDigestsToSemver',
  ],
  labels: [
    'dependencies',
  ],
  rangeStrategy: 'bump',
  postUpdateOptions: [
    'pnpmDedupe',
  ],
  ignorePaths: [
    '**/node_modules/**',
  ],
  packageRules: [
    {
      groupName: 'github-actions',
      matchManagers: [
        'github-actions',
      ],
    },
    {
      groupName: 'better-auth dependencies',
      matchManagers: [
        'npm',
      ],
      matchFileNames: [
        'packages/better-auth/**',
      ],
    },
  ],
  ignoreDeps: [
    '@biomejs/biome',
    '@types/node',
    'drizzle-orm',
    'node',
    'npm',
    'pnpm',
  ],
}

```

--------------------------------------------------------------------------------
/packages/telemetry/src/types.ts:
--------------------------------------------------------------------------------

```typescript
export interface DetectionInfo {
	name: string;
	version: string | null;
}

export interface SystemInfo {
	// Software information
	systemPlatform: string;
	systemRelease: string;
	systemArchitecture: string;

	// Machine information
	cpuCount: number;
	cpuModel: string | null;
	cpuSpeed: number | null;
	memory: number;

	// Environment information
	isDocker: boolean;
	isTTY: boolean;
	isWSL: boolean;
	isCI: boolean;
}

export interface AuthConfigInfo {
	options: any;
	plugins: string[];
}

export interface ProjectInfo {
	isGit: boolean;
	packageManager: DetectionInfo | null;
}

export interface TelemetryEvent {
	type: string;
	anonymousId?: string;
	payload: Record<string, any>;
}

export interface TelemetryContext {
	customTrack?: (event: TelemetryEvent) => Promise<void>;
	database?: string;
	adapter?: string;
	skipTestCheck?: boolean;
}

```

--------------------------------------------------------------------------------
/demo/nextjs/app/pricing/page.tsx:
--------------------------------------------------------------------------------

```typescript
import { Pricing } from "@/components/blocks/pricing";

const demoPlans = [
	{
		name: "Plus",
		price: "20",
		yearlyPrice: "16",
		period: "per month",
		features: [
			"Up to 10 projects",
			"Basic analytics",
			"48-hour support response time",
			"Limited API access",
		],
		description: "Perfect for individuals and small projects",
		buttonText: "Start Free Trial",
		href: "/sign-up",
		isPopular: false,
	},
	{
		name: "Pro",
		price: "50",
		yearlyPrice: "40",
		period: "per month",
		features: [
			"Unlimited projects",
			"Advanced analytics",
			"24-hour support response time",
			"Full API access",
			"Priority support",
		],
		description: "Ideal for growing teams and businesses",
		buttonText: "Get Started",
		href: "/sign-up",
		isPopular: true,
	},
];

export default function Page() {
	return <Pricing plans={demoPlans} />;
}

```

--------------------------------------------------------------------------------
/packages/cli/src/utils/install-dependencies.ts:
--------------------------------------------------------------------------------

```typescript
import { exec } from "child_process";

export function installDependencies({
	dependencies,
	packageManager,
	cwd,
}: {
	dependencies: string[];
	packageManager: "npm" | "pnpm" | "bun" | "yarn";
	cwd: string;
}): Promise<boolean> {
	let installCommand: string;
	switch (packageManager) {
		case "npm":
			installCommand = "npm install --force";
			break;
		case "pnpm":
			installCommand = "pnpm install";
			break;
		case "bun":
			installCommand = "bun install";
			break;
		case "yarn":
			installCommand = "yarn install";
			break;
		default:
			throw new Error("Invalid package manager");
	}
	const command = `${installCommand} ${dependencies.join(" ")}`;

	return new Promise((resolve, reject) => {
		exec(command, { cwd }, (error, stdout, stderr) => {
			if (error) {
				reject(new Error(stderr));
				return;
			}
			resolve(true);
		});
	});
}

```

--------------------------------------------------------------------------------
/docs/components/mdx/add-to-cursor.tsx:
--------------------------------------------------------------------------------

```typescript
import Link from "next/link";

export const AddToCursor = () => {
	return (
		<div className="w-max">
			<Link
				href="cursor://anysphere.cursor-deeplink/mcp/install?name=Better%20Auth&config=eyJ1cmwiOiJodHRwczovL21jcC5jaG9ua2llLmFpL2JldHRlci1hdXRoL2JldHRlci1hdXRoLWJ1aWxkZXIvbWNwIn0%3D"
				className="dark:hidden"
			>
				<img
					src="https://cursor.com/deeplink/mcp-install-dark.svg"
					alt="Add Better Auth MCP to Cursor"
					height="32"
				/>
			</Link>

			<Link
				href="cursor://anysphere.cursor-deeplink/mcp/install?name=Better%20Auth&config=eyJ1cmwiOiJodHRwczovL21jcC5jaG9ua2llLmFpL2JldHRlci1hdXRoL2JldHRlci1hdXRoLWJ1aWxkZXIvbWNwIn0%3D"
				className="dark:block hidden"
			>
				<img
					src="https://cursor.com/deeplink/mcp-install-light.svg"
					alt="Add Better Auth MCP to Cursor"
					height="32"
				/>
			</Link>
		</div>
	);
};

```

--------------------------------------------------------------------------------
/packages/better-auth/src/adapters/memory-adapter/adapter.memory.test.ts:
--------------------------------------------------------------------------------

```typescript
import { getAuthTables } from "../../db";
import { testAdapter } from "../test-adapter";
import { memoryAdapter } from "./memory-adapter";
import {
	performanceTestSuite,
	normalTestSuite,
	transactionsTestSuite,
	authFlowTestSuite,
	numberIdTestSuite,
} from "../tests";
let db: Record<string, any[]> = {};

const { execute } = await testAdapter({
	adapter: () => {
		return memoryAdapter(db);
	},
	runMigrations: (options) => {
		db = {};
		const authTables = getAuthTables(options);
		const allModels = Object.keys(authTables);
		for (const model of allModels) {
			const modelName = authTables[model]?.modelName || model;
			db[modelName] = [];
		}
	},
	tests: [
		normalTestSuite(),
		transactionsTestSuite({ disableTests: { ALL: true } }),
		authFlowTestSuite(),
		numberIdTestSuite(),
		performanceTestSuite(),
	],
	async onFinish() {},
});

execute();

```

--------------------------------------------------------------------------------
/docs/app/api/analytics/event/route.ts:
--------------------------------------------------------------------------------

```typescript
import { logEventToAnalytics } from "@/lib/inkeep-analytics";
import { NextRequest, NextResponse } from "next/server";

export const runtime = "edge";

export async function POST(req: NextRequest) {
	try {
		const { type, entityType, messageId, conversationId } = await req.json();

		if (!type || !entityType) {
			return NextResponse.json(
				{ error: "type and entityType are required" },
				{ status: 400 },
			);
		}

		if (entityType !== "message" && entityType !== "conversation") {
			return NextResponse.json(
				{ error: "entityType must be 'message' or 'conversation'" },
				{ status: 400 },
			);
		}

		const result = await logEventToAnalytics({
			type,
			entityType,
			messageId,
			conversationId,
		});

		return NextResponse.json(result);
	} catch (error) {
		return NextResponse.json({ error: "Failed to log event" }, { status: 500 });
	}
}

```

--------------------------------------------------------------------------------
/packages/better-auth/src/plugins/siwe/types.ts:
--------------------------------------------------------------------------------

```typescript
/**
 * SIWE Plugin Type Definitions
 */

export interface WalletAddress {
	id: string;
	userId: string;
	address: string;
	chainId: number;
	isPrimary: boolean;
	createdAt: Date;
}

interface CacaoHeader {
	t: "caip122";
}

// Signed Cacao (CAIP-74)
interface CacaoPayload {
	domain: string;
	aud: string;
	nonce: string;
	iss: string;
	version?: string;
	iat?: string;
	nbf?: string;
	exp?: string;
	statement?: string;
	requestId?: string;
	resources?: string[];
	type?: string;
}

interface Cacao {
	h: CacaoHeader;
	p: CacaoPayload;
	s: {
		t: "eip191" | "eip1271";
		s: string;
		m?: string;
	};
}

export interface SIWEVerifyMessageArgs {
	message: string;
	signature: string;
	address: string;
	chainId: number;
	cacao?: Cacao;
}

export interface ENSLookupArgs {
	walletAddress: string;
}

export interface ENSLookupResult {
	name: string;
	avatar: string;
}

```

--------------------------------------------------------------------------------
/docs/components/landing/gradient-bg.tsx:
--------------------------------------------------------------------------------

```typescript
"use client";
import React from "react";
import { cn } from "@/lib/utils";

export function GradientBG({
	children,
	className,
	...props
}: React.PropsWithChildren<
	{
		className?: string;
	} & React.HTMLAttributes<HTMLElement>
>) {
	return (
		<div
			className={cn(
				"relative flex   content-center  transition duration-500  items-center flex-col flex-nowrap gap-10 h-min justify-center overflow-visible p-px decoration-clone w-full",
			)}
			{...props}
		>
			<div className={cn("w-auto z-10  px-4 py-2 rounded-none", className)}>
				{children}
			</div>
			<div
				className={cn(
					"flex-none inset-0 overflow-hidden absolute z-0 rounded-none bg-gradient-to-tl dark:from-amber-100/30 dark:via-zinc-900 dark:to-black blur-md opacity-50",
				)}
			/>
			<div className="bg-zinc-100 dark:bg-zinc-950 absolute z-1 flex-none inset-[2px] " />
		</div>
	);
}

```

--------------------------------------------------------------------------------
/packages/better-auth/src/plugins/captcha/types.ts:
--------------------------------------------------------------------------------

```typescript
import type { Providers } from "./constants";

export type Provider = (typeof Providers)[keyof typeof Providers];

export interface BaseCaptchaOptions {
	secretKey: string;
	endpoints?: string[];
	siteVerifyURLOverride?: string;
}

export interface GoogleRecaptchaOptions extends BaseCaptchaOptions {
	provider: typeof Providers.GOOGLE_RECAPTCHA;
	minScore?: number;
}

export interface CloudflareTurnstileOptions extends BaseCaptchaOptions {
	provider: typeof Providers.CLOUDFLARE_TURNSTILE;
}

export interface HCaptchaOptions extends BaseCaptchaOptions {
	provider: typeof Providers.HCAPTCHA;
	siteKey?: string;
}

export interface CaptchaFoxOptions extends BaseCaptchaOptions {
	provider: typeof Providers.CAPTCHAFOX;
	siteKey?: string;
}

export type CaptchaOptions =
	| GoogleRecaptchaOptions
	| CloudflareTurnstileOptions
	| HCaptchaOptions
	| CaptchaFoxOptions;

```

--------------------------------------------------------------------------------
/docs/app/v1/_components/v1-text.tsx:
--------------------------------------------------------------------------------

```typescript
export const ShipText = () => {
	const voxels = [
		// V
		[0, 0],
		[0, 1],
		[0, 2],
		[1, 3],
		[2, 2],
		[2, 1],
		[2, 0],
		// 1
		[4, 0],
		[4, 1],
		[4, 2],
		[4, 3],
		// .
		[6, 3],
		// 0
		[8, 0],
		[8, 1],
		[8, 2],
		[8, 3],
		[9, 0],
		[9, 3],
		[10, 0],
		[10, 1],
		[10, 2],
		[10, 3],
	];

	return (
		<div className="flex justify-center items-center mb-0 h-[80%]">
			<div className="grid grid-cols-11 gap-2">
				{Array.from({ length: 44 }).map((_, index) => {
					const row = Math.floor(index / 11);
					const col = index % 11;
					const isActive = voxels.some(([x, y]) => x === col && y === row);
					return (
						<div
							key={index}
							className={`w-8 h-8 ${
								isActive
									? "bg-gradient-to-tr from-stone-100 via-white/90 to-zinc-900"
									: "bg-transparent"
							}`}
						/>
					);
				})}
			</div>
		</div>
	);
};

```

--------------------------------------------------------------------------------
/packages/telemetry/src/detectors/detect-runtime.ts:
--------------------------------------------------------------------------------

```typescript
import { getEnvVar, isTest } from "@better-auth/core/env";
import { isCI } from "./detect-system-info";

export function detectRuntime() {
	// @ts-expect-error: TS doesn't know about Deno global
	if (typeof Deno !== "undefined") {
		// @ts-expect-error: TS doesn't know about Deno global
		const denoVersion = Deno?.version?.deno ?? null;
		return { name: "deno", version: denoVersion };
	}

	if (typeof Bun !== "undefined") {
		const bunVersion = Bun?.version ?? null;
		return { name: "bun", version: bunVersion };
	}

	if (typeof process !== "undefined" && process?.versions?.node) {
		return { name: "node", version: process.versions.node ?? null };
	}
	return { name: "edge", version: null };
}

export function detectEnvironment() {
	return getEnvVar("NODE_ENV") === "production"
		? "production"
		: isCI()
			? "ci"
			: isTest()
				? "test"
				: "development";
}

```

--------------------------------------------------------------------------------
/docs/components/endpoint.tsx:
--------------------------------------------------------------------------------

```typescript
"use client";
import { cn } from "@/lib/utils";
import { useState } from "react";

function Method({ method }: { method: "POST" | "GET" | "DELETE" | "PUT" }) {
	return (
		<div className="flex items-center justify-center h-6 px-2 text-sm font-semibold uppercase border rounded-lg select-none w-fit font-display bg-background">
			{method}
		</div>
	);
}

export function Endpoint({
	path,
	method,
	isServerOnly,
	className,
}: {
	path: string;
	method: "POST" | "GET" | "DELETE" | "PUT";
	isServerOnly?: boolean;
	className?: string;
}) {
	const [copying, setCopying] = useState(false);
	return (
		<div
			className={cn(
				"relative flex items-center w-full gap-2 p-2 border-t border-x border-border bg-fd-secondary/50 group",
				className,
			)}
		>
			<Method method={method} />
			<span className="font-mono text-sm text-muted-foreground">{path}</span>
		</div>
	);
}

```

--------------------------------------------------------------------------------
/docs/components/display-techstack.tsx:
--------------------------------------------------------------------------------

```typescript
import { cn } from "@/lib/utils";
import { techStackIcons } from "./techstack-icons";
import {
	Tooltip,
	TooltipContent,
	TooltipProvider,
	TooltipTrigger,
} from "@/components/ui/tooltip";

export const TechStackDisplay = ({
	skills,
	className,
}: {
	skills: string[];
	className?: string;
}) => {
	return (
		<div
			className={cn(
				"flex gap-7 flex-wrap mt-3 justify-center items-center max-w-4xl",
				className,
			)}
		>
			{skills.map((icon) => {
				return (
					<TooltipProvider delayDuration={50} key={icon}>
						<Tooltip>
							<TooltipTrigger asChild>
								<span className="transform duration-300 hover:rotate-12 transition-transform">
									{techStackIcons[icon].icon}
								</span>
							</TooltipTrigger>
							<TooltipContent>{techStackIcons[icon].name}</TooltipContent>
						</Tooltip>
					</TooltipProvider>
				);
			})}
		</div>
	);
};

```

--------------------------------------------------------------------------------
/docs/components/ui/use-copy-button.tsx:
--------------------------------------------------------------------------------

```typescript
"use client";
import { type MouseEventHandler, useEffect, useRef, useState } from "react";
import { useEffectEvent } from "fumadocs-core/utils/use-effect-event";

export function useCopyButton(
	onCopy: () => void | Promise<void>,
): [checked: boolean, onClick: MouseEventHandler] {
	const [checked, setChecked] = useState(false);
	const timeoutRef = useRef<number | null>(null);

	const onClick: MouseEventHandler = useEffectEvent(() => {
		if (timeoutRef.current) window.clearTimeout(timeoutRef.current);
		const res = Promise.resolve(onCopy());

		void res.then(() => {
			setChecked(true);
			timeoutRef.current = window.setTimeout(() => {
				setChecked(false);
			}, 1500);
		});
	});

	// Avoid updates after being unmounted
	useEffect(() => {
		return () => {
			if (timeoutRef.current) window.clearTimeout(timeoutRef.current);
		};
	}, []);

	return [checked, onClick];
}

```

--------------------------------------------------------------------------------
/packages/better-auth/src/plugins/username/schema.ts:
--------------------------------------------------------------------------------

```typescript
import type { BetterAuthPluginDBSchema } from "@better-auth/core/db";

export const getSchema = (normalizer: {
	username: (username: string) => string;
	displayUsername: (displayUsername: string) => string;
}) => {
	return {
		user: {
			fields: {
				username: {
					type: "string",
					required: false,
					sortable: true,
					unique: true,
					returned: true,
					transform: {
						input(value) {
							return typeof value !== "string"
								? value
								: normalizer.username(value as string);
						},
					},
				},
				displayUsername: {
					type: "string",
					required: false,
					transform: {
						input(value) {
							return typeof value !== "string"
								? value
								: normalizer.displayUsername(value as string);
						},
					},
				},
			},
		},
	} satisfies BetterAuthPluginDBSchema;
};

export type UsernameSchema = ReturnType<typeof getSchema>;

```

--------------------------------------------------------------------------------
/packages/better-auth/src/client/solid/solid-store.ts:
--------------------------------------------------------------------------------

```typescript
import type { Store, StoreValue } from "nanostores";
import { createStore, reconcile } from "solid-js/store";
import type { Accessor } from "solid-js";
import { onCleanup } from "solid-js";

/**
 * Subscribes to store changes and gets store’s value.
 *
 * @param store Store instance.
 * @returns Store value.
 */
export function useStore<
	SomeStore extends Store,
	Value extends StoreValue<SomeStore>,
>(store: SomeStore): Accessor<Value> {
	// Activate the store explicitly:
	// https://github.com/nanostores/solid/issues/19
	const unbindActivation = store.listen(() => {});

	const [state, setState] = createStore({
		value: store.get(),
	});

	const unsubscribe = store.subscribe((newValue) => {
		setState("value", reconcile(newValue));
	});

	onCleanup(() => unsubscribe());

	// Remove temporary listener now that there is already a proper subscriber.
	unbindActivation();

	return () => state.value;
}

```

--------------------------------------------------------------------------------
/packages/better-auth/src/client/vue/vue-store.ts:
--------------------------------------------------------------------------------

```typescript
import type { Store, StoreValue } from "nanostores";
import {
	getCurrentInstance,
	getCurrentScope,
	onScopeDispose,
	readonly,
	shallowRef,
	type DeepReadonly,
	type ShallowRef,
	type UnwrapNestedRefs,
} from "vue";

export function registerStore(store: Store) {
	let instance = getCurrentInstance();
	if (instance && instance.proxy) {
		let vm = instance.proxy as any;
		let cache = "_nanostores" in vm ? vm._nanostores : (vm._nanostores = []);
		cache.push(store);
	}
}

export function useStore<
	SomeStore extends Store,
	Value extends StoreValue<SomeStore>,
>(store: SomeStore): DeepReadonly<UnwrapNestedRefs<ShallowRef<Value>>> {
	let state = shallowRef();

	let unsubscribe = store.subscribe((value) => {
		state.value = value;
	});

	getCurrentScope() && onScopeDispose(unsubscribe);

	if (process.env.NODE_ENV !== "production") {
		registerStore(store);
		return readonly(state);
	}
	return state;
}

```

--------------------------------------------------------------------------------
/demo/expo-example/tsconfig.json:
--------------------------------------------------------------------------------

```json
{
  "compilerOptions": {
    "esModuleInterop": true,
    "skipLibCheck": true,
    "target": "ES2022",
    "lib": ["ES2022"],
    "allowJs": true,
    "resolveJsonModule": true,
    "moduleDetection": "force",
    "isolatedModules": true,
    "incremental": true,
    "disableSourceOfProjectReferenceRedirect": true,
    "tsBuildInfoFile": "${configDir}/.cache/tsbuildinfo.json",
    "strict": true,
    "noUncheckedIndexedAccess": true,
    "checkJs": false,
    "types": ["nativewind"],
    "module": "es2022",
    "moduleResolution": "Bundler",
    "noEmit": true,
    "jsx": "react-native",
    "moduleSuffixes": [".ios", ".android", ".native", ""],
    "paths": {
      "@/*": ["./src/*"]
    }
  },
  "include": [
    "src",
    ".expo/types/**/*.ts",
    "expo-env.d.ts",
    "nativewind-env.d.ts"
  ],
  "exclude": ["node_modules", "build", "dist", ".next", ".expo"],
  "extends": "expo/tsconfig.base"
}

```

--------------------------------------------------------------------------------
/demo/nextjs/components/ui/input.tsx:
--------------------------------------------------------------------------------

```typescript
import * as React from "react";

import { cn } from "@/lib/utils";

function Input({ className, type, ...props }: React.ComponentProps<"input">) {
	return (
		<input
			type={type}
			data-slot="input"
			className={cn(
				"border-input file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground flex h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
				"focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
				"aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
				className,
			)}
			{...props}
		/>
	);
}

export { Input };

```

--------------------------------------------------------------------------------
/docs/components/ui/input.tsx:
--------------------------------------------------------------------------------

```typescript
import * as React from "react";

import { cn } from "@/lib/utils";

function Input({ className, type, ...props }: React.ComponentProps<"input">) {
	return (
		<input
			type={type}
			data-slot="input"
			className={cn(
				"border-input file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground flex h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
				"focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
				"aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
				className,
			)}
			{...props}
		/>
	);
}

export { Input };

```

--------------------------------------------------------------------------------
/packages/core/src/db/schema/account.ts:
--------------------------------------------------------------------------------

```typescript
import * as z from "zod";
import { coreSchema } from "./shared";

export const accountSchema = coreSchema.extend({
	providerId: z.string(),
	accountId: z.string(),
	userId: z.coerce.string(),
	accessToken: z.string().nullish(),
	refreshToken: z.string().nullish(),
	idToken: z.string().nullish(),
	/**
	 * Access token expires at
	 */
	accessTokenExpiresAt: z.date().nullish(),
	/**
	 * Refresh token expires at
	 */
	refreshTokenExpiresAt: z.date().nullish(),
	/**
	 * The scopes that the user has authorized
	 */
	scope: z.string().nullish(),
	/**
	 * Password is only stored in the credential provider
	 */
	password: z.string().nullish(),
});

/**
 * Account schema type used by better-auth, note that it's possible that account could have additional fields
 *
 * todo: we should use generics to extend this type with additional fields from plugins and options in the future
 */
export type Account = z.infer<typeof accountSchema>;

```

--------------------------------------------------------------------------------
/packages/stripe/CHANGELOG.md:
--------------------------------------------------------------------------------

```markdown
# @better-auth/stripe

## 1.3.4

### Patch Changes

- ac6baba: chore: fix typo on `freeTrial`
- c2fb1aa: Fix duplicate trials when switching plans
- 2bd2fa9: Added support for listing organization members with pagination, sorting, and filtering, and improved client inference for additional organization fields. Also fixed date handling in rate limits and tokens, improved Notion OAuth user extraction, and ensured session is always set in context.

  Organization

  - Added listMembers API with pagination, sorting, and filtering.
  - Added membersLimit param to getFullOrganization.
  - Improved client inference for additional fields in organization schemas.
  - Bug Fixes
  - Fixed date handling by casting DB values to Date objects before using date methods.
  - Fixed Notion OAuth to extract user info correctly.
  - Ensured session is set in context when reading from cookie cach

- Updated dependencies [2bd2fa9]
  - [email protected]

```

--------------------------------------------------------------------------------
/packages/telemetry/package.json:
--------------------------------------------------------------------------------

```json
{
  "name": "@better-auth/telemetry",
  "version": "1.4.0-beta.10",
  "description": "Telemetry package for Better Auth",
  "type": "module",
  "main": "./dist/index.js",
  "module": "./dist/index.js",
  "exports": {
    ".": {
      "import": {
        "types": "./dist/index.d.ts",
        "default": "./dist/index.js"
      },
      "require": {
        "types": "./dist/index.d.cts",
        "default": "./dist/index.cjs"
      }
    }
  },
  "typesVersions": {
    "*": {
      "index": [
        "dist/index.d.ts"
      ]
    }
  },
  "scripts": {
    "build": "tsdown",
    "dev": "tsdown --watch",
    "typecheck": "tsc --project tsconfig.json"
  },
  "devDependencies": {
    "@better-auth/core": "workspace:*",
    "tsdown": "^0.15.6",
    "type-fest": "^4.31.0"
  },
  "dependencies": {
    "@better-auth/utils": "0.3.0",
    "@better-fetch/fetch": "catalog:"
  },
  "peerDependencies": {
    "@better-auth/core": "workspace:*"
  }
}

```

--------------------------------------------------------------------------------
/docs/components/landing/section.tsx:
--------------------------------------------------------------------------------

```typescript
import type React from "react";
import SectionSvg from "./section-svg";

const Section = ({
	className,
	id,
	crosses,
	crossesOffset,
	customPaddings,
	children,
}: {
	className: string;
	id: string;
	crosses?: boolean;
	crossesOffset: string;
	customPaddings: boolean;
	children: React.ReactNode;
}) => {
	return (
		<div
			id={id}
			className={`
      relative
      ${customPaddings || `py-10 lg:py-16  ${crosses ? "" : ""}`}
      ${className || " "}`}
		>
			{children}

			<div className="hidden absolute top-0 left-5 w-[0.0625rem] h-[calc(100%_+_30px)] dark:bg-[#26242C] bg-stone-200  pointer-events-none lg:block lg:left-16 xl:left-16" />
			<div className="hidden absolute top-0 right-5 w-[0.0625rem] h-[calc(100%_+_30px)]  dark:bg-[#26242C] bg-stone-200  pointer-events-none lg:block lg:right-14 xl:right-14" />

			{crosses && (
				<>
					<SectionSvg crossesOffset={crossesOffset} />
				</>
			)}
		</div>
	);
};

export default Section;

```

--------------------------------------------------------------------------------
/docs/content/docs/adapters/mongo.mdx:
--------------------------------------------------------------------------------

```markdown
---
title: MongoDB Adapter
description: Integrate Better Auth with MongoDB.
---

MongoDB is a popular NoSQL database that is widely used for building scalable and flexible applications. It provides a flexible schema that allows for easy data modeling and querying.
Read more here: [MongoDB](https://www.mongodb.com/).

## Example Usage

Make sure you have MongoDB installed and configured.
Then, you can use the mongodb adapter.

```ts title="auth.ts"
import { betterAuth } from "better-auth";
import { MongoClient } from "mongodb";
import { mongodbAdapter } from "better-auth/adapters/mongodb";

const client = new MongoClient("mongodb://localhost:27017/database");
const db = client.db();

export const auth = betterAuth({
  database: mongodbAdapter(db, {
    // Optional: if you don't provide a client, database transactions won't be enabled.
    client
  }),
});
```

## Schema generation & migration

For MongoDB, we don't need to generate or migrate the schema.
```

--------------------------------------------------------------------------------
/demo/expo-example/src/components/ui/input.tsx:
--------------------------------------------------------------------------------

```typescript
import * as React from "react";
import { TextInput, type TextInputProps } from "react-native";
import { cn } from "@/lib/utils";

const Input = React.forwardRef<
	React.ElementRef<typeof TextInput>,
	TextInputProps
>(({ className, placeholderClassName, ...props }, ref) => {
	return (
		<TextInput
			ref={ref}
			className={cn(
				"web:flex h-10 native:h-12 web:w-full rounded-md border border-input bg-background px-3 web:py-2 text-base lg:text-sm native:text-lg native:leading-[1.25] text-foreground placeholder:text-muted-foreground web:ring-offset-background file:border-0 file:bg-transparent file:font-medium web:focus-visible:outline-none web:focus-visible:ring-2 web:focus-visible:ring-ring web:focus-visible:ring-offset-2",
				props.editable === false && "opacity-50 web:cursor-not-allowed",
				className,
			)}
			placeholderClassName={cn("text-muted-foreground", placeholderClassName)}
			{...props}
		/>
	);
});

Input.displayName = "Input";

export { Input };

```

--------------------------------------------------------------------------------
/docs/components/techstack-icons.tsx:
--------------------------------------------------------------------------------

```typescript
import { Icons } from "./icons";
type TechStackIconType = {
	[key: string]: {
		name: string;
		icon: any;
	};
};
export const techStackIcons: TechStackIconType = {
	nextJs: {
		name: "Next.js",
		icon: <Icons.nextJS className="w-10 h-10" />,
	},
	nuxt: {
		name: "Nuxt",
		icon: <Icons.nuxt className="w-10 h-10" />,
	},
	svelteKit: {
		name: "SvelteKit",
		icon: <Icons.svelteKit className="w-10 h-10" />,
	},
	solidStart: {
		name: "SolidStart",
		icon: <Icons.solidStart className="w-10 h-10" />,
	},
	react: {
		name: "React",
		icon: <Icons.react className="w-10 h-10" />,
	},
	hono: {
		name: "Hono",
		icon: <Icons.hono className="w-10 h-10" />,
	},
	astro: {
		name: "Astro",
		icon: <Icons.astro className="w-10 h-10" />,
	},
	tanstack: {
		name: "TanStack Start",
		icon: <Icons.tanstack className="w-10 h-10" />,
	},
	expo: {
		name: "Expo",
		icon: <Icons.expo className="w-10 h-10" />,
	},
	nitro: {
		name: "Nitro",
		icon: <Icons.nitro className="w-10 h-10" />,
	},
};

```

--------------------------------------------------------------------------------
/packages/better-auth/src/plugins/admin/has-permission.ts:
--------------------------------------------------------------------------------

```typescript
import { defaultRoles } from "./access";
import type { AdminOptions } from "./types";

type PermissionExclusive =
	| {
			/**
			 * @deprecated Use `permissions` instead
			 */
			permission: { [key: string]: string[] };
			permissions?: never;
	  }
	| {
			permissions: { [key: string]: string[] };
			permission?: never;
	  };

export const hasPermission = (
	input: {
		userId?: string;
		role?: string;
		options?: AdminOptions;
	} & PermissionExclusive,
) => {
	if (input.userId && input.options?.adminUserIds?.includes(input.userId)) {
		return true;
	}
	if (!input.permissions && !input.permission) {
		return false;
	}
	const roles = (input.role || input.options?.defaultRole || "user").split(",");
	const acRoles = input.options?.roles || defaultRoles;
	for (const role of roles) {
		const _role = acRoles[role as keyof typeof acRoles];
		const result = _role?.authorize(input.permission ?? input.permissions);
		if (result?.success) {
			return true;
		}
	}
	return false;
};

```

--------------------------------------------------------------------------------
/docs/components/ui/switch.tsx:
--------------------------------------------------------------------------------

```typescript
"use client";

import * as React from "react";
import * as SwitchPrimitive from "@radix-ui/react-switch";

import { cn } from "@/lib/utils";

function Switch({
	className,
	...props
}: React.ComponentProps<typeof SwitchPrimitive.Root>) {
	return (
		<SwitchPrimitive.Root
			data-slot="switch"
			className={cn(
				"peer data-[state=checked]:bg-primary data-[state=unchecked]:bg-input focus-visible:border-ring focus-visible:ring-ring/50 inline-flex h-5 w-9 shrink-0 items-center rounded-full border-2 border-transparent shadow-xs transition-all outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50",
				className,
			)}
			{...props}
		>
			<SwitchPrimitive.Thumb
				data-slot="switch-thumb"
				className={cn(
					"bg-background pointer-events-none block size-4 rounded-full ring-0 shadow-lg transition-transform data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0",
				)}
			/>
		</SwitchPrimitive.Root>
	);
}

export { Switch };

```

--------------------------------------------------------------------------------
/docs/components/ui/aside-link.tsx:
--------------------------------------------------------------------------------

```typescript
"use client";
import type { ClassValue } from "clsx";
import Link from "next/link";
import { useSelectedLayoutSegment } from "next/navigation";

import { cn } from "@/lib/utils";

type Props = {
	href: string;
	children: React.ReactNode;
	startWith: string;
	title?: string | null;
	className?: ClassValue;
	activeClassName?: ClassValue;
} & React.AnchorHTMLAttributes<HTMLAnchorElement>;

export const AsideLink = ({
	href,
	children,
	startWith,
	title,
	className,
	activeClassName,
	...props
}: Props) => {
	const segment = useSelectedLayoutSegment();
	const path = href;
	const isActive = path.replace("/docs/", "") === segment;

	return (
		<Link
			href={href}
			className={cn(
				isActive
					? cn("text-foreground bg-primary/10", activeClassName)
					: "text-muted-foreground hover:text-foreground hover:bg-primary/10",
				"w-full transition-colors flex items-center gap-x-2.5 hover:bg-primary/10 px-5 py-1",
				className,
			)}
			{...props}
		>
			{children}
		</Link>
	);
};

```

--------------------------------------------------------------------------------
/packages/better-auth/src/adapters/mongodb-adapter/adapter.mongo-db.test.ts:
--------------------------------------------------------------------------------

```typescript
import { MongoClient, ObjectId } from "mongodb";
import { testAdapter } from "../test-adapter";
import { mongodbAdapter } from "./mongodb-adapter";
import {
	normalTestSuite,
	performanceTestSuite,
	authFlowTestSuite,
	transactionsTestSuite,
} from "../tests";

const dbClient = async (connectionString: string, dbName: string) => {
	const client = new MongoClient(connectionString);
	await client.connect();
	const db = client.db(dbName);
	return { db, client };
};

const { db, client } = await dbClient(
	"mongodb://127.0.0.1:27017",
	"better-auth",
);

const { execute } = await testAdapter({
	adapter: (options) => {
		return mongodbAdapter(db, { transaction: false });
	},
	runMigrations: async (betterAuthOptions) => {},
	tests: [
		normalTestSuite(),
		authFlowTestSuite(),
		transactionsTestSuite(),
		// numberIdTestSuite(), // Mongo doesn't support number ids
		performanceTestSuite(),
	],
	customIdGenerator: () => new ObjectId().toString(),
	defaultRetryCount: 20,
});

execute();

```

--------------------------------------------------------------------------------
/demo/nextjs/app/device/denied/page.tsx:
--------------------------------------------------------------------------------

```typescript
"use client";

import { Card } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { X } from "lucide-react";
import Link from "next/link";

export default function DeviceDeniedPage() {
	return (
		<div className="flex min-h-screen items-center justify-center p-4">
			<Card className="w-full max-w-md p-6">
				<div className="space-y-4 text-center">
					<div className="mx-auto flex h-12 w-12 items-center justify-center rounded-full bg-red-100">
						<X className="h-6 w-6 text-red-600" />
					</div>

					<div>
						<h1 className="text-2xl font-bold">Device Denied</h1>
						<p className="text-muted-foreground mt-2">
							The device authorization request has been denied.
						</p>
					</div>

					<p className="text-sm text-muted-foreground">
						The device will not be able to access your account.
					</p>

					<Button asChild className="w-full">
						<Link href="/">Return to Home</Link>
					</Button>
				</div>
			</Card>
		</div>
	);
}

```

--------------------------------------------------------------------------------
/docs/components/generate-secret.tsx:
--------------------------------------------------------------------------------

```typescript
"use client";
import { createRandomStringGenerator } from "@better-auth/utils/random";
import { useState } from "react";
import { Button } from "./ui/button";
export const GenerateSecret = () => {
	const [generated, setGenerated] = useState(false);
	const generateRandomString = createRandomStringGenerator("a-z", "0-9", "A-Z");
	return (
		<div className="my-2">
			<Button
				variant="outline"
				size="sm"
				disabled={generated}
				onClick={() => {
					const elements = document.querySelectorAll("pre code span.line span");
					for (let i = 0; i < elements.length; i++) {
						if (elements[i].textContent === "BETTER_AUTH_SECRET=") {
							elements[i].textContent =
								`BETTER_AUTH_SECRET=${generateRandomString(32)}`;
							setGenerated(true);
							setTimeout(() => {
								elements[i].textContent = "BETTER_AUTH_SECRET=";
								setGenerated(false);
							}, 5000);
						}
					}
				}}
			>
				{generated ? "Generated" : "Generate Secret"}
			</Button>
		</div>
	);
};

```

--------------------------------------------------------------------------------
/e2e/integration/solid-vinxi/e2e/test.spec.ts:
--------------------------------------------------------------------------------

```typescript
import { test, expect } from "@playwright/test";
import { runClient, setup } from "./utils";

const { ref, start, clean } = setup();
test.describe("solid-vinxi", async () => {
	test.beforeEach(async () => start());
	test.afterEach(async () => clean());

	test("signIn with existing email and password should work", async ({
		page,
	}) => {
		await page.goto(`http://localhost:${ref.clientPort}`);
		await page.locator("text=Ready").waitFor();

		await expect(
			runClient(page, ({ client }) => typeof client !== "undefined"),
		).resolves.toBe(true);
		await expect(
			runClient(page, async ({ client }) => client.getSession()),
		).resolves.toEqual({ data: null, error: null });
		await runClient(page, ({ client }) =>
			client.signIn.email({
				email: "[email protected]",
				password: "password123",
			}),
		);

		// Check that the session is now set
		const cookies = await page.context().cookies();
		expect(
			cookies.find((c) => c.name === "better-auth.session_token"),
		).toBeDefined();
	});
});

```

--------------------------------------------------------------------------------
/packages/better-auth/src/adapters/prisma-adapter/test/get-prisma-client.ts:
--------------------------------------------------------------------------------

```typescript
import type { PrismaClient } from "@prisma/client";
type PC = InstanceType<typeof PrismaClient>;

let migrationCount = 0;
const clientMap = new Map<string, PC>();
export const getPrismaClient = async (
	dialect: "sqlite" | "postgresql" | "mysql",
) => {
	if (clientMap.has(`${dialect}-${migrationCount}`)) {
		return clientMap.get(`${dialect}-${migrationCount}`) as PC;
	}
	const { PrismaClient } = await import(
		migrationCount === 0
			? "@prisma/client"
			: `./.tmp/prisma-client-${dialect}-${migrationCount}`
	);
	const db = new PrismaClient();
	clientMap.set(`${dialect}-${migrationCount}`, db);
	return db as PC;
};

export const incrementMigrationCount = () => {
	migrationCount++;
	return migrationCount;
};

export const destroyPrismaClient = ({
	migrationCount,
	dialect,
}: {
	migrationCount: number;
	dialect: "sqlite" | "postgresql" | "mysql";
}) => {
	const db = clientMap.get(`${dialect}-${migrationCount}`);
	if (db) {
		db.$disconnect();
	}
	clientMap.delete(`${dialect}-${migrationCount}`);
};

```

--------------------------------------------------------------------------------
/docs/lib/chat/inkeep-qa-schema.ts:
--------------------------------------------------------------------------------

```typescript
import { z } from "zod";

const InkeepRecordTypes = z.enum([
	"documentation",
	"site",
	"discourse_post",
	"github_issue",
	"github_discussion",
	"stackoverflow_question",
	"discord_forum_post",
	"discord_message",
	"custom_question_answer",
]);

const LinkType = z.union([InkeepRecordTypes, z.string()]);

const LinkSchema = z.object({
	label: z.string().nullish(),
	url: z.string(),
	title: z.string().nullish(),
	type: LinkType.nullish(),
	breadcrumbs: z.array(z.string()).nullish(),
});

const LinksSchema = z.array(LinkSchema).nullish();

export const ProvideLinksToolSchema = z.object({
	links: LinksSchema,
});

const KnownAnswerConfidence = z.enum([
	"very_confident",
	"somewhat_confident",
	"not_confident",
	"no_sources",
	"other",
]);

const AnswerConfidence = z.union([KnownAnswerConfidence, z.string()]); // evolvable

const AIAnnotationsToolSchema = z.object({
	answerConfidence: AnswerConfidence,
});

export const ProvideAIAnnotationsToolSchema = z.object({
	aiAnnotations: AIAnnotationsToolSchema,
});

```

--------------------------------------------------------------------------------
/turbo.json:
--------------------------------------------------------------------------------

```json
{
  "$schema": "https://turborepo.org/schema.json",
  "globalDependencies": [
    "package.json",
    "tsconfig.json",
    "pnpm-lock.yaml",
    "pnpm-workspace.yaml"
  ],
  "tasks": {
    "dev": {
      "cache": false,
      "persistent": true
    },
    "build": {
      "dependsOn": ["^build"],
      "inputs": ["$TURBO_DEFAULT$", ".env*"],
      "outputs": [".next/**", "!.next/cache/**", "dist/**"]
    },
    "clean": {},
    "format": {
      "dependsOn": ["//#format"]
    },
    "//#format": {},
    "lint": {},
    "knip": {
      "cache": true
    },
    "test": {
      "dependsOn": ["build"],
      "outputs": []
    },
    "e2e:smoke": {
      "dependsOn": ["^build"],
      "outputs": []
    },
    "e2e:integration": {
      "dependsOn": ["^build"],
      "outputs": []
    },
    "typecheck": {
      "outputs": [".tsbuildinfo", "dist/**"],
      "cache": true
    },
    "deploy": {
      "cache": false
    },
    "migrate": {
      "cache": false
    },
    "generate": {
      "cache": false
    }
  }
}

```

--------------------------------------------------------------------------------
/demo/nextjs/app/device/success/page.tsx:
--------------------------------------------------------------------------------

```typescript
"use client";

import { Card } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
import { Check } from "lucide-react";
import Link from "next/link";

export default function DeviceSuccessPage() {
	return (
		<div className="flex min-h-screen items-center justify-center p-4">
			<Card className="w-full max-w-md p-6">
				<div className="space-y-4 text-center">
					<div className="mx-auto flex h-12 w-12 items-center justify-center rounded-full bg-green-100">
						<Check className="h-6 w-6 text-green-600" />
					</div>

					<div>
						<h1 className="text-2xl font-bold">Device Approved</h1>
						<p className="text-muted-foreground mt-2">
							The device has been successfully authorized to access your
							account.
						</p>
					</div>

					<p className="text-sm text-muted-foreground">
						You can now return to your device to continue.
					</p>

					<Button asChild className="w-full">
						<Link href="/">Return to Home</Link>
					</Button>
				</div>
			</Card>
		</div>
	);
}

```

--------------------------------------------------------------------------------
/packages/better-auth/src/plugins/two-factor/client.ts:
--------------------------------------------------------------------------------

```typescript
import type { BetterAuthClientPlugin } from "@better-auth/core";
import type { twoFactor as twoFa } from "../../plugins/two-factor";

export const twoFactorClient = (options?: {
	/**
	 * a redirect function to call if a user needs to verify
	 * their two factor
	 */
	onTwoFactorRedirect?: () => void | Promise<void>;
}) => {
	return {
		id: "two-factor",
		$InferServerPlugin: {} as ReturnType<typeof twoFa>,
		atomListeners: [
			{
				matcher: (path) => path.startsWith("/two-factor/"),
				signal: "$sessionSignal",
			},
		],
		pathMethods: {
			"/two-factor/disable": "POST",
			"/two-factor/enable": "POST",
			"/two-factor/send-otp": "POST",
			"/two-factor/generate-backup-codes": "POST",
		},
		fetchPlugins: [
			{
				id: "two-factor",
				name: "two-factor",
				hooks: {
					async onSuccess(context) {
						if (context.data?.twoFactorRedirect) {
							if (options?.onTwoFactorRedirect) {
								await options.onTwoFactorRedirect();
							}
						}
					},
				},
			},
		],
	} satisfies BetterAuthClientPlugin;
};

```

--------------------------------------------------------------------------------
/demo/nextjs/components/ui/avatar.tsx:
--------------------------------------------------------------------------------

```typescript
"use client";

import * as React from "react";
import * as AvatarPrimitive from "@radix-ui/react-avatar";

import { cn } from "@/lib/utils";

function Avatar({
	className,
	...props
}: React.ComponentProps<typeof AvatarPrimitive.Root>) {
	return (
		<AvatarPrimitive.Root
			data-slot="avatar"
			className={cn(
				"relative flex size-8 shrink-0 overflow-hidden rounded-full",
				className,
			)}
			{...props}
		/>
	);
}

function AvatarImage({
	className,
	...props
}: React.ComponentProps<typeof AvatarPrimitive.Image>) {
	return (
		<AvatarPrimitive.Image
			data-slot="avatar-image"
			className={cn("aspect-square size-full", className)}
			{...props}
		/>
	);
}

function AvatarFallback({
	className,
	...props
}: React.ComponentProps<typeof AvatarPrimitive.Fallback>) {
	return (
		<AvatarPrimitive.Fallback
			data-slot="avatar-fallback"
			className={cn(
				"bg-muted flex size-full items-center justify-center rounded-full",
				className,
			)}
			{...props}
		/>
	);
}

export { Avatar, AvatarImage, AvatarFallback };

```

--------------------------------------------------------------------------------
/docs/components/nav-link.tsx:
--------------------------------------------------------------------------------

```typescript
"use client";
import { cn } from "@/lib/utils";
import Link from "next/link";
import { useSelectedLayoutSegment } from "next/navigation";

type Props = {
	href: string;
	children: React.ReactNode;
	className?: string;
	external?: boolean;
};

export const NavLink = ({ href, children, className, external }: Props) => {
	const segment = useSelectedLayoutSegment();
	const isActive =
		segment === href.slice(1) || (segment === null && href === "/");

	return (
		<li className={cn("relative group", className)}>
			<Link
				href={href}
				className={cn(
					"w-full h-full block py-4 px-5 transition-colors",
					"group-hover:text-foreground",
					isActive ? "text-foreground" : "text-muted-foreground",
				)}
				target={external ? "_blank" : "_parent"}
			>
				{children}
			</Link>
			<div
				className={cn(
					"absolute bottom-0 h-0.5 bg-muted-foreground opacity-0 transition-all duration-500",
					"group-hover:opacity-100 group-hover:w-full",
					isActive ? "opacity-100 w-full" : "w-0",
				)}
			/>
		</li>
	);
};

```

--------------------------------------------------------------------------------
/docs/components/ui/avatar.tsx:
--------------------------------------------------------------------------------

```typescript
"use client";

import * as React from "react";
import * as AvatarPrimitive from "@radix-ui/react-avatar";

import { cn } from "@/lib/utils";

function Avatar({
	className,
	...props
}: React.ComponentProps<typeof AvatarPrimitive.Root>) {
	return (
		<AvatarPrimitive.Root
			data-slot="avatar"
			className={cn(
				"relative flex size-8 shrink-0 overflow-hidden rounded-full",
				className,
			)}
			{...props}
		/>
	);
}

function AvatarImage({
	className,
	...props
}: React.ComponentProps<typeof AvatarPrimitive.Image>) {
	return (
		<AvatarPrimitive.Image
			data-slot="avatar-image"
			className={cn("aspect-square size-full", className)}
			{...props}
		/>
	);
}

function AvatarFallback({
	className,
	...props
}: React.ComponentProps<typeof AvatarPrimitive.Fallback>) {
	return (
		<AvatarPrimitive.Fallback
			data-slot="avatar-fallback"
			className={cn(
				"bg-muted flex size-full items-center justify-center rounded-full",
				className,
			)}
			{...props}
		/>
	);
}

export { Avatar, AvatarImage, AvatarFallback };

```

--------------------------------------------------------------------------------
/demo/nextjs/components/tier-labels.tsx:
--------------------------------------------------------------------------------

```typescript
import type React from "react";
import { cva, type VariantProps } from "class-variance-authority";
import { cn } from "@/lib/utils";

const tierVariants = cva(
	"inline-flex items-center rounded-full px-3 py-1 text-xs font-semibold ring-1 ring-inset transition-all duration-300 ease-in-out",
	{
		variants: {
			variant: {
				free: "bg-gray-500 text-white ring-gray-400 hover:bg-gray-600",
				plus: "bg-lime-700/40 text-white ring-lime-200/40 hover:bg-lime-600",
				pro: "bg-purple-800/80 ring-purple-400 hover:bg-purple-700",
			},
		},
		defaultVariants: {
			variant: "free",
		},
	},
);

export interface SubscriptionTierLabelProps
	extends React.HTMLAttributes<HTMLSpanElement>,
		VariantProps<typeof tierVariants> {
	tier?: "free" | "plus" | "pro";
}

export const SubscriptionTierLabel: React.FC<SubscriptionTierLabelProps> = ({
	tier = "free",
	className,
	...props
}) => {
	return (
		<span className={cn(tierVariants({ variant: tier }), className)} {...props}>
			{tier.charAt(0).toUpperCase() + tier.slice(1)}
		</span>
	);
};

```

--------------------------------------------------------------------------------
/demo/nextjs/components/ui/slider.tsx:
--------------------------------------------------------------------------------

```typescript
"use client";

import * as React from "react";
import * as SliderPrimitive from "@radix-ui/react-slider";

import { cn } from "@/lib/utils";

const Slider = ({
	ref,
	className,
	...props
}: React.ComponentPropsWithoutRef<typeof SliderPrimitive.Root> & {
	ref: React.RefObject<React.ElementRef<typeof SliderPrimitive.Root>>;
}) => (
	<SliderPrimitive.Root
		ref={ref}
		className={cn(
			"relative flex w-full touch-none select-none items-center",
			className,
		)}
		{...props}
	>
		<SliderPrimitive.Track className="relative h-1.5 w-full grow overflow-hidden rounded-full bg-primary/20">
			<SliderPrimitive.Range className="absolute h-full bg-primary" />
		</SliderPrimitive.Track>
		<SliderPrimitive.Thumb className="block h-4 w-4 rounded-full border border-primary/50 bg-background shadow transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50" />
	</SliderPrimitive.Root>
);
Slider.displayName = SliderPrimitive.Root.displayName;

export { Slider };

```

--------------------------------------------------------------------------------
/e2e/integration/vanilla-node/e2e/test.spec.ts:
--------------------------------------------------------------------------------

```typescript
import { test, expect } from "@playwright/test";
import { runClient, setup } from "./utils";

const { ref, start, clean } = setup();
test.describe("vanilla-node", async () => {
	test.beforeEach(async () => start());
	test.afterEach(async () => clean());

	test("signIn with existing email and password should work", async ({
		page,
	}) => {
		await page.goto(
			`http://localhost:${ref.clientPort}/?port=${ref.serverPort}`,
		);
		await page.locator("text=Ready").waitFor();

		await expect(
			runClient(page, ({ client }) => typeof client !== "undefined"),
		).resolves.toBe(true);
		await expect(
			runClient(page, async ({ client }) => client.getSession()),
		).resolves.toEqual({ data: null, error: null });
		await runClient(page, ({ client }) =>
			client.signIn.email({
				email: "[email protected]",
				password: "password123",
			}),
		);

		// Check that the session is now set
		const cookies = await page.context().cookies();
		expect(
			cookies.find((c) => c.name === "better-auth.session_token"),
		).toBeDefined();
	});
});

```

--------------------------------------------------------------------------------
/packages/core/src/oauth2/utils.ts:
--------------------------------------------------------------------------------

```typescript
import { base64Url } from "@better-auth/utils/base64";
import type { OAuth2Tokens } from "./oauth-provider";

export function getOAuth2Tokens(data: Record<string, any>): OAuth2Tokens {
	const getDate = (seconds: number) => {
		const now = new Date();
		return new Date(now.getTime() + seconds * 1000);
	};

	return {
		tokenType: data.token_type,
		accessToken: data.access_token,
		refreshToken: data.refresh_token,
		accessTokenExpiresAt: data.expires_in
			? getDate(data.expires_in)
			: undefined,
		refreshTokenExpiresAt: data.refresh_token_expires_in
			? getDate(data.refresh_token_expires_in)
			: undefined,
		scopes: data?.scope
			? typeof data.scope === "string"
				? data.scope.split(" ")
				: data.scope
			: [],
		idToken: data.id_token,
	};
}

export async function generateCodeChallenge(codeVerifier: string) {
	const encoder = new TextEncoder();
	const data = encoder.encode(codeVerifier);
	const hash = await crypto.subtle.digest("SHA-256", data);
	return base64Url.encode(new Uint8Array(hash), {
		padding: false,
	});
}

```

--------------------------------------------------------------------------------
/docs/scripts/endpoint-to-doc/output.mdx:
--------------------------------------------------------------------------------

```markdown
{/* -------------------------------------------------------- */}
{/*                   APIMethod component                    */}
{/* -------------------------------------------------------- */}

<APIMethod
  path="/subscription/restore"
  method="POST"
  requireSession
>
```ts
type restoreSubscription = {
    /**
     * Reference id of the subscription to restore. 
     */
    referenceId?: string = '123'
    /**
     * The id of the subscription to restore. 
     */
    subscriptionId: string = 'sub_123'
}
```
</APIMethod>

{/* -------------------------------------------------------- */}
{/*                JSDOC For the endpoint                    */}
{/* -------------------------------------------------------- */}

/**
 * ### Endpoint
 * 
 * POST `/subscription/restore`
 * 
 * ### API Methods
 * 
 * **server:**
 * `auth.api.restoreSubscription`
 * 
 * **client:**
 * `authClient.subscription.restore`
 * 
 * @see [Read our docs to learn more.](https://better-auth.com/docs/plugins/subscription#api-method-subscription-restore)
 */
```

--------------------------------------------------------------------------------
/packages/better-auth/src/plugins/index.ts:
--------------------------------------------------------------------------------

```typescript
export * from "./organization";
export * from "./two-factor";
export * from "./username";
export * from "./bearer";
export * from "../types/plugins";
export * from "../utils/hide-metadata";
export * from "./magic-link";
export * from "./phone-number";
export * from "./anonymous";
export * from "./admin";
export * from "./generic-oauth";
export * from "./jwt";
export * from "./multi-session";
export * from "./email-otp";
export * from "./one-tap";
export * from "./oauth-proxy";
export * from "./custom-session";
export * from "./open-api";
export * from "./oidc-provider";
export * from "./captcha";
export * from "./api-key";
export * from "./haveibeenpwned";
export * from "./one-time-token";
export * from "./mcp";
export * from "./siwe";
export * from "./device-authorization";
export * from "./last-login-method";
/**
 * @deprecated Please import from `better-auth/api` directly.
 */
export {
	createAuthEndpoint,
	createAuthMiddleware,
	optionsMiddleware,
	type AuthEndpoint,
	type AuthMiddleware,
} from "@better-auth/core/middleware";

```

--------------------------------------------------------------------------------
/demo/expo-example/app.config.ts:
--------------------------------------------------------------------------------

```typescript
import type { ConfigContext, ExpoConfig } from "expo/config";

export default ({ config }: ConfigContext): ExpoConfig => ({
	...config,
	name: "Better Auth",
	slug: "better-auth",
	scheme: "better-auth",
	version: "0.1.0",
	orientation: "portrait",
	icon: "./assets/icon.png",
	userInterfaceStyle: "automatic",
	splash: {
		image: "./assets/icon.png",
		resizeMode: "contain",
		backgroundColor: "#1F104A",
	},
	web: {
		bundler: "metro",
		output: "server",
	},
	updates: {
		fallbackToCacheTimeout: 0,
	},
	assetBundlePatterns: ["**/*"],
	ios: {
		bundleIdentifier: "your.bundle.identifier",
		supportsTablet: true,
	},
	android: {
		package: "your.bundle.identifier",
		adaptiveIcon: {
			foregroundImage: "./assets/icon.png",
			backgroundColor: "#1F104A",
		},
	},
	// extra: {
	//   eas: {
	//     projectId: "your-eas-project-id",
	//   },
	// },
	experiments: {
		tsconfigPaths: true,
		typedRoutes: true,
	},
	plugins: [
		[
			"expo-router",
			{
				origin: "http://localhost:8081",
			},
		],
		"expo-secure-store",
		"expo-font",
	],
});

```

--------------------------------------------------------------------------------
/packages/cli/test/__snapshots__/migrations.sql:
--------------------------------------------------------------------------------

```sql
create table "user" ("id" text not null primary key, "name" text not null, "email" text not null unique, "emailVerified" integer not null, "image" text, "createdAt" date not null, "updatedAt" date not null);

create table "session" ("id" text not null primary key, "expiresAt" date not null, "token" text not null unique, "createdAt" date not null, "updatedAt" date not null, "ipAddress" text, "userAgent" text, "userId" text not null references "user" ("id") on delete cascade);

create table "account" ("id" text not null primary key, "accountId" text not null, "providerId" text not null, "userId" text not null references "user" ("id") on delete cascade, "accessToken" text, "refreshToken" text, "idToken" text, "accessTokenExpiresAt" date, "refreshTokenExpiresAt" date, "scope" text, "password" text, "createdAt" date not null, "updatedAt" date not null);

create table "verification" ("id" text not null primary key, "identifier" text not null, "value" text not null, "expiresAt" date not null, "createdAt" date not null, "updatedAt" date not null);
```

--------------------------------------------------------------------------------
/docs/components/docs/ui/collapsible.tsx:
--------------------------------------------------------------------------------

```typescript
"use client";
import * as CollapsiblePrimitive from "@radix-ui/react-collapsible";
import { forwardRef, useEffect, useState } from "react";
import { cn } from "../../../lib/utils";

const Collapsible = CollapsiblePrimitive.Root;

const CollapsibleTrigger = CollapsiblePrimitive.CollapsibleTrigger;

const CollapsibleContent = forwardRef<
	HTMLDivElement,
	React.ComponentPropsWithoutRef<typeof CollapsiblePrimitive.CollapsibleContent>
>(({ children, ...props }, ref) => {
	const [mounted, setMounted] = useState(false);

	useEffect(() => {
		setMounted(true);
	}, []);

	return (
		<CollapsiblePrimitive.CollapsibleContent
			ref={ref}
			{...props}
			className={cn(
				"overflow-hidden",
				mounted &&
					"data-[state=closed]:animate-fd-collapsible-up data-[state=open]:animate-fd-collapsible-down",
				props.className,
			)}
		>
			{children}
		</CollapsiblePrimitive.CollapsibleContent>
	);
});

CollapsibleContent.displayName =
	CollapsiblePrimitive.CollapsibleContent.displayName;

export { Collapsible, CollapsibleTrigger, CollapsibleContent };

```

--------------------------------------------------------------------------------
/docs/next.config.js:
--------------------------------------------------------------------------------

```javascript
import { createMDX } from "fumadocs-mdx/next";

const withMDX = createMDX();

/** @type {import('next').NextConfig} */
const config = {
	async rewrites() {
		return [
			{
				source: "/docs/:path*.mdx",
				destination: "/llms.txt/:path*",
			},
		];
	},
	redirects: async () => {
		return [
			{
				source: "/docs",
				destination: "/docs/introduction",
				permanent: true,
			},
			{
				source: "/docs/examples",
				destination: "/docs/examples/next-js",
				permanent: true,
			},
		];
	},
	serverExternalPackages: [
		"ts-morph",
		"typescript",
		"oxc-transform",
		"@shikijs/twoslash",
	],
	images: {
		remotePatterns: [
			{
				hostname: "images.unsplash.com",
			},
			{
				hostname: "assets.aceternity.com",
			},
			{
				hostname: "pbs.twimg.com",
			},
			{
				hostname: "github.com",
			},
			{
				hostname: "hebbkx1anhila5yf.public.blob.vercel-storage.com",
			},
		],
	},
	reactStrictMode: true,
	typescript: {
		ignoreBuildErrors: true,
	},
	experimental: {
		turbopackFileSystemCacheForDev: true,
	},
};

export default withMDX(config);

```

--------------------------------------------------------------------------------
/packages/better-auth/src/index.ts:
--------------------------------------------------------------------------------

```typescript
//#region Re-exports necessaries from core module
export * from "@better-auth/core/env";
export * from "@better-auth/core";
export * from "@better-auth/core/oauth2";
export * from "@better-auth/core/error";
export * from "@better-auth/core/utils";
//#endregion
export { getCurrentAdapter } from "@better-auth/core/context";
export * from "./auth";
export * from "./types";
export * from "./utils";
export type * from "better-call";
export type * from "zod/v4";
// @ts-expect-error we need to export core to make sure type annotations works with v4/core
export type * from "zod/v4/core";
//@ts-expect-error: we need to export helper types even when they conflict with better-call types to avoid "The inferred type of 'auth' cannot be named without a reference to..."
export type * from "./types/helper";
// export this as we are referencing OAuth2Tokens in the `refresh-token` api as return type

// telemetry exports for CLI and consumers
export {
	createTelemetry,
	getTelemetryAuthConfig,
	type TelemetryEvent,
} from "@better-auth/telemetry";
export { APIError } from "./api";

```

--------------------------------------------------------------------------------
/e2e/smoke/test/fixtures/cloudflare/src/index.ts:
--------------------------------------------------------------------------------

```typescript
import { Hono } from "hono";

import { betterAuth } from "better-auth";
import { createDrizzle } from "./db";
import { drizzleAdapter } from "better-auth/adapters/drizzle";

interface CloudflareBindings {
	DB: D1Database;
}

const createAuth = (env: CloudflareBindings) =>
	betterAuth({
		baseURL: "http://localhost:4000",
		database: drizzleAdapter(createDrizzle(env.DB), { provider: "sqlite" }),
		emailAndPassword: {
			enabled: true,
		},
		logger: {
			level: "debug",
		},
	});

type Auth = ReturnType<typeof createAuth>;

const app = new Hono<{
	Bindings: CloudflareBindings;
	Variables: {
		auth: Auth;
	};
}>();

app.use("*", async (c, next) => {
	const auth = createAuth(c.env);
	c.set("auth", auth);
	await next();
});

app.on(["POST", "GET"], "/api/auth/*", (c) => c.var.auth.handler(c.req.raw));

app.get("/", async (c) => {
	const session = await c.var.auth.api.getSession({
		headers: c.req.raw.headers,
	});
	if (session) return c.text("Hello " + session.user.name);
	return c.text("Not logged in");
});

export default app satisfies ExportedHandler<CloudflareBindings>;

```

--------------------------------------------------------------------------------
/demo/nextjs/components/ui/badge.tsx:
--------------------------------------------------------------------------------

```typescript
import * as React from "react";
import { cva, type VariantProps } from "class-variance-authority";

import { cn } from "@/lib/utils";

const badgeVariants = cva(
	"inline-flex items-center rounded-md border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2",
	{
		variants: {
			variant: {
				default:
					"border-transparent bg-primary text-primary-foreground shadow hover:bg-primary/80",
				secondary:
					"border-transparent bg-secondary text-secondary-foreground hover:bg-secondary/80",
				destructive:
					"border-transparent bg-destructive text-destructive-foreground shadow hover:bg-destructive/80",
				outline: "text-foreground",
			},
		},
		defaultVariants: {
			variant: "default",
		},
	},
);

export interface BadgeProps
	extends React.HTMLAttributes<HTMLDivElement>,
		VariantProps<typeof badgeVariants> {}

function Badge({ className, variant, ...props }: BadgeProps) {
	return (
		<div className={cn(badgeVariants({ variant }), className)} {...props} />
	);
}

export { Badge, badgeVariants };

```

--------------------------------------------------------------------------------
/docs/source.config.ts:
--------------------------------------------------------------------------------

```typescript
import {
	defineDocs,
	defineConfig,
	defineCollections,
} from "fumadocs-mdx/config";
import { z } from "zod";
import { remarkAutoTypeTable, createGenerator } from "fumadocs-typescript";
import { remarkNpm } from "fumadocs-core/mdx-plugins";

export const docs = defineDocs({
	dir: "./content/docs",
});

export const changelogCollection = defineCollections({
	type: "doc",
	dir: "./content/changelogs",
	schema: z.object({
		title: z.string(),
		description: z.string(),
		date: z.date(),
	}),
});

export const blogCollection = defineCollections({
	type: "doc",
	dir: "./content/blogs",
	schema: z.object({
		title: z.string(),
		description: z.string(),
		date: z.date(),
		author: z.object({
			name: z.string(),
			avatar: z.string(),
			twitter: z.string().optional(),
		}),
		image: z.string(),
		tags: z.array(z.string()),
	}),
});

const generator = createGenerator();

export default defineConfig({
	mdxOptions: {
		remarkPlugins: [
			[
				remarkNpm,
				{
					persist: {
						id: "persist-install",
					},
				},
			],
			[remarkAutoTypeTable, { generator }],
		],
	},
});

```

--------------------------------------------------------------------------------
/packages/better-auth/src/utils/merger.ts:
--------------------------------------------------------------------------------

```typescript
import { clone } from "./clone";

const mergeObjects = (target: any, source: any): any => {
	for (const key in source) {
		if (!source.hasOwnProperty(key)) continue;

		if (key === "constructor" || key === "prototype" || key === "__proto__")
			continue;

		const value = source[key];

		if (isPrimitive(value)) {
			if (value !== undefined || !(key in target)) {
				target[key] = value;
			}
		} else if (!target[key] || isArray(value)) {
			target[key] = clone(value);
		} else {
			target[key] = mergeObjects(target[key], value);
		}
	}

	return target;
};

const isArray = (value: unknown): value is unknown[] => {
	return Array.isArray(value);
};

const isPrimitive = (
	value: unknown,
): value is bigint | symbol | string | number | boolean | null | undefined => {
	if (value === null) return true;

	const type = typeof value;

	return type !== "object" && type !== "function";
};

export const merge = (objects: object[]): object => {
	const target = clone(objects[0]!);

	for (let i = 1, l = objects.length; i < l; i++) {
		mergeObjects(target, objects[i]!);
	}

	return target;
};

```

--------------------------------------------------------------------------------
/packages/better-auth/src/plugins/organization/access/statement.ts:
--------------------------------------------------------------------------------

```typescript
import { createAccessControl } from "../../access";

export const defaultStatements = {
	organization: ["update", "delete"],
	member: ["create", "update", "delete"],
	invitation: ["create", "cancel"],
	team: ["create", "update", "delete"],
	ac: ["create", "read", "update", "delete"],
} as const;

export const defaultAc = createAccessControl(defaultStatements);

export const adminAc = defaultAc.newRole({
	organization: ["update"],
	invitation: ["create", "cancel"],
	member: ["create", "update", "delete"],
	team: ["create", "update", "delete"],
	ac: ["create", "read", "update", "delete"],
});

export const ownerAc = defaultAc.newRole({
	organization: ["update", "delete"],
	member: ["create", "update", "delete"],
	invitation: ["create", "cancel"],
	team: ["create", "update", "delete"],
	ac: ["create", "read", "update", "delete"],
});

export const memberAc = defaultAc.newRole({
	organization: [],
	member: [],
	invitation: [],
	team: [],
	ac: ["read"], // Allow members to see all roles for their org.
});

export const defaultRoles = {
	admin: adminAc,
	owner: ownerAc,
	member: memberAc,
};

```

--------------------------------------------------------------------------------
/packages/better-auth/src/adapters/tests/number-id.ts:
--------------------------------------------------------------------------------

```typescript
import { expect } from "vitest";
import { createTestSuite } from "../create-test-suite";
import type { User } from "better-auth/types";
import { getNormalTestSuiteTests } from "./normal";

export const numberIdTestSuite = createTestSuite(
	"number-id",
	{
		defaultBetterAuthOptions: {
			advanced: {
				database: {
					useNumberId: true,
				},
			},
		},
		alwaysMigrate: true,
		prefixTests: "number-id",
	},
	(helpers) => {
		const { "create - should use generateId if provided": _, ...normalTests } =
			getNormalTestSuiteTests({ ...helpers });

		return {
			"init - tests": async () => {
				const opts = helpers.getBetterAuthOptions();
				expect(opts.advanced?.database?.useNumberId).toBe(true);
			},
			"create - should return a number id": async () => {
				const user = await helpers.generate("user");
				const res = await helpers.adapter.create<User>({
					model: "user",
					data: user,
					forceAllowId: true,
				});
				expect(res).toHaveProperty("id");
				expect(typeof res.id).toBe("string");
				expect(parseInt(res.id)).toBeGreaterThan(0);
			},
			...normalTests,
		};
	},
);

```

--------------------------------------------------------------------------------
/docs/components/docs/ui/popover.tsx:
--------------------------------------------------------------------------------

```typescript
"use client";
import * as PopoverPrimitive from "@radix-ui/react-popover";
import * as React from "react";
import { cn } from "../../../lib/utils";

const Popover = PopoverPrimitive.Root;

const PopoverTrigger = PopoverPrimitive.Trigger;

const PopoverContent = React.forwardRef<
	React.ComponentRef<typeof PopoverPrimitive.Content>,
	React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>
>(({ className, align = "center", sideOffset = 4, ...props }, ref) => (
	<PopoverPrimitive.Portal>
		<PopoverPrimitive.Content
			ref={ref}
			align={align}
			sideOffset={sideOffset}
			side="bottom"
			className={cn(
				"z-50 min-w-[220px] max-w-[98vw] rounded-lg border bg-fd-popover p-2 text-sm text-fd-popover-foreground shadow-lg focus-visible:outline-none data-[state=closed]:animate-fd-popover-out data-[state=open]:animate-fd-popover-in",
				className,
			)}
			{...props}
		/>
	</PopoverPrimitive.Portal>
));
PopoverContent.displayName = PopoverPrimitive.Content.displayName;

const PopoverClose = PopoverPrimitive.PopoverClose;

export { Popover, PopoverTrigger, PopoverContent, PopoverClose };

```

--------------------------------------------------------------------------------
/packages/better-auth/src/crypto/password.ts:
--------------------------------------------------------------------------------

```typescript
import { constantTimeEqual } from "./buffer";
import { scryptAsync } from "@noble/hashes/scrypt.js";
import { hex } from "@better-auth/utils/hex";
import { hexToBytes } from "@noble/hashes/utils.js";
import { BetterAuthError } from "@better-auth/core/error";

const config = {
	N: 16384,
	r: 16,
	p: 1,
	dkLen: 64,
};

async function generateKey(password: string, salt: string) {
	return await scryptAsync(password.normalize("NFKC"), salt, {
		N: config.N,
		p: config.p,
		r: config.r,
		dkLen: config.dkLen,
		maxmem: 128 * config.N * config.r * 2,
	});
}

export const hashPassword = async (password: string) => {
	const salt = hex.encode(crypto.getRandomValues(new Uint8Array(16)));
	const key = await generateKey(password, salt);
	return `${salt}:${hex.encode(key)}`;
};

export const verifyPassword = async ({
	hash,
	password,
}: {
	hash: string;
	password: string;
}) => {
	const [salt, key] = hash.split(":");
	if (!salt || !key) {
		throw new BetterAuthError("Invalid password hash");
	}
	const targetKey = await generateKey(password, salt!);
	return constantTimeEqual(targetKey, hexToBytes(key));
};

```

--------------------------------------------------------------------------------
/.github/workflows/preview.yml:
--------------------------------------------------------------------------------

```yaml
name: Publish Any Commit
on: [pull_request]

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
        with:
          fetch-depth: 0

      - name: Cache turbo build setup
        uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
        with:
          path: .turbo
          key: ${{ runner.os }}-turbo-${{ github.sha }}
          restore-keys: |
            ${{ runner.os }}-turbo-

      - uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4.1.0

      - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0
        with:
          node-version: 22.x
          registry-url: 'https://registry.npmjs.org'
          cache: pnpm
      
      - name: Install
        run: pnpm install

      - name: Build
        env:
          TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
          TURBO_TEAM: ${{ vars.TURBO_TEAM || github.repository_owner }}
          TURBO_CACHE: remote:rw
        run: pnpm build
          
      - run: pnpm dlx pkg-pr-new publish --pnpm ./packages/*
```

--------------------------------------------------------------------------------
/demo/nextjs/components/ui/toggle.tsx:
--------------------------------------------------------------------------------

```typescript
"use client";
import * as TogglePrimitive from "@radix-ui/react-toggle";
import { cva } from "class-variance-authority";

import { cn } from "@/lib/utils";

const toggleVariants = cva(
	"inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors hover:bg-muted hover:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground",
	{
		variants: {
			variant: {
				default: "bg-transparent",
				outline:
					"border border-input bg-transparent shadow-sm hover:bg-accent hover:text-accent-foreground",
			},
			size: {
				default: "h-9 px-3",
				sm: "h-8 px-2",
				lg: "h-10 px-3",
			},
		},
		defaultVariants: {
			variant: "default",
			size: "default",
		},
	},
);

const Toggle = ({ ref, className, variant, size, ...props }) => (
	<TogglePrimitive.Root
		ref={ref}
		className={cn(toggleVariants({ variant, size, className }))}
		{...props}
	/>
);

Toggle.displayName = TogglePrimitive.Root.displayName;

export { Toggle, toggleVariants };

```

--------------------------------------------------------------------------------
/demo/nextjs/components/ui/checkbox.tsx:
--------------------------------------------------------------------------------

```typescript
"use client";

import * as React from "react";
import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
import { CheckIcon } from "lucide-react";

import { cn } from "@/lib/utils";

function Checkbox({
	className,
	...props
}: React.ComponentProps<typeof CheckboxPrimitive.Root>) {
	return (
		<CheckboxPrimitive.Root
			data-slot="checkbox"
			className={cn(
				"peer border-input data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground data-[state=checked]:border-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive size-4 shrink-0 rounded-[4px] border shadow-xs transition-shadow outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50",
				className,
			)}
			{...props}
		>
			<CheckboxPrimitive.Indicator
				data-slot="checkbox-indicator"
				className="flex items-center justify-center text-current transition-none"
			>
				<CheckIcon className="size-3.5" />
			</CheckboxPrimitive.Indicator>
		</CheckboxPrimitive.Root>
	);
}

export { Checkbox };

```

--------------------------------------------------------------------------------
/docs/components/ui/checkbox.tsx:
--------------------------------------------------------------------------------

```typescript
"use client";

import * as React from "react";
import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
import { CheckIcon } from "lucide-react";

import { cn } from "@/lib/utils";

function Checkbox({
	className,
	...props
}: React.ComponentProps<typeof CheckboxPrimitive.Root>) {
	return (
		<CheckboxPrimitive.Root
			data-slot="checkbox"
			className={cn(
				"peer border-input data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground data-[state=checked]:border-primary focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive size-4 shrink-0 rounded-[4px] border shadow-xs transition-shadow outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50",
				className,
			)}
			{...props}
		>
			<CheckboxPrimitive.Indicator
				data-slot="checkbox-indicator"
				className="flex items-center justify-center text-current transition-none"
			>
				<CheckIcon className="size-3.5" />
			</CheckboxPrimitive.Indicator>
		</CheckboxPrimitive.Root>
	);
}

export { Checkbox };

```

--------------------------------------------------------------------------------
/packages/better-auth/src/plugins/device-authorization/schema.ts:
--------------------------------------------------------------------------------

```typescript
import type { BetterAuthPluginDBSchema } from "@better-auth/core/db";
import * as z from "zod";

export const schema = {
	deviceCode: {
		fields: {
			deviceCode: {
				type: "string",
				required: true,
			},
			userCode: {
				type: "string",
				required: true,
			},
			userId: {
				type: "string",
				required: false,
			},
			expiresAt: {
				type: "date",
				required: true,
			},
			status: {
				type: "string",
				required: true,
			},
			lastPolledAt: {
				type: "date",
				required: false,
			},
			pollingInterval: {
				type: "number",
				required: false,
			},
			clientId: {
				type: "string",
				required: false,
			},
			scope: {
				type: "string",
				required: false,
			},
		},
	},
} satisfies BetterAuthPluginDBSchema;

export const deviceCode = z.object({
	id: z.string(),
	deviceCode: z.string(),
	userCode: z.string(),
	userId: z.string().optional(),
	expiresAt: z.date(),
	status: z.string(),
	lastPolledAt: z.date().optional(),
	pollingInterval: z.number().optional(),
	clientId: z.string().optional(),
	scope: z.string().optional(),
});

export type DeviceCode = z.infer<typeof deviceCode>;

```

--------------------------------------------------------------------------------
/demo/nextjs/app/layout.tsx:
--------------------------------------------------------------------------------

```typescript
import "./globals.css";
import { Toaster } from "@/components/ui/sonner";
import { ThemeProvider } from "@/components/theme-provider";
import { GeistMono } from "geist/font/mono";
import { GeistSans } from "geist/font/sans";
import { Wrapper, WrapperWithQuery } from "@/components/wrapper";
import { createMetadata } from "@/lib/metadata";

export const metadata = createMetadata({
	title: {
		template: "%s | Better Auth",
		default: "Better Auth",
	},
	description: "The most comprehensive authentication library for typescript",
	metadataBase: new URL("https://demo.better-auth.com"),
});

export default function RootLayout({
	children,
}: Readonly<{
	children: React.ReactNode;
}>) {
	return (
		<html lang="en" suppressHydrationWarning>
			<head>
				<link rel="icon" href="/favicon/favicon.ico" sizes="any" />
			</head>
			<body className={`${GeistSans.variable} ${GeistMono.variable} font-sans`}>
				<ThemeProvider attribute="class" defaultTheme="dark">
					<Wrapper>
						<WrapperWithQuery>{children}</WrapperWithQuery>
					</Wrapper>
					<Toaster richColors closeButton />
				</ThemeProvider>
			</body>
		</html>
	);
}

```

--------------------------------------------------------------------------------
/packages/better-auth/src/crypto/index.ts:
--------------------------------------------------------------------------------

```typescript
import { createHash } from "@better-auth/utils/hash";
import { xchacha20poly1305 } from "@noble/ciphers/chacha.js";
import {
	bytesToHex,
	hexToBytes,
	utf8ToBytes,
	managedNonce,
} from "@noble/ciphers/utils.js";

export type SymmetricEncryptOptions = {
	key: string;
	data: string;
};

export const symmetricEncrypt = async ({
	key,
	data,
}: SymmetricEncryptOptions) => {
	const keyAsBytes = await createHash("SHA-256").digest(key);
	const dataAsBytes = utf8ToBytes(data);
	const chacha = managedNonce(xchacha20poly1305)(new Uint8Array(keyAsBytes));
	return bytesToHex(chacha.encrypt(dataAsBytes));
};

export type SymmetricDecryptOptions = {
	key: string;
	data: string;
};

export const symmetricDecrypt = async ({
	key,
	data,
}: SymmetricDecryptOptions) => {
	const keyAsBytes = await createHash("SHA-256").digest(key);
	const dataAsBytes = hexToBytes(data);
	const chacha = managedNonce(xchacha20poly1305)(new Uint8Array(keyAsBytes));
	return new TextDecoder().decode(chacha.decrypt(dataAsBytes));
};

export * from "./buffer";
export * from "./hash";
export * from "./jwt";
export * from "./password";
export * from "./random";

```
Page 2/49FirstPrevNextLast