Files
better-auth/demo/nextjs/lib/auth.ts
ririxi cb900f9594 feat(organization): support multiple permissions check (#2227)
* feat: remove the artificial resource limit so that code can check

Also change `permission` to `permissions` (clearer for end user). `permission` is left for backwards compatibility.

* docs: add examples for multiple perms checking

* refactor: check `permissions` first, then legacy one

* feat: use union types for `permission` & `permissions`

* fix: properly use union types

* fix: remove accidental `@deprecated` comment

* chore: lint

* fix test

* chore: add oneTimeToken plugin to client barrel exports (#2224)

* docs(expo): add id token usage

* feat(oauth2): override user info on provider sign-in (#2148)

* feat(oauth2): override user info on provider sign-in

* improve email verification handling

* resolve mrge

* fix(sso): update overrideUserInfo handling to use provider configuration

* fix param

* chore: change plugin interface middleware type (#2195)

* fix: delete from session table when stopImpersonate called (#2230)

* chore: fix active organization inferred type

* chore: fix admin test

---------

Co-authored-by: Bereket Engida <bekacru@gmail.com>
Co-authored-by: Wade Fletcher <3798059+wadefletch@users.noreply.github.com>
Co-authored-by: Bereket Engida <86073083+Bekacru@users.noreply.github.com>
Co-authored-by: KinfeMichael Tariku <65047246+Kinfe123@users.noreply.github.com>
2025-04-12 22:00:58 +03:00

205 lines
4.9 KiB
TypeScript

import { betterAuth } from "better-auth";
import {
bearer,
admin,
multiSession,
organization,
twoFactor,
oneTap,
oAuthProxy,
openAPI,
oidcProvider,
customSession,
} from "better-auth/plugins";
import { reactInvitationEmail } from "./email/invitation";
import { LibsqlDialect } from "@libsql/kysely-libsql";
import { reactResetPasswordEmail } from "./email/reset-password";
import { resend } from "./email/resend";
import { MysqlDialect } from "kysely";
import { createPool } from "mysql2/promise";
import { nextCookies } from "better-auth/next-js";
import { passkey } from "better-auth/plugins/passkey";
import { expo } from "@better-auth/expo";
import { stripe } from "@better-auth/stripe";
import { Stripe } from "stripe";
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 || "",
});
const mysql = process.env.USE_MYSQL
? new MysqlDialect(createPool(process.env.MYSQL_DATABASE_URL || ""))
: null;
const dialect = process.env.USE_MYSQL ? mysql : libsql;
if (!dialect) {
throw new Error("No dialect found");
}
const PROFESSION_PRICE_ID = {
default: "price_1QxWZ5LUjnrYIrml5Dnwnl0X",
annual: "price_1QxWZTLUjnrYIrmlyJYpwyhz",
};
const STARTER_PRICE_ID = {
default: "price_1QxWWtLUjnrYIrmleljPKszG",
annual: "price_1QxWYqLUjnrYIrmlonqPThVF",
};
export const auth = betterAuth({
appName: "Better Auth Demo",
database: {
dialect,
type: process.env.USE_MYSQL ? "mysql" : "sqlite",
},
emailVerification: {
async sendVerificationEmail({ user, url }) {
const res = await resend.emails.send({
from,
to: to || user.email,
subject: "Verify your email address",
html: `<a href="${url}">Verify your email address</a>`,
});
console.log(res, user.email);
},
},
account: {
accountLinking: {
trustedProviders: ["google", "github", "demo-app"],
},
},
emailAndPassword: {
enabled: true,
async sendResetPassword({ user, url }) {
await resend.emails.send({
from,
to: user.email,
subject: "Reset your password",
react: reactResetPasswordEmail({
username: user.email,
resetLink: url,
}),
});
},
},
socialProviders: {
facebook: {
clientId: process.env.FACEBOOK_CLIENT_ID || "",
clientSecret: process.env.FACEBOOK_CLIENT_SECRET || "",
},
github: {
clientId: process.env.GITHUB_CLIENT_ID || "",
clientSecret: process.env.GITHUB_CLIENT_SECRET || "",
},
google: {
clientId: process.env.NEXT_PUBLIC_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 || "",
},
twitch: {
clientId: process.env.TWITCH_CLIENT_ID || "",
clientSecret: process.env.TWITCH_CLIENT_SECRET || "",
},
twitter: {
clientId: process.env.TWITTER_CLIENT_ID || "",
clientSecret: process.env.TWITTER_CLIENT_SECRET || "",
},
},
plugins: [
organization({
async sendInvitationEmail(data) {
await resend.emails.send({
from,
to: data.email,
subject: "You've been invited to join an organization",
react: reactInvitationEmail({
username: data.email,
invitedByUsername: data.inviter.user.name,
invitedByEmail: data.inviter.user.email,
teamName: data.organization.name,
inviteLink:
process.env.NODE_ENV === "development"
? `http://localhost:3000/accept-invitation/${data.id}`
: `${
process.env.BETTER_AUTH_URL ||
"https://demo.better-auth.com"
}/accept-invitation/${data.id}`,
}),
});
},
}),
twoFactor({
otpOptions: {
async sendOTP({ user, otp }) {
await resend.emails.send({
from,
to: user.email,
subject: "Your OTP",
html: `Your OTP is ${otp}`,
});
},
},
}),
passkey(),
openAPI(),
bearer(),
admin({
adminUserIds: ["EXD5zjob2SD6CBWcEQ6OpLRHcyoUbnaB"],
}),
multiSession(),
oAuthProxy(),
nextCookies(),
oidcProvider({
loginPage: "/sign-in",
}),
oneTap(),
customSession(async (session) => {
return {
...session,
user: {
...session.user,
dd: "test",
},
};
}),
stripe({
stripeClient: new Stripe(process.env.STRIPE_KEY || "sk_test_"),
stripeWebhookSecret: process.env.STRIPE_WEBHOOK_SECRET!,
subscription: {
enabled: true,
plans: [
{
name: "Starter",
priceId: STARTER_PRICE_ID.default,
annualDiscountPriceId: STARTER_PRICE_ID.annual,
freeTrial: {
days: 7,
},
},
{
name: "Professional",
priceId: PROFESSION_PRICE_ID.default,
annualDiscountPriceId: PROFESSION_PRICE_ID.annual,
},
{
name: "Enterprise",
},
],
},
}),
expo(),
],
trustedOrigins: ["exp://"],
});