mirror of
https://github.com/LukeHagar/better-auth.git
synced 2025-12-09 20:27:44 +00:00
fix: email verfication
This commit is contained in:
@@ -4,11 +4,13 @@ import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar";
|
|||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import {
|
import {
|
||||||
Card,
|
Card,
|
||||||
|
CardDescription,
|
||||||
CardContent,
|
CardContent,
|
||||||
CardFooter,
|
CardFooter,
|
||||||
CardHeader,
|
CardHeader,
|
||||||
CardTitle,
|
CardTitle,
|
||||||
} from "@/components/ui/card";
|
} from "@/components/ui/card";
|
||||||
|
import { Alert, AlertTitle, AlertDescription } from "@/components/ui/alert";
|
||||||
import { Checkbox } from "@/components/ui/checkbox";
|
import { Checkbox } from "@/components/ui/checkbox";
|
||||||
import {
|
import {
|
||||||
Dialog,
|
Dialog,
|
||||||
@@ -87,7 +89,8 @@ export default function UserCard(props: {
|
|||||||
const [twoFaPassword, setTwoFaPassword] = useState<string>("");
|
const [twoFaPassword, setTwoFaPassword] = useState<string>("");
|
||||||
const [twoFactorDialog, setTwoFactorDialog] = useState<boolean>(false);
|
const [twoFactorDialog, setTwoFactorDialog] = useState<boolean>(false);
|
||||||
const [isSignOut, setIsSignOut] = useState<boolean>(false);
|
const [isSignOut, setIsSignOut] = useState<boolean>(false);
|
||||||
|
const [emailVerificationPending, setEmailVerificationPending] =
|
||||||
|
useState<boolean>(false);
|
||||||
return (
|
return (
|
||||||
<Card>
|
<Card>
|
||||||
<CardHeader>
|
<CardHeader>
|
||||||
@@ -113,6 +116,47 @@ export default function UserCard(props: {
|
|||||||
</div>
|
</div>
|
||||||
<EditUserDialog session={session} />
|
<EditUserDialog session={session} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{session?.user.emailVerified ? null : (
|
||||||
|
<Alert>
|
||||||
|
<AlertTitle>Verify Your Email Address</AlertTitle>
|
||||||
|
<AlertDescription className="text-muted-foreground">
|
||||||
|
Please verify your email address. Check your inbox for the
|
||||||
|
verification email. If you haven't received the email, click the
|
||||||
|
button below to resend.
|
||||||
|
</AlertDescription>
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
variant="secondary"
|
||||||
|
className="mt-2"
|
||||||
|
onClick={async () => {
|
||||||
|
await client.sendVerificationEmail({
|
||||||
|
email: session?.user.email || "",
|
||||||
|
fetchOptions: {
|
||||||
|
onRequest(context) {
|
||||||
|
setEmailVerificationPending(true);
|
||||||
|
},
|
||||||
|
onError(context) {
|
||||||
|
toast.error(context.error.message);
|
||||||
|
setEmailVerificationPending(false);
|
||||||
|
},
|
||||||
|
onSuccess() {
|
||||||
|
toast.success("Verification email sent successfully");
|
||||||
|
setEmailVerificationPending(false);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{emailVerificationPending ? (
|
||||||
|
<Loader2 size={15} className="animate-spin" />
|
||||||
|
) : (
|
||||||
|
"Resend Verification Email"
|
||||||
|
)}
|
||||||
|
</Button>
|
||||||
|
</Alert>
|
||||||
|
)}
|
||||||
|
|
||||||
<div className="border-l-2 px-2 w-max gap-1 flex flex-col">
|
<div className="border-l-2 px-2 w-max gap-1 flex flex-col">
|
||||||
<p className="text-xs font-medium ">Active Sessions</p>
|
<p className="text-xs font-medium ">Active Sessions</p>
|
||||||
{props.activeSessions
|
{props.activeSessions
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { reactResetPasswordEmail } from "./email/rest-password";
|
|||||||
import { resend } from "./email/resend";
|
import { resend } from "./email/resend";
|
||||||
|
|
||||||
const from = process.env.BETTER_AUTH_EMAIL || "delivered@resend.dev";
|
const from = process.env.BETTER_AUTH_EMAIL || "delivered@resend.dev";
|
||||||
|
const to = process.env.TEST_EMAIL || "";
|
||||||
export const auth = betterAuth({
|
export const auth = betterAuth({
|
||||||
database: new LibsqlDialect({
|
database: new LibsqlDialect({
|
||||||
url: process.env.TURSO_DATABASE_URL || "",
|
url: process.env.TURSO_DATABASE_URL || "",
|
||||||
@@ -30,7 +31,16 @@ export const auth = betterAuth({
|
|||||||
}/reset-password/${token}`,
|
}/reset-password/${token}`,
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
console.log(res, user.email);
|
},
|
||||||
|
sendEmailVerificationOnSignUp: true,
|
||||||
|
async sendVerificationEmail(email, url) {
|
||||||
|
const res = await resend.emails.send({
|
||||||
|
from,
|
||||||
|
to: to || email,
|
||||||
|
subject: "Verify your email address",
|
||||||
|
html: `<a href="${url}">Verify your email address</a>`,
|
||||||
|
});
|
||||||
|
console.log(res, email);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
|
|||||||
@@ -122,13 +122,12 @@ const verifyEmail = async () => {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### Password Reset
|
### Forget Password
|
||||||
|
|
||||||
|
to allow users to reset a password first you need to provider `sendResetPassword` function to the email and password authenticator. The `sendResetPassword` function takes an object with the following properties:
|
||||||
to reset a password first you need to provider `sendResetPasswordToken` function to the email and password authenticator. The `sendResetPasswordToken` function takes an object with the following properties:
|
|
||||||
|
|
||||||
- `user`: The user object.
|
- `user`: The user object.
|
||||||
- `token`: The token that was generated.
|
- `url`: The url to send to the user which contains the token.
|
||||||
|
|
||||||
```ts title="auth.ts"
|
```ts title="auth.ts"
|
||||||
import { betterAuth } from "better-auth"
|
import { betterAuth } from "better-auth"
|
||||||
@@ -140,9 +139,8 @@ export const auth = await betterAuth({
|
|||||||
},
|
},
|
||||||
emailAndPassword: { // [!code highlight]
|
emailAndPassword: { // [!code highlight]
|
||||||
enabled: true, // [!code highlight]
|
enabled: true, // [!code highlight]
|
||||||
async sendResetPasswordToken(token, user) { // [!code highlight]
|
async sendResetPassword(url, user) { // [!code highlight]
|
||||||
// send email to user // [!code highlight]
|
// send email to user // [!code highlight]
|
||||||
const url = `https://example.com/reset-password?token=${token}` // [!code highlight]
|
|
||||||
await sendResetEmail(user.email, url) //your function to send email to user // [!code highlight]
|
await sendResetEmail(user.email, url) //your function to send email to user // [!code highlight]
|
||||||
}, // [!code highlight]
|
}, // [!code highlight]
|
||||||
} // [!code highlight]
|
} // [!code highlight]
|
||||||
@@ -151,10 +149,16 @@ export const auth = await betterAuth({
|
|||||||
|
|
||||||
once you configured your server you can call `forgetPassword` function to send reset password link to user.
|
once you configured your server you can call `forgetPassword` function to send reset password link to user.
|
||||||
|
|
||||||
|
It takes an object with the following properties:
|
||||||
|
|
||||||
|
- `email`: The email address of the user.
|
||||||
|
- `redirectTo`: The URL to redirect to after the user clicks on the link in the email. If the token is valid, the user will be redirected to this URL with the token in the query string. If the token is invalid, the user will be redirected to this URL with an error message in the query string `?error=invalid_token`.
|
||||||
|
|
||||||
```ts title="client.ts"
|
```ts title="client.ts"
|
||||||
const forgetPassword = async () => {
|
const forgetPassword = async () => {
|
||||||
const data = await client.forgetPassword({
|
const data = await client.forgetPassword({
|
||||||
email: "test@example.com",
|
email: "test@example.com",
|
||||||
|
redirectTo: "/reset-password"
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -218,7 +222,7 @@ export const auth = betterAuth({
|
|||||||
type: 'number',
|
type: 'number',
|
||||||
default: 32,
|
default: 32,
|
||||||
},
|
},
|
||||||
sendResetPasswordToken: {
|
sendResetPassword: {
|
||||||
description: 'send reset password email. It takes a functions that takes two parameters: token and user.',
|
description: 'send reset password email. It takes a functions that takes two parameters: token and user.',
|
||||||
type: 'function',
|
type: 'function',
|
||||||
},
|
},
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user