diff --git a/demo/nextjs/.env.exmaple b/demo/nextjs/.env.exmaple
new file mode 100644
index 00000000..cc4427a2
--- /dev/null
+++ b/demo/nextjs/.env.exmaple
@@ -0,0 +1,14 @@
+GOOGLE_CLIENT_SECRET=
+GOOGLE_CLIENT_ID=
+BETTER_AUTH_URL="http://localhost:3000"
+BETTER_AUTH_SECRET=
+TURSO_DATABASE_URL=
+TURSO_AUTH_TOKEN=
+GITHUB_CLIENT_ID=
+GITHUB_CLIENT_SECRET=
+RESEND_API_KEY=
+TEST_EMAIL=
+DISCORD_CLIENT_ID=
+DISCORD_CLIENT_SECRET=
+MICROSOFT_CLIENT_ID=
+MICROSOFT_CLIENT_SECRET=
\ No newline at end of file
diff --git a/demo/nextjs/.gitignore b/demo/nextjs/.gitignore
index b6cd43c6..2fd56990 100644
--- a/demo/nextjs/.gitignore
+++ b/demo/nextjs/.gitignore
@@ -30,7 +30,7 @@ yarn-debug.log*
yarn-error.log*
# env files (can opt-in for commiting if needed)
-.env*
+.env
# vercel
.vercel
diff --git a/dev/bc-fe/hono/.gitignore b/dev/bc-fe/hono/.gitignore
deleted file mode 100644
index 506e4c37..00000000
--- a/dev/bc-fe/hono/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-# deps
-node_modules/
diff --git a/dev/bc-fe/hono/README.md b/dev/bc-fe/hono/README.md
deleted file mode 100644
index 6dd13e7c..00000000
--- a/dev/bc-fe/hono/README.md
+++ /dev/null
@@ -1,11 +0,0 @@
-To install dependencies:
-```sh
-bun install
-```
-
-To run:
-```sh
-bun run dev
-```
-
-open http://localhost:3000
diff --git a/dev/bc-fe/hono/auth.d.ts b/dev/bc-fe/hono/auth.d.ts
deleted file mode 100644
index 0c231982..00000000
--- a/dev/bc-fe/hono/auth.d.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-export type Auth = {
- baseURL: "http://localhost:3000";
- basePath: "/auth";
- database: {
- provider: "sqlite";
- url: "./db.sqlite";
- };
- socialProviders: [
- {
- id: "github";
- },
- ];
- plugins: [
- {
- id: "two-factor";
- endpoints: {};
- },
- {
- id: "organization";
- endpoints: {};
- },
- ];
-};
diff --git a/dev/bc-fe/hono/db.sqlite b/dev/bc-fe/hono/db.sqlite
deleted file mode 100644
index 6474cce8..00000000
Binary files a/dev/bc-fe/hono/db.sqlite and /dev/null differ
diff --git a/dev/bc-fe/hono/package.json b/dev/bc-fe/hono/package.json
deleted file mode 100644
index 7ce2d283..00000000
--- a/dev/bc-fe/hono/package.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "name": "@dev/hono",
- "scripts": {
- "dev": "tsx -r dotenv/config src/index.ts",
- "auth": "pnpm better-auth"
- },
- "dependencies": {
- "@hono/node-server": "^1.12.2",
- "better-auth": "workspace:*",
- "@types/better-sqlite3": "^7.6.11",
- "better-sqlite3": "^11.3.0",
- "dotenv": "^16.4.5",
- "hono": "^4.5.9",
- "tsx": "^4.19.0"
- },
- "devDependencies": {
- "@types/bun": "latest"
- }
-}
\ No newline at end of file
diff --git a/dev/bc-fe/hono/src/auth.ts b/dev/bc-fe/hono/src/auth.ts
deleted file mode 100644
index 0ccd5cd2..00000000
--- a/dev/bc-fe/hono/src/auth.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-import Database from "better-sqlite3";
-import { betterAuth } from "better-auth";
-import { organization, twoFactor, username } from "better-auth/plugins";
-
-export const auth = betterAuth({
- baseURL: "http://localhost:3000",
- basePath: "/auth",
- database: new Database("./db.sqlite"),
- socialProviders: {
- github: {
- clientId: process.env.GITHUB_CLIENT_ID || "",
- clientSecret: process.env.GITHUB_CLIENT_SECRET || "",
- },
- },
- plugins: [
- twoFactor({
- issuer: "BetterAuth",
- }),
- organization(),
- username(),
- ],
- emailAndPassword: {
- enabled: true,
- },
-});
diff --git a/dev/bc-fe/hono/src/index.ts b/dev/bc-fe/hono/src/index.ts
deleted file mode 100644
index 94938f49..00000000
--- a/dev/bc-fe/hono/src/index.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-import { Hono } from "hono";
-import { auth } from "./auth";
-import { serve } from "@hono/node-server";
-import { cors } from "hono/cors";
-
-const app = new Hono();
-
-app.use(
- "/api/auth/**",
- cors({
- origin: "http://localhost:5173",
- allowHeaders: ["Content-Type", "Authorization"],
- allowMethods: ["POST", "GET", "OPTIONS"],
- exposeHeaders: ["Content-Length"],
- maxAge: 600,
- credentials: true,
- }),
-);
-
-app.on(["POST", "GET"], "/api/auth/**", (c) => {
- return auth.handler(c.req.raw);
-});
-
-serve(app);
diff --git a/dev/bc-fe/hono/tsconfig.json b/dev/bc-fe/hono/tsconfig.json
deleted file mode 100644
index 4a655351..00000000
--- a/dev/bc-fe/hono/tsconfig.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "compilerOptions": {
- "strict": true,
- "jsx": "react-jsx",
- "jsxImportSource": "hono/jsx",
- "module": "Preserve"
- }
-}
diff --git a/dev/bc-fe/react/.gitignore b/dev/bc-fe/react/.gitignore
deleted file mode 100644
index a547bf36..00000000
--- a/dev/bc-fe/react/.gitignore
+++ /dev/null
@@ -1,24 +0,0 @@
-# Logs
-logs
-*.log
-npm-debug.log*
-yarn-debug.log*
-yarn-error.log*
-pnpm-debug.log*
-lerna-debug.log*
-
-node_modules
-dist
-dist-ssr
-*.local
-
-# Editor directories and files
-.vscode/*
-!.vscode/extensions.json
-.idea
-.DS_Store
-*.suo
-*.ntvs*
-*.njsproj
-*.sln
-*.sw?
diff --git a/dev/bc-fe/react/README.md b/dev/bc-fe/react/README.md
deleted file mode 100644
index 74872fd4..00000000
--- a/dev/bc-fe/react/README.md
+++ /dev/null
@@ -1,50 +0,0 @@
-# React + TypeScript + Vite
-
-This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
-
-Currently, two official plugins are available:
-
-- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react/README.md) uses [Babel](https://babeljs.io/) for Fast Refresh
-- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh
-
-## Expanding the ESLint configuration
-
-If you are developing a production application, we recommend updating the configuration to enable type aware lint rules:
-
-- Configure the top-level `parserOptions` property like this:
-
-```js
-export default tseslint.config({
- languageOptions: {
- // other options...
- parserOptions: {
- project: ['./tsconfig.node.json', './tsconfig.app.json'],
- tsconfigRootDir: import.meta.dirname,
- },
- },
-})
-```
-
-- Replace `tseslint.configs.recommended` to `tseslint.configs.recommendedTypeChecked` or `tseslint.configs.strictTypeChecked`
-- Optionally add `...tseslint.configs.stylisticTypeChecked`
-- Install [eslint-plugin-react](https://github.com/jsx-eslint/eslint-plugin-react) and update the config:
-
-```js
-// eslint.config.js
-import react from 'eslint-plugin-react'
-
-export default tseslint.config({
- // Set the react version
- settings: { react: { version: '18.3' } },
- plugins: {
- // Add the react plugin
- react,
- },
- rules: {
- // other rules...
- // Enable its recommended rules
- ...react.configs.recommended.rules,
- ...react.configs['jsx-runtime'].rules,
- },
-})
-```
diff --git a/dev/bc-fe/react/eslint.config.js b/dev/bc-fe/react/eslint.config.js
deleted file mode 100644
index 34a820fe..00000000
--- a/dev/bc-fe/react/eslint.config.js
+++ /dev/null
@@ -1,28 +0,0 @@
-import js from "@eslint/js";
-import reactHooks from "eslint-plugin-react-hooks";
-import reactRefresh from "eslint-plugin-react-refresh";
-import globals from "globals";
-import tseslint from "typescript-eslint";
-
-export default tseslint.config(
- { ignores: ["dist"] },
- {
- extends: [js.configs.recommended, ...tseslint.configs.recommended],
- files: ["**/*.{ts,tsx}"],
- languageOptions: {
- ecmaVersion: 2020,
- globals: globals.browser,
- },
- plugins: {
- "react-hooks": reactHooks,
- "react-refresh": reactRefresh,
- },
- rules: {
- ...reactHooks.configs.recommended.rules,
- "react-refresh/only-export-components": [
- "warn",
- { allowConstantExport: true },
- ],
- },
- },
-);
diff --git a/dev/bc-fe/react/index.html b/dev/bc-fe/react/index.html
deleted file mode 100644
index e4b78eae..00000000
--- a/dev/bc-fe/react/index.html
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
-
-
- Vite + React + TS
-
-
-
-
-
-
diff --git a/dev/bc-fe/react/package.json b/dev/bc-fe/react/package.json
deleted file mode 100644
index cd0d6609..00000000
--- a/dev/bc-fe/react/package.json
+++ /dev/null
@@ -1,30 +0,0 @@
-{
- "name": "@dev/react",
- "private": true,
- "version": "0.0.0",
- "type": "module",
- "scripts": {
- "dev": "vite",
- "build": "tsc -b && vite build",
- "lint": "eslint .",
- "preview": "vite preview"
- },
- "dependencies": {
- "better-auth": "workspace:^",
- "react": "^18.3.1",
- "react-dom": "^18.3.1"
- },
- "devDependencies": {
- "@eslint/js": "^9.9.0",
- "@types/react": "^18.3.3",
- "@types/react-dom": "^18.3.0",
- "@vitejs/plugin-react": "^4.3.1",
- "eslint": "^9.9.0",
- "eslint-plugin-react-hooks": "^5.1.0-rc.0",
- "eslint-plugin-react-refresh": "^0.4.9",
- "globals": "^15.9.0",
- "typescript": "^5.5.3",
- "typescript-eslint": "^8.0.1",
- "vite": "^5.4.1"
- }
-}
\ No newline at end of file
diff --git a/dev/bc-fe/react/public/vite.svg b/dev/bc-fe/react/public/vite.svg
deleted file mode 100644
index e7b8dfb1..00000000
--- a/dev/bc-fe/react/public/vite.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/dev/bc-fe/react/src/App.css b/dev/bc-fe/react/src/App.css
deleted file mode 100644
index b9d355df..00000000
--- a/dev/bc-fe/react/src/App.css
+++ /dev/null
@@ -1,42 +0,0 @@
-#root {
- max-width: 1280px;
- margin: 0 auto;
- padding: 2rem;
- text-align: center;
-}
-
-.logo {
- height: 6em;
- padding: 1.5em;
- will-change: filter;
- transition: filter 300ms;
-}
-.logo:hover {
- filter: drop-shadow(0 0 2em #646cffaa);
-}
-.logo.react:hover {
- filter: drop-shadow(0 0 2em #61dafbaa);
-}
-
-@keyframes logo-spin {
- from {
- transform: rotate(0deg);
- }
- to {
- transform: rotate(360deg);
- }
-}
-
-@media (prefers-reduced-motion: no-preference) {
- a:nth-of-type(2) .logo {
- animation: logo-spin infinite 20s linear;
- }
-}
-
-.card {
- padding: 2em;
-}
-
-.read-the-docs {
- color: #888;
-}
diff --git a/dev/bc-fe/react/src/App.tsx b/dev/bc-fe/react/src/App.tsx
deleted file mode 100644
index 6a1020c5..00000000
--- a/dev/bc-fe/react/src/App.tsx
+++ /dev/null
@@ -1,204 +0,0 @@
-import { useState } from "react";
-import "./App.css";
-import { auth } from "./lib/auth";
-
-function App() {
- const session = auth.useSession();
- return (
- <>
- Better Auth
-
- {session ? (
-
-
{session.user.name}
-
{session.user.username}
-
{session.user.email}
-
- {session.user.twoFactorEnabled ? (
-
- ) : (
-
- )}
-
-
-
-
- ) : (
-
-
-
-
-
- )}
-
- >
- );
-}
-
-export default App;
-
-function SignUp() {
- const [email, setEmail] = useState("");
- const [name, setName] = useState("");
- const [username, setUsername] = useState("");
- const [password, setPassword] = useState("");
- return (
-
- setEmail(e.target.value)}
- />
- setName(e.target.value)}
- />
- setUsername(e.target.value)}
- />
- setPassword(e.target.value)}
- />
-
-
- );
-}
-
-function SignIn() {
- const [email, setEmail] = useState("");
- const [password, setPassword] = useState("");
- return (
-
- setEmail(e.target.value)}
- />
-
- setPassword(e.target.value)}
- />
-
-
- );
-}
diff --git a/dev/bc-fe/react/src/assets/react.svg b/dev/bc-fe/react/src/assets/react.svg
deleted file mode 100644
index 6c87de9b..00000000
--- a/dev/bc-fe/react/src/assets/react.svg
+++ /dev/null
@@ -1 +0,0 @@
-
\ No newline at end of file
diff --git a/dev/bc-fe/react/src/index.css b/dev/bc-fe/react/src/index.css
deleted file mode 100644
index 6119ad9a..00000000
--- a/dev/bc-fe/react/src/index.css
+++ /dev/null
@@ -1,68 +0,0 @@
-:root {
- font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
- line-height: 1.5;
- font-weight: 400;
-
- color-scheme: light dark;
- color: rgba(255, 255, 255, 0.87);
- background-color: #242424;
-
- font-synthesis: none;
- text-rendering: optimizeLegibility;
- -webkit-font-smoothing: antialiased;
- -moz-osx-font-smoothing: grayscale;
-}
-
-a {
- font-weight: 500;
- color: #646cff;
- text-decoration: inherit;
-}
-a:hover {
- color: #535bf2;
-}
-
-body {
- margin: 0;
- display: flex;
- place-items: center;
- min-width: 320px;
- min-height: 100vh;
-}
-
-h1 {
- font-size: 3.2em;
- line-height: 1.1;
-}
-
-button {
- border-radius: 8px;
- border: 1px solid transparent;
- padding: 0.6em 1.2em;
- font-size: 1em;
- font-weight: 500;
- font-family: inherit;
- background-color: #1a1a1a;
- cursor: pointer;
- transition: border-color 0.25s;
-}
-button:hover {
- border-color: #646cff;
-}
-button:focus,
-button:focus-visible {
- outline: 4px auto -webkit-focus-ring-color;
-}
-
-@media (prefers-color-scheme: light) {
- :root {
- color: #213547;
- background-color: #ffffff;
- }
- a:hover {
- color: #747bff;
- }
- button {
- background-color: #f9f9f9;
- }
-}
diff --git a/dev/bc-fe/react/src/lib/auth.ts b/dev/bc-fe/react/src/lib/auth.ts
deleted file mode 100644
index e89bb140..00000000
--- a/dev/bc-fe/react/src/lib/auth.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-import { createAuthClient } from "better-auth/react";
-import { twoFactorClient, usernameClient } from "better-auth/client/plugins";
-
-export const auth = createAuthClient({
- baseURL: "http://localhost:3000/api/auth",
- plugins: [
- twoFactorClient({
- twoFactorPage: "/two-factor",
- }),
- usernameClient(),
- ],
-});
diff --git a/dev/bc-fe/react/src/main.tsx b/dev/bc-fe/react/src/main.tsx
deleted file mode 100644
index f84bc47d..00000000
--- a/dev/bc-fe/react/src/main.tsx
+++ /dev/null
@@ -1,10 +0,0 @@
-import { StrictMode } from "react";
-import { createRoot } from "react-dom/client";
-import App from "./App.tsx";
-import "./index.css";
-
-createRoot(document.getElementById("root")!).render(
-
-
- ,
-);
diff --git a/dev/bc-fe/react/src/vite-env.d.ts b/dev/bc-fe/react/src/vite-env.d.ts
deleted file mode 100644
index 11f02fe2..00000000
--- a/dev/bc-fe/react/src/vite-env.d.ts
+++ /dev/null
@@ -1 +0,0 @@
-///
diff --git a/dev/bc-fe/react/tsconfig.app.json b/dev/bc-fe/react/tsconfig.app.json
deleted file mode 100644
index b896f924..00000000
--- a/dev/bc-fe/react/tsconfig.app.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "compilerOptions": {
- "target": "ES2020",
- "useDefineForClassFields": true,
- "lib": ["ES2020", "DOM", "DOM.Iterable"],
- "module": "ESNext",
- "skipLibCheck": true,
- "moduleResolution": "bundler",
- "allowImportingTsExtensions": true,
- "isolatedModules": true,
- "moduleDetection": "force",
- "noEmit": true,
- "jsx": "react-jsx",
- "strict": true,
- "noUnusedLocals": true,
- "noUnusedParameters": true,
- "noFallthroughCasesInSwitch": true
- },
- "include": ["src"]
-}
diff --git a/dev/bc-fe/react/tsconfig.json b/dev/bc-fe/react/tsconfig.json
deleted file mode 100644
index fb124188..00000000
--- a/dev/bc-fe/react/tsconfig.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "files": [],
- "references": [
- { "path": "./tsconfig.app.json" },
- { "path": "./tsconfig.node.json" }
- ]
-}
diff --git a/dev/bc-fe/react/tsconfig.node.json b/dev/bc-fe/react/tsconfig.node.json
deleted file mode 100644
index da16d82d..00000000
--- a/dev/bc-fe/react/tsconfig.node.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "compilerOptions": {
- "target": "ES2022",
- "lib": ["ES2023"],
- "module": "ESNext",
- "skipLibCheck": true,
- "moduleResolution": "bundler",
- "allowImportingTsExtensions": true,
- "isolatedModules": true,
- "moduleDetection": "force",
- "noEmit": true,
- "strict": true,
- "noUnusedLocals": true,
- "noUnusedParameters": true,
- "noFallthroughCasesInSwitch": true
- },
- "include": ["vite.config.ts"]
-}
diff --git a/dev/bc-fe/react/vite.config.ts b/dev/bc-fe/react/vite.config.ts
deleted file mode 100644
index e29a791f..00000000
--- a/dev/bc-fe/react/vite.config.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-import react from "@vitejs/plugin-react";
-import { defineConfig } from "vite";
-
-// https://vitejs.dev/config/
-export default defineConfig({
- plugins: [react()],
-});
diff --git a/dev/express/.gitignore b/dev/express/.gitignore
deleted file mode 100644
index 9b1ee42e..00000000
--- a/dev/express/.gitignore
+++ /dev/null
@@ -1,175 +0,0 @@
-# Based on https://raw.githubusercontent.com/github/gitignore/main/Node.gitignore
-
-# Logs
-
-logs
-_.log
-npm-debug.log_
-yarn-debug.log*
-yarn-error.log*
-lerna-debug.log*
-.pnpm-debug.log*
-
-# Caches
-
-.cache
-
-# Diagnostic reports (https://nodejs.org/api/report.html)
-
-report.[0-9]_.[0-9]_.[0-9]_.[0-9]_.json
-
-# Runtime data
-
-pids
-_.pid
-_.seed
-*.pid.lock
-
-# Directory for instrumented libs generated by jscoverage/JSCover
-
-lib-cov
-
-# Coverage directory used by tools like istanbul
-
-coverage
-*.lcov
-
-# nyc test coverage
-
-.nyc_output
-
-# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
-
-.grunt
-
-# Bower dependency directory (https://bower.io/)
-
-bower_components
-
-# node-waf configuration
-
-.lock-wscript
-
-# Compiled binary addons (https://nodejs.org/api/addons.html)
-
-build/Release
-
-# Dependency directories
-
-node_modules/
-jspm_packages/
-
-# Snowpack dependency directory (https://snowpack.dev/)
-
-web_modules/
-
-# TypeScript cache
-
-*.tsbuildinfo
-
-# Optional npm cache directory
-
-.npm
-
-# Optional eslint cache
-
-.eslintcache
-
-# Optional stylelint cache
-
-.stylelintcache
-
-# Microbundle cache
-
-.rpt2_cache/
-.rts2_cache_cjs/
-.rts2_cache_es/
-.rts2_cache_umd/
-
-# Optional REPL history
-
-.node_repl_history
-
-# Output of 'npm pack'
-
-*.tgz
-
-# Yarn Integrity file
-
-.yarn-integrity
-
-# dotenv environment variable files
-
-.env
-.env.development.local
-.env.test.local
-.env.production.local
-.env.local
-
-# parcel-bundler cache (https://parceljs.org/)
-
-.parcel-cache
-
-# Next.js build output
-
-.next
-out
-
-# Nuxt.js build / generate output
-
-.nuxt
-dist
-
-# Gatsby files
-
-# Comment in the public line in if your project uses Gatsby and not Next.js
-
-# https://nextjs.org/blog/next-9-1#public-directory-support
-
-# public
-
-# vuepress build output
-
-.vuepress/dist
-
-# vuepress v2.x temp and cache directory
-
-.temp
-
-# Docusaurus cache and generated files
-
-.docusaurus
-
-# Serverless directories
-
-.serverless/
-
-# FuseBox cache
-
-.fusebox/
-
-# DynamoDB Local files
-
-.dynamodb/
-
-# TernJS port file
-
-.tern-port
-
-# Stores VSCode versions used for testing VSCode extensions
-
-.vscode-test
-
-# yarn v2
-
-.yarn/cache
-.yarn/unplugged
-.yarn/build-state.yml
-.yarn/install-state.gz
-.pnp.*
-
-# IntelliJ based IDEs
-.idea
-
-# Finder (MacOS) folder config
-.DS_Store
diff --git a/dev/express/README.md b/dev/express/README.md
deleted file mode 100644
index bbb379a8..00000000
--- a/dev/express/README.md
+++ /dev/null
@@ -1,15 +0,0 @@
-# express
-
-To install dependencies:
-
-```bash
-bun install
-```
-
-To run:
-
-```bash
-bun run index.ts
-```
-
-This project was created using `bun init` in bun v1.1.27. [Bun](https://bun.sh) is a fast all-in-one JavaScript runtime.
diff --git a/dev/express/auth.ts b/dev/express/auth.ts
deleted file mode 100644
index 5f70fe73..00000000
--- a/dev/express/auth.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-import Database from "better-sqlite3";
-import { betterAuth } from "better-auth";
-
-export const auth = betterAuth({
- database: new Database("better_auth.db"),
-});
diff --git a/dev/express/index.ts b/dev/express/index.ts
deleted file mode 100644
index 6bbf6fcb..00000000
--- a/dev/express/index.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-import express from "express";
-import { toNodeHandler } from "better-auth/node";
-import { auth } from "./auth";
-
-const app = express();
-const port = 3005;
-
-app.get("/api/auth/*", toNodeHandler(auth));
-
-app.listen(port, () => {
- console.log(`Example app listening on port ${port}`);
-});
diff --git a/dev/express/package.json b/dev/express/package.json
deleted file mode 100644
index ecaaec3c..00000000
--- a/dev/express/package.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "name": "@better-auth/dev-express",
- "private": true,
- "module": "index.ts",
- "type": "module",
- "devDependencies": {
- "@types/bun": "latest",
- "@types/express": "^4.17.21"
- },
- "peerDependencies": {
- "typescript": "^5.0.0",
- "@types/better-sqlite3": "^7.6.11",
- "better-sqlite3": "^11.3.0"
- },
- "dependencies": {
- "better-auth": "workspace:*",
- "express": "^4.21.0",
- "tsx": "^4.19.0"
- }
-}
\ No newline at end of file
diff --git a/dev/express/tsconfig.json b/dev/express/tsconfig.json
deleted file mode 100644
index e0abf845..00000000
--- a/dev/express/tsconfig.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "compilerOptions": {
- "esModuleInterop": true,
- "skipLibCheck": true,
- "target": "es2022",
- "allowJs": true,
- "resolveJsonModule": true,
- "moduleDetection": "force",
- "isolatedModules": true,
- "verbatimModuleSyntax": true,
- "strict": true,
- "moduleResolution": "Bundler",
- "outDir": "dist",
- "sourceMap": true,
- "lib": ["es2022"]
- }
-}
diff --git a/dev/schema-gen/auth.ts b/dev/schema-gen/auth.ts
deleted file mode 100644
index f2ab4bda..00000000
--- a/dev/schema-gen/auth.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-import { betterAuth } from "better-auth";
-import { prismaAdapter } from "better-auth/adapters/prisma";
-import { PrismaClient } from "@prisma/client";
-
-const prisma = new PrismaClient();
-
-export const auth = betterAuth({
- database: prismaAdapter(prisma, {
- provider: "sqlite",
- }),
- provider: "sqlite",
-});
diff --git a/dev/schema-gen/drizzle-auth.ts b/dev/schema-gen/drizzle-auth.ts
deleted file mode 100644
index c85b729d..00000000
--- a/dev/schema-gen/drizzle-auth.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-import { betterAuth } from "better-auth";
-import { drizzleAdapter } from "better-auth/adapters/drizzle";
-import { db } from "./drizzle";
-
-export const auth = betterAuth({
- database: drizzleAdapter(db, {
- provider: "pg",
- }),
-});
diff --git a/dev/schema-gen/drizzle.ts b/dev/schema-gen/drizzle.ts
deleted file mode 100644
index a770e1fd..00000000
--- a/dev/schema-gen/drizzle.ts
+++ /dev/null
@@ -1,22 +0,0 @@
-import { drizzle } from "drizzle-orm/postgres-js";
-import {
- pgTable,
- serial,
- varchar,
- text,
- timestamp,
- integer,
- boolean,
-} from "drizzle-orm/pg-core";
-import postgres from "postgres";
-
-const table = pgTable("test", {
- id: text("id").primaryKey(),
-});
-
-const schema = {
- table,
-};
-
-export const client = postgres(process.env.POSTGRES_URL || "");
-export const db = drizzle(client, { schema });
diff --git a/dev/schema-gen/index.ts b/dev/schema-gen/index.ts
deleted file mode 100644
index e69de29b..00000000
diff --git a/dev/schema-gen/package.json b/dev/schema-gen/package.json
deleted file mode 100644
index b35ad940..00000000
--- a/dev/schema-gen/package.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "name": "prisma-dev",
- "dependencies": {
- "@prisma/client": "^5.19.1",
- "better-auth": "workspace:*",
- "drizzle-orm": "^0.33.0",
- "postgres": "^3.4.4",
- "prisma": "^5.19.1"
- }
-}
\ No newline at end of file
diff --git a/dev/schema-gen/prisma/schema.prisma b/dev/schema-gen/prisma/schema.prisma
deleted file mode 100644
index 197dc594..00000000
--- a/dev/schema-gen/prisma/schema.prisma
+++ /dev/null
@@ -1,49 +0,0 @@
-
-generator client {
- provider = "prisma-client-js"
-}
-
-datasource db {
- provider = "sqlite"
- url = "file:.db/dev.db"
-}
-
-model Test {
- id String @id @default(cuid())
-}
-
-model user {
- id String @id
- name String
- email String
- emailVerified Boolean
- image String?
- createdAt DateTime
- updatedAt DateTime
- session session[]
- account account[]
-
- @@unique([email])
-}
-
-model session {
- id String @id
- expiresAt DateTime
- ipAddress String?
- userAgent String?
- userId String
- User user @relation(fields: [userId], references: [id], onDelete: Cascade)
-}
-
-model account {
- id String @id
- accountId String
- providerId String
- userId String
- User user @relation(fields: [userId], references: [id], onDelete: Cascade)
- accessToken String?
- refreshToken String?
- idToken String?
- expiresAt DateTime?
- password String?
-}
diff --git a/dev/schema-gen/schema.ts b/dev/schema-gen/schema.ts
deleted file mode 100644
index f02132f8..00000000
--- a/dev/schema-gen/schema.ts
+++ /dev/null
@@ -1,41 +0,0 @@
-import {
- pgTable,
- text,
- integer,
- timestamp,
- boolean,
-} from "drizzle-orm/pg-core";
-
-export const user = pgTable("user", {
- id: text("id").primaryKey(),
- name: text("name").notNull(),
- email: text("email").notNull().unique(),
- emailVerified: boolean("emailVerified").notNull(),
- image: text("image"),
- createdAt: timestamp("createdAt").notNull(),
- updatedAt: timestamp("updatedAt").notNull(),
-});
-
-export const session = pgTable("session", {
- id: text("id").primaryKey(),
- expiresAt: timestamp("expiresAt").notNull(),
- ipAddress: text("ipAddress"),
- userAgent: text("userAgent"),
- userId: text("userId")
- .notNull()
- .references(() => user.id),
-});
-
-export const account = pgTable("account", {
- id: text("id").primaryKey(),
- accountId: text("accountId").notNull(),
- providerId: text("providerId").notNull(),
- userId: text("userId")
- .notNull()
- .references(() => user.id),
- accessToken: text("accessToken"),
- refreshToken: text("refreshToken"),
- idToken: text("idToken"),
- expiresAt: timestamp("expiresAt"),
- password: text("password"),
-});
diff --git a/examples/astro-example/.env.example b/examples/astro-example/.env.example
new file mode 100644
index 00000000..9abb10ae
--- /dev/null
+++ b/examples/astro-example/.env.example
@@ -0,0 +1,3 @@
+GOOGLE_CLIENT_SECRET=
+GOOGLE_CLIENT_ID=
+RESEND_API_KEY=
\ No newline at end of file
diff --git a/examples/nextjs-example/.env.exmaple b/examples/nextjs-example/.env.exmaple
new file mode 100644
index 00000000..cc4427a2
--- /dev/null
+++ b/examples/nextjs-example/.env.exmaple
@@ -0,0 +1,14 @@
+GOOGLE_CLIENT_SECRET=
+GOOGLE_CLIENT_ID=
+BETTER_AUTH_URL="http://localhost:3000"
+BETTER_AUTH_SECRET=
+TURSO_DATABASE_URL=
+TURSO_AUTH_TOKEN=
+GITHUB_CLIENT_ID=
+GITHUB_CLIENT_SECRET=
+RESEND_API_KEY=
+TEST_EMAIL=
+DISCORD_CLIENT_ID=
+DISCORD_CLIENT_SECRET=
+MICROSOFT_CLIENT_ID=
+MICROSOFT_CLIENT_SECRET=
\ No newline at end of file
diff --git a/examples/nextjs-example/.gitignore b/examples/nextjs-example/.gitignore
index 26b002aa..2fd56990 100644
--- a/examples/nextjs-example/.gitignore
+++ b/examples/nextjs-example/.gitignore
@@ -30,7 +30,7 @@ yarn-debug.log*
yarn-error.log*
# env files (can opt-in for commiting if needed)
-.env*
+.env
# vercel
.vercel
@@ -38,3 +38,5 @@ yarn-error.log*
# typescript
*.tsbuildinfo
next-env.d.ts
+
+certificates
\ No newline at end of file
diff --git a/examples/nextjs-example/README.md b/examples/nextjs-example/README.md
index e88e5d16..e215bc4c 100644
--- a/examples/nextjs-example/README.md
+++ b/examples/nextjs-example/README.md
@@ -1,19 +1,36 @@
-# Better Auth Next js example
+This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
-This is an example of how to use Better Auth with Next.
+## Getting Started
-**Implements the following features:**
-Email & Password . Social Sign-in . Passkeys . Email Verification . Password Reset . Two Factor Authentication . Profile Update . Session Management . Organization, Members and Roles
+First, run the development server:
+```bash
+npm run dev
+# or
+yarn dev
+# or
+pnpm dev
+# or
+bun dev
+```
+Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
-## How to run
+You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
-1. Clone the code sandbox (or the repo) and open it in your code editor
-2. Move .env.example to .env and provide necessary variables
-3. Run the following commands
- ```bash
- pnpm install
- pnpm dev
- ```
-4. Open the browser and navigate to `http://localhost:3000`
\ No newline at end of file
+This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
+
+## Learn More
+
+To learn more about Next.js, take a look at the following resources:
+
+- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
+- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
+
+You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
+
+## Deploy on Vercel
+
+The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
+
+Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
diff --git a/examples/nextjs-example/app/(auth)/forget-password/page.tsx b/examples/nextjs-example/app/(auth)/forget-password/page.tsx
index 06c91dfe..d16a6f5c 100644
--- a/examples/nextjs-example/app/(auth)/forget-password/page.tsx
+++ b/examples/nextjs-example/app/(auth)/forget-password/page.tsx
@@ -28,13 +28,11 @@ export default function Component() {
setIsSubmitting(true);
setError("");
- // Simulate API call
try {
const res = await client.forgetPassword({
email,
redirectTo: "/reset-password",
});
- // If the API call is successful, set isSubmitted to true
setIsSubmitted(true);
} catch (err) {
setError("An error occurred. Please try again.");
diff --git a/examples/nextjs-example/app/(auth)/reset-password/page.tsx b/examples/nextjs-example/app/(auth)/reset-password/page.tsx
index 365e8545..7a8751ab 100644
--- a/examples/nextjs-example/app/(auth)/reset-password/page.tsx
+++ b/examples/nextjs-example/app/(auth)/reset-password/page.tsx
@@ -18,16 +18,11 @@ import { useRouter } from "next/navigation";
import { useState } from "react";
import { toast } from "sonner";
-export default function ResetPassword({
- params,
-}: {
- params: { token: string };
-}) {
+export default function ResetPassword() {
const [password, setPassword] = useState("");
const [confirmPassword, setConfirmPassword] = useState("");
const [isSubmitting, setIsSubmitting] = useState(false);
const [error, setError] = useState("");
- const token = params.token;
const router = useRouter();
async function handleSubmit(e: React.FormEvent) {
e.preventDefault();
diff --git a/examples/nextjs-example/app/(auth)/two-factor/page.tsx b/examples/nextjs-example/app/(auth)/two-factor/page.tsx
index fbb3ac42..130e1157 100644
--- a/examples/nextjs-example/app/(auth)/two-factor/page.tsx
+++ b/examples/nextjs-example/app/(auth)/two-factor/page.tsx
@@ -32,7 +32,7 @@ export default function Component() {
code: totpCode,
})
.then((res) => {
- if (res.data?.status) {
+ if (res.data?.session) {
setSuccess(true);
setError("");
} else {
diff --git a/examples/nextjs-example/app/accept-invitation/[id]/page.tsx b/examples/nextjs-example/app/accept-invitation/[id]/page.tsx
index b2a01478..c98f0ade 100644
--- a/examples/nextjs-example/app/accept-invitation/[id]/page.tsx
+++ b/examples/nextjs-example/app/accept-invitation/[id]/page.tsx
@@ -11,19 +11,15 @@ import {
} from "@/components/ui/card";
import { CheckIcon, XIcon } from "lucide-react";
import { useEffect, useState } from "react";
-import { useRouter } from "next/navigation";
+import { useParams, useRouter } from "next/navigation";
import { Skeleton } from "@/components/ui/skeleton";
import { client, organization } from "@/lib/auth-client";
import { InvitationError } from "./invitation-error";
-import { Invitation } from "@/lib/auth-types";
-export default function InvitationPage({
- params,
-}: {
- params: {
+export default function InvitationPage() {
+ const params = useParams<{
id: string;
- };
-}) {
+ }>();
const router = useRouter();
const [invitationStatus, setInvitationStatus] = useState<
"pending" | "accepted" | "rejected"
diff --git a/examples/nextjs-example/app/admin/page.tsx b/examples/nextjs-example/app/admin/page.tsx
new file mode 100644
index 00000000..d8b645df
--- /dev/null
+++ b/examples/nextjs-example/app/admin/page.tsx
@@ -0,0 +1,460 @@
+"use client";
+
+import { useState } from "react";
+import { Button } from "@/components/ui/button";
+import { Input } from "@/components/ui/input";
+import { Label } from "@/components/ui/label";
+import {
+ Select,
+ SelectContent,
+ SelectItem,
+ SelectTrigger,
+ SelectValue,
+} from "@/components/ui/select";
+import {
+ Table,
+ TableBody,
+ TableCell,
+ TableHead,
+ TableHeader,
+ TableRow,
+} from "@/components/ui/table";
+import { toast, Toaster } from "sonner";
+import { client } from "@/lib/auth-client";
+import { useQuery, useQueryClient } from "@tanstack/react-query";
+import { useRouter } from "next/navigation";
+import {
+ Loader2,
+ Plus,
+ Trash,
+ RefreshCw,
+ UserCircle,
+ Calendar as CalendarIcon,
+} from "lucide-react";
+import {
+ Dialog,
+ DialogContent,
+ DialogHeader,
+ DialogTitle,
+ DialogTrigger,
+} from "@/components/ui/dialog";
+import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
+import { Calendar } from "@/components/ui/calendar";
+import {
+ Popover,
+ PopoverContent,
+ PopoverTrigger,
+} from "@/components/ui/popover";
+import { format } from "date-fns";
+import { cn } from "@/lib/utils";
+import { Badge } from "@/components/ui/badge";
+
+type User = {
+ id: string;
+ email: string;
+ name: string;
+ role: "admin" | "user";
+};
+
+export default function AdminDashboard() {
+ const queryClient = useQueryClient();
+ const router = useRouter();
+ const [isDialogOpen, setIsDialogOpen] = useState(false);
+ const [newUser, setNewUser] = useState({
+ email: "",
+ password: "",
+ name: "",
+ role: "user" as const,
+ });
+ const [isLoading, setIsLoading] = useState();
+ const [isBanDialogOpen, setIsBanDialogOpen] = useState(false);
+ const [banForm, setBanForm] = useState({
+ userId: "",
+ reason: "",
+ expirationDate: undefined as Date | undefined,
+ });
+
+ const { data: users, isLoading: isUsersLoading } = useQuery({
+ queryKey: ["users"],
+ queryFn: () =>
+ client.admin
+ .listUsers({
+ query: {
+ limit: 10,
+ sortBy: "createdAt",
+ sortDirection: "desc",
+ },
+ })
+ .then((res) => res.data?.users ?? []),
+ });
+
+ const handleCreateUser = async (e: React.FormEvent) => {
+ e.preventDefault();
+ setIsLoading("create");
+ try {
+ await client.admin.createUser({
+ email: newUser.email,
+ password: newUser.password,
+ name: newUser.name,
+ role: newUser.role,
+ });
+ toast.success("User created successfully");
+ setNewUser({ email: "", password: "", name: "", role: "user" });
+ setIsDialogOpen(false);
+ queryClient.invalidateQueries({
+ queryKey: ["users"],
+ });
+ } catch (error: any) {
+ toast.error(error.message || "Failed to create user");
+ } finally {
+ setIsLoading(undefined);
+ }
+ };
+
+ const handleDeleteUser = async (id: string) => {
+ setIsLoading(`delete-${id}`);
+ try {
+ await client.admin.removeUser({ userId: id });
+ toast.success("User deleted successfully");
+ queryClient.invalidateQueries({
+ queryKey: ["users"],
+ });
+ } catch (error: any) {
+ toast.error(error.message || "Failed to delete user");
+ } finally {
+ setIsLoading(undefined);
+ }
+ };
+
+ const handleRevokeSessions = async (id: string) => {
+ setIsLoading(`revoke-${id}`);
+ try {
+ await client.admin.revokeUserSessions({ userId: id });
+ toast.success("Sessions revoked for user");
+ } catch (error: any) {
+ toast.error(error.message || "Failed to revoke sessions");
+ } finally {
+ setIsLoading(undefined);
+ }
+ };
+
+ const handleImpersonateUser = async (id: string) => {
+ setIsLoading(`impersonate-${id}`);
+ try {
+ await client.admin.impersonateUser({ userId: id });
+ toast.success("Impersonated user");
+ router.push("/dashboard");
+ } catch (error: any) {
+ toast.error(error.message || "Failed to impersonate user");
+ } finally {
+ setIsLoading(undefined);
+ }
+ };
+
+ const handleBanUser = async (e: React.FormEvent) => {
+ e.preventDefault();
+ setIsLoading(`ban-${banForm.userId}`);
+ try {
+ if (!banForm.expirationDate) {
+ throw new Error("Expiration date is required");
+ }
+ await client.admin.banUser({
+ userId: banForm.userId,
+ banReason: banForm.reason,
+ banExpiresIn: banForm.expirationDate.getTime() - new Date().getTime(),
+ });
+ toast.success("User banned successfully");
+ setIsBanDialogOpen(false);
+ queryClient.invalidateQueries({
+ queryKey: ["users"],
+ });
+ } catch (error: any) {
+ toast.error(error.message || "Failed to ban user");
+ } finally {
+ setIsLoading(undefined);
+ }
+ };
+
+ return (
+
+
+
+
+ Admin Dashboard
+
+
+
+
+ {isUsersLoading ? (
+
+
+
+ ) : (
+
+
+
+ Email
+ Name
+ Role
+ Banned
+ Actions
+
+
+
+ {users?.map((user) => (
+
+ {user.email}
+ {user.name}
+ {user.role || "user"}
+
+ {user.banned ? (
+ Yes
+ ) : (
+ No
+ )}
+
+
+
+
+
+
+
+
+
+
+ ))}
+
+
+ )}
+
+
+
+ );
+}
diff --git a/examples/nextjs-example/app/dashboard/page.tsx b/examples/nextjs-example/app/dashboard/page.tsx
index 317741be..d94dbb5a 100644
--- a/examples/nextjs-example/app/dashboard/page.tsx
+++ b/examples/nextjs-example/app/dashboard/page.tsx
@@ -7,10 +7,10 @@ import { OrganizationCard } from "./organization-card";
export default async function DashboardPage() {
const [session, activeSessions] = await Promise.all([
auth.api.getSession({
- headers: headers(),
+ headers: await headers(),
}),
auth.api.listSessions({
- headers: headers(),
+ headers: await headers(),
}),
]).catch((e) => {
throw redirect("/sign-in");
diff --git a/examples/nextjs-example/app/dashboard/user-card.tsx b/examples/nextjs-example/app/dashboard/user-card.tsx
index 8dab1f14..a61aa8e9 100644
--- a/examples/nextjs-example/app/dashboard/user-card.tsx
+++ b/examples/nextjs-example/app/dashboard/user-card.tsx
@@ -62,7 +62,7 @@ export default function UserCard(props: {
activeSessions: Session["session"][];
}) {
const router = useRouter();
- const { data, isPending, error } = useSession(props.session);
+ const { data, isPending, error } = useSession();
const [ua, setUa] = useState();
const session = data || props.session;
@@ -216,7 +216,7 @@ export default function UserCard(props: {
Two Factor
- {session?.user.twoFactorEnabled && (
+ {!!session?.user.twoFactorEnabled && (
-
-
diff --git a/examples/nextjs-example/lib/auth-client.ts b/examples/nextjs-example/lib/auth-client.ts
index 5a87c355..391e03f1 100644
--- a/examples/nextjs-example/lib/auth-client.ts
+++ b/examples/nextjs-example/lib/auth-client.ts
@@ -3,6 +3,7 @@ import {
organizationClient,
passkeyClient,
twoFactorClient,
+ adminClient,
} from "better-auth/client/plugins";
import { toast } from "sonner";
@@ -10,9 +11,11 @@ export const client = createAuthClient({
plugins: [
organizationClient(),
twoFactorClient({
+ redirect: true,
twoFactorPage: "/two-factor",
}),
passkeyClient(),
+ adminClient(),
],
fetchOptions: {
onError(e) {
diff --git a/examples/nextjs-example/lib/auth.ts b/examples/nextjs-example/lib/auth.ts
index 81fc1c19..b9754a59 100644
--- a/examples/nextjs-example/lib/auth.ts
+++ b/examples/nextjs-example/lib/auth.ts
@@ -1,37 +1,45 @@
import { betterAuth } from "better-auth";
-import { organization, passkey, twoFactor } from "better-auth/plugins";
+import {
+ bearer,
+ organization,
+ passkey,
+ twoFactor,
+ admin,
+} from "better-auth/plugins";
import { reactInvitationEmail } from "./email/invitation";
+import { LibsqlDialect } from "@libsql/kysely-libsql";
import { reactResetPasswordEmail } from "./email/rest-password";
import { resend } from "./email/resend";
const from = process.env.BETTER_AUTH_EMAIL || "delivered@resend.dev";
const to = process.env.TEST_EMAIL || "";
+
+const libsql = new LibsqlDialect({
+ url: process.env.TURSO_DATABASE_URL || "",
+ authToken: process.env.TURSO_AUTH_TOKEN || "",
+});
+
export const auth = betterAuth({
database: {
- provider: "sqlite",
- url: "./db.sqlite",
+ dialect: libsql,
+ type: "sqlite",
},
emailAndPassword: {
enabled: true,
- async sendResetPassword(token, user) {
- const res = await resend.emails.send({
+ async sendResetPassword(url, user) {
+ await resend.emails.send({
from,
to: user.email,
subject: "Reset your password",
react: reactResetPasswordEmail({
username: user.email,
- resetLink: `${
- process.env.NODE_ENV === "development"
- ? "http://localhost:3000"
- : process.env.NEXT_PUBLIC_APP_URL ||
- process.env.VERCEL_URL ||
- process.env.BETTER_AUTH_URL
- }/reset-password/${token}`,
+ resetLink: url,
}),
});
},
sendEmailVerificationOnSignUp: true,
async sendVerificationEmail(email, url) {
+ console.log("Sending verification email to", email);
const res = await resend.emails.send({
from,
to: to || email,
@@ -68,12 +76,19 @@ export const auth = betterAuth({
}),
twoFactor({
otpOptions: {
- sendOTP(user, otp) {
- console.log({ otp });
+ async sendOTP(user, otp) {
+ await resend.emails.send({
+ from,
+ to: user.email,
+ subject: "Your OTP",
+ html: `Your OTP is ${otp}`,
+ });
},
},
}),
passkey(),
+ bearer(),
+ admin(),
],
socialProviders: {
github: {
@@ -84,5 +99,13 @@ export const auth = betterAuth({
clientId: process.env.GOOGLE_CLIENT_ID || "",
clientSecret: process.env.GOOGLE_CLIENT_SECRET || "",
},
+ discord: {
+ clientId: process.env.DISCORD_CLIENT_ID || "",
+ clientSecret: process.env.DISCORD_CLIENT_SECRET || "",
+ },
+ microsoft: {
+ clientId: process.env.MICROSOFT_CLIENT_ID || "",
+ clientSecret: process.env.MICROSOFT_CLIENT_SECRET || "",
+ },
},
});
diff --git a/examples/nextjs-example/package.json b/examples/nextjs-example/package.json
index 396a49bd..dc06d2c6 100644
--- a/examples/nextjs-example/package.json
+++ b/examples/nextjs-example/package.json
@@ -1,10 +1,11 @@
{
- "name": "@better-auth/next",
+ "name": "@better-auth/demo",
"version": "0.1.0",
"private": true,
"scripts": {
- "dev": "pnpm migrate && next dev",
- "migrate": "better-auth migrate",
+ "dev": "next dev",
+ "dev:secure": "next dev --experimental-https",
+ "typecheck": "tsc --noEmit",
"build": "next build",
"start": "next start",
"lint": "next lint"
@@ -46,13 +47,14 @@
"@react-email/components": "^0.0.25",
"@react-three/fiber": "^8.17.7",
"@tanstack/react-query": "^5.56.2",
- "better-auth": "workspace:*",
"@types/better-sqlite3": "^7.6.11",
- "better-sqlite3": "^11.3.0",
+ "better-auth": "workspace:*",
"better-call": "0.2.3-beta.2",
+ "better-sqlite3": "^11.3.0",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.1",
"cmdk": "1.0.0",
+ "consola": "^3.2.3",
"date-fns": "^3.6.0",
"embla-carousel-react": "^8.2.1",
"framer-motion": "^11.5.4",
@@ -61,7 +63,7 @@
"kysely": "^0.27.4",
"lucide-react": "^0.439.0",
"mini-svg-data-uri": "^1.4.4",
- "next": "15.0.0-canary.157",
+ "next": "15.0.0-canary.185",
"next-themes": "^0.3.0",
"prisma": "^5.19.1",
"react": "19.0.0-rc-7771d3a7-20240827",
diff --git a/examples/nextjs-example/public/favicon/android-chrome-192x192.png b/examples/nextjs-example/public/favicon/android-chrome-192x192.png
index 45b1a90a..c2b1bbff 100644
Binary files a/examples/nextjs-example/public/favicon/android-chrome-192x192.png and b/examples/nextjs-example/public/favicon/android-chrome-192x192.png differ
diff --git a/examples/nextjs-example/public/favicon/android-chrome-512x512.png b/examples/nextjs-example/public/favicon/android-chrome-512x512.png
index 6d2d953a..5c7449d6 100644
Binary files a/examples/nextjs-example/public/favicon/android-chrome-512x512.png and b/examples/nextjs-example/public/favicon/android-chrome-512x512.png differ
diff --git a/examples/nextjs-example/public/favicon/apple-touch-icon.png b/examples/nextjs-example/public/favicon/apple-touch-icon.png
index 1000536e..25bf85b5 100644
Binary files a/examples/nextjs-example/public/favicon/apple-touch-icon.png and b/examples/nextjs-example/public/favicon/apple-touch-icon.png differ
diff --git a/examples/nextjs-example/public/favicon/favicon-16x16.png b/examples/nextjs-example/public/favicon/favicon-16x16.png
index 13f3ec81..c63e12ef 100644
Binary files a/examples/nextjs-example/public/favicon/favicon-16x16.png and b/examples/nextjs-example/public/favicon/favicon-16x16.png differ
diff --git a/examples/nextjs-example/public/favicon/favicon-32x32.png b/examples/nextjs-example/public/favicon/favicon-32x32.png
index 8e99d26a..fe912c8f 100644
Binary files a/examples/nextjs-example/public/favicon/favicon-32x32.png and b/examples/nextjs-example/public/favicon/favicon-32x32.png differ
diff --git a/examples/nextjs-example/public/favicon/favicon.ico b/examples/nextjs-example/public/favicon/favicon.ico
index 4ad7a8e6..9edb1b94 100644
Binary files a/examples/nextjs-example/public/favicon/favicon.ico and b/examples/nextjs-example/public/favicon/favicon.ico differ
diff --git a/examples/nextjs-example/public/favicon/light/android-chrome-192x192.png b/examples/nextjs-example/public/favicon/light/android-chrome-192x192.png
new file mode 100644
index 00000000..2dff0986
Binary files /dev/null and b/examples/nextjs-example/public/favicon/light/android-chrome-192x192.png differ
diff --git a/examples/nextjs-example/public/favicon/light/android-chrome-512x512.png b/examples/nextjs-example/public/favicon/light/android-chrome-512x512.png
new file mode 100644
index 00000000..f42fa86e
Binary files /dev/null and b/examples/nextjs-example/public/favicon/light/android-chrome-512x512.png differ
diff --git a/examples/nextjs-example/public/favicon/light/apple-touch-icon.png b/examples/nextjs-example/public/favicon/light/apple-touch-icon.png
new file mode 100644
index 00000000..4649b141
Binary files /dev/null and b/examples/nextjs-example/public/favicon/light/apple-touch-icon.png differ
diff --git a/examples/nextjs-example/public/favicon/light/favicon-16x16.png b/examples/nextjs-example/public/favicon/light/favicon-16x16.png
new file mode 100644
index 00000000..2b18ff2c
Binary files /dev/null and b/examples/nextjs-example/public/favicon/light/favicon-16x16.png differ
diff --git a/examples/nextjs-example/public/favicon/light/favicon-32x32.png b/examples/nextjs-example/public/favicon/light/favicon-32x32.png
new file mode 100644
index 00000000..dff2b87d
Binary files /dev/null and b/examples/nextjs-example/public/favicon/light/favicon-32x32.png differ
diff --git a/examples/nextjs-example/public/favicon/light/favicon.ico b/examples/nextjs-example/public/favicon/light/favicon.ico
new file mode 100644
index 00000000..d3a2eb4c
Binary files /dev/null and b/examples/nextjs-example/public/favicon/light/favicon.ico differ
diff --git a/examples/nextjs-example/public/favicon/light/site.webmanifest b/examples/nextjs-example/public/favicon/light/site.webmanifest
new file mode 100644
index 00000000..95911504
--- /dev/null
+++ b/examples/nextjs-example/public/favicon/light/site.webmanifest
@@ -0,0 +1,19 @@
+{
+ "name": "",
+ "short_name": "",
+ "icons": [
+ {
+ "src": "/android-chrome-192x192.png",
+ "sizes": "192x192",
+ "type": "image/png"
+ },
+ {
+ "src": "/android-chrome-512x512.png",
+ "sizes": "512x512",
+ "type": "image/png"
+ }
+ ],
+ "theme_color": "#ffffff",
+ "background_color": "#ffffff",
+ "display": "standalone"
+}
diff --git a/examples/nuxt-example/.env.example b/examples/nuxt-example/.env.example
new file mode 100644
index 00000000..9abb10ae
--- /dev/null
+++ b/examples/nuxt-example/.env.example
@@ -0,0 +1,3 @@
+GOOGLE_CLIENT_SECRET=
+GOOGLE_CLIENT_ID=
+RESEND_API_KEY=
\ No newline at end of file
diff --git a/packages/better-auth/package.json b/packages/better-auth/package.json
index 53066183..b80b209d 100644
--- a/packages/better-auth/package.json
+++ b/packages/better-auth/package.json
@@ -90,6 +90,7 @@
"@nanostores/solid": "^0.4.2",
"@nanostores/vue": "^0.10.0",
"@noble/ciphers": "^0.6.0",
+ "@noble/hashes": "^1.5.0",
"@simplewebauthn/browser": "^10.0.0",
"@simplewebauthn/server": "^10.0.1",
"better-call": "0.2.6",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index a3ef9694..b7b7d732 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -1456,6 +1456,9 @@ importers:
'@noble/ciphers':
specifier: ^0.6.0
version: 0.6.0
+ '@noble/hashes':
+ specifier: ^1.5.0
+ version: 1.5.0
'@simplewebauthn/browser':
specifier: ^10.0.0
version: 10.0.0
@@ -3630,6 +3633,10 @@ packages:
'@noble/ciphers@0.6.0':
resolution: {integrity: sha512-mIbq/R9QXk5/cTfESb1OKtyFnk7oc1Om/8onA1158K9/OZUQFDEVy55jVTato+xmp3XX6F6Qh0zz0Nc1AxAlRQ==}
+ '@noble/hashes@1.5.0':
+ resolution: {integrity: sha512-1j6kQFb7QRru7eKN3ZDvRcP13rugwdxZqCjbiAVZfIJwgj2A65UmT4TgARXGlXgnRkORLTDTrO19ZErt7+QXgA==}
+ engines: {node: ^14.21.3 || >=16}
+
'@node-rs/argon2-android-arm-eabi@1.7.0':
resolution: {integrity: sha512-udDqkr5P9E+wYX1SZwAVPdyfYvaF4ry9Tm+R9LkfSHbzWH0uhU6zjIwNRp7m+n4gx691rk+lqqDAIP8RLKwbhg==}
engines: {node: '>= 10'}
@@ -16299,6 +16306,8 @@ snapshots:
'@noble/ciphers@0.6.0': {}
+ '@noble/hashes@1.5.0': {}
+
'@node-rs/argon2-android-arm-eabi@1.7.0':
optional: true