Skip to content

Commit 1d8fa71

Browse files
committed
feat(auth): add basic phone signin and signup
1 parent 4303442 commit 1d8fa71

File tree

8 files changed

+755
-3
lines changed

8 files changed

+755
-3
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,6 @@ yarn-error.log*
3939
# typescript
4040
*.tsbuildinfo
4141
next-env.d.ts
42+
queries/
43+
.idea/
44+
sqlite.db

app/api/auth/[...all]/route.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import { auth } from "@/lib/auth";
2+
import { toNextJsHandler } from "better-auth/next-js";
3+
4+
export const { POST, GET } = toNextJsHandler(auth);

app/page.tsx

Lines changed: 57 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,60 @@
1-
import { ComponentExample } from "@/components/component-example";
1+
"use client";
2+
3+
import { Button } from "@/components/ui/button";
4+
import { Input } from "@/components/ui/input";
5+
import { phoneNumber, signOut, useSession } from "@/lib/auth-client";
6+
import { useState } from "react";
27

38
export default function Page() {
4-
return <ComponentExample />;
9+
const session = useSession();
10+
const [phone, setPhone] = useState("");
11+
12+
function sendOtp(event: React.FormEvent) {
13+
event.preventDefault();
14+
const formData = new FormData(event.target as HTMLFormElement);
15+
const phone = formData.get("phone") as string;
16+
17+
setPhone(phone);
18+
19+
phoneNumber.sendOtp({
20+
phoneNumber: phone,
21+
});
22+
}
23+
24+
function onVerify(event: React.FormEvent) {
25+
event.preventDefault();
26+
27+
if (!phone) return;
28+
29+
const formData = new FormData(event.target as HTMLFormElement);
30+
const otp = formData.get("otp") as string;
31+
32+
phoneNumber.verify({ phoneNumber: phone, code: otp });
33+
}
34+
35+
return (
36+
<main>
37+
{session.data?.session ? (
38+
<div>
39+
<Button type="button" onClick={() => signOut()}>
40+
Logout
41+
</Button>
42+
<pre>
43+
<code>{JSON.stringify(session.data?.user ?? {}, null, "\t")}</code>
44+
</pre>
45+
</div>
46+
) : (
47+
<div>
48+
<form className="flex" onSubmit={sendOtp}>
49+
<Input type="text" name="phone" placeholder="Phone Number" />
50+
<Button type="submit">Send</Button>
51+
</form>
52+
<form className="flex" onSubmit={onVerify}>
53+
<Input type="text" name="otp" placeholder="Confirmation Code" />
54+
<Button type="submit">Verify</Button>
55+
</form>
56+
</div>
57+
)}
58+
</main>
59+
);
560
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
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, "phoneNumber" text unique, "phoneNumberVerified" integer);
2+
3+
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);
4+
5+
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);
6+
7+
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);
8+
9+
create index "session_userId_idx" on "session" ("userId");
10+
11+
create index "account_userId_idx" on "account" ("userId");
12+
13+
create index "verification_identifier_idx" on "verification" ("identifier");

lib/auth-client.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { phoneNumberClient } from "better-auth/client/plugins";
2+
import { createAuthClient } from "better-auth/react";
3+
4+
const authClient = createAuthClient({
5+
plugins: [phoneNumberClient()],
6+
});
7+
8+
export const { signIn, signUp, useSession, phoneNumber, signOut } = authClient;

lib/auth.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { betterAuth } from "better-auth";
2+
import { phoneNumber } from "better-auth/plugins";
3+
import Database from "better-sqlite3";
4+
5+
export const auth = betterAuth({
6+
database: new Database("./sqlite.db"),
7+
8+
plugins: [
9+
phoneNumber({
10+
sendOTP: ({ phoneNumber, code }, ctx) => {
11+
console.log({ phoneNumber, code });
12+
},
13+
signUpOnVerification: {
14+
getTempEmail: (phoneNumber) => {
15+
return `${phoneNumber}@example.org`;
16+
},
17+
},
18+
}),
19+
],
20+
});

0 commit comments

Comments
 (0)