mirror of
https://github.com/LukeHagar/better-auth.git
synced 2025-12-06 04:19:20 +00:00
chore(docs): misc
This commit is contained in:
committed by
Alex Yang
parent
ccc7c48dee
commit
c456b6a2c5
58
docs/app/api/support/route.ts
Normal file
58
docs/app/api/support/route.ts
Normal file
@@ -0,0 +1,58 @@
|
||||
import { NextResponse } from "next/server";
|
||||
|
||||
export async function POST(request: Request) {
|
||||
try {
|
||||
const body = await request.json();
|
||||
const {
|
||||
name,
|
||||
email,
|
||||
company,
|
||||
website,
|
||||
userCount,
|
||||
interest,
|
||||
features,
|
||||
additional,
|
||||
} = body ?? {};
|
||||
|
||||
if (!name || !email) {
|
||||
return NextResponse.json(
|
||||
{ error: "Missing required fields" },
|
||||
{ status: 400 },
|
||||
);
|
||||
}
|
||||
|
||||
const payload = {
|
||||
name,
|
||||
email,
|
||||
company: company ?? "",
|
||||
website: website ?? "",
|
||||
userCount: userCount ?? "",
|
||||
interest: interest ?? "",
|
||||
features: features ?? "",
|
||||
additional: additional ?? "",
|
||||
submittedAt: new Date().toISOString(),
|
||||
userAgent: request.headers.get("user-agent") ?? undefined,
|
||||
referer: request.headers.get("referer") ?? undefined,
|
||||
};
|
||||
|
||||
const webhook = process.env.SUPPORT_WEBHOOK_URL;
|
||||
if (webhook) {
|
||||
try {
|
||||
await fetch(webhook, {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
} catch (e) {
|
||||
console.error("Support webhook failed", e);
|
||||
}
|
||||
} else {
|
||||
console.log("[support] submission", payload);
|
||||
}
|
||||
|
||||
return NextResponse.json({ ok: true });
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
return NextResponse.json({ error: "Invalid request" }, { status: 400 });
|
||||
}
|
||||
}
|
||||
@@ -16,13 +16,13 @@ import { File, Folder, Files } from "fumadocs-ui/components/files";
|
||||
import { Accordion, Accordions } from "fumadocs-ui/components/accordion";
|
||||
import { Pre } from "fumadocs-ui/components/codeblock";
|
||||
import { Glow } from "../_components/default-changelog";
|
||||
import { IconLink } from "../_components/changelog-layout";
|
||||
import { BookIcon, GitHubIcon, XIcon } from "../_components/icons";
|
||||
import { DiscordLogoIcon } from "@radix-ui/react-icons";
|
||||
import { XIcon } from "../_components/icons";
|
||||
import { StarField } from "../_components/stat-field";
|
||||
import Image from "next/image";
|
||||
import { BlogPage } from "../_components/blog-list";
|
||||
import { Callout } from "@/components/ui/callout";
|
||||
import { ArrowLeftIcon, ExternalLink } from "lucide-react";
|
||||
import { Support } from "../_components/support";
|
||||
|
||||
const metaTitle = "Blogs";
|
||||
const metaDescription = "Latest changes , fixes and updates.";
|
||||
@@ -42,99 +42,127 @@ export default async function Page({
|
||||
notFound();
|
||||
}
|
||||
const MDX = page.data?.body;
|
||||
const toc = page.data?.toc;
|
||||
const { title, description, date } = page.data;
|
||||
return (
|
||||
<div className="md:flex min-h-screen items-stretch relative">
|
||||
<div className="bg-gradient-to-tr hidden md:block overflow-hidden px-12 py-24 md:py-0 -mt-[100px] md:h-dvh relative md:sticky top-0 from-transparent dark:via-stone-950/5 via-stone-100/30 to-stone-200/20 dark:to-transparent/10 min-h-screen flex-shrink-0 w-full md:w-1/2">
|
||||
<StarField className="top-1/2 -translate-y-1/2 left-1/2 -translate-x-1/2" />
|
||||
<div className="relative min-h-screen">
|
||||
<div className="pointer-events-none absolute inset-0 -z-10">
|
||||
<StarField className="top-1/3 left-1/2 -translate-x-1/2" />
|
||||
<Glow />
|
||||
|
||||
<div className="flex flex-col md:justify-center max-w-xl mx-auto h-full">
|
||||
<Link href="/blog" className="text-gray-600 dark:text-gray-300">
|
||||
<div className="flex flex-col">
|
||||
<div className="flex items-center cursor-pointer gap-x-2 text-xs w-full border-white/20">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="2.5em"
|
||||
height="2.5em"
|
||||
className="rotate-180"
|
||||
viewBox="0 0 24 24"
|
||||
>
|
||||
<path
|
||||
fill="currentColor"
|
||||
d="M2 13v-2h16.172l-3.95-3.95l1.414-1.414L22 12l-6.364 6.364l-1.414-1.414l3.95-3.95z"
|
||||
></path>
|
||||
</svg>
|
||||
</div>
|
||||
<h1 className="mt-2 relative font-sans font-semibold tracking-tighter text-4xl mb-2 border-dashed">
|
||||
{title}{" "}
|
||||
</h1>
|
||||
</div>
|
||||
</Link>
|
||||
|
||||
<p className="text-gray-600 dark:text-gray-300">{description}</p>
|
||||
<div className="text-gray-600 text-sm dark:text-gray-400 flex items-center gap-x-1 text-left">
|
||||
By {page.data?.author.name} | {formatDate(page.data?.date)}
|
||||
</div>
|
||||
<div className="mt-4">
|
||||
<Image
|
||||
src={page.data?.image}
|
||||
alt={title}
|
||||
width={804}
|
||||
height={452}
|
||||
className="rounded-md border bg-muted transition-colors"
|
||||
/>
|
||||
</div>
|
||||
<hr className="h-px bg-gray-300 mt-5" />
|
||||
<div className="mt-8 flex flex-wrap text-gray-600 dark:text-gray-300 gap-x-1 gap-y-3 sm:gap-x-2">
|
||||
<IconLink
|
||||
href="/docs"
|
||||
icon={BookIcon}
|
||||
className="flex-none text-gray-600 dark:text-gray-300"
|
||||
>
|
||||
Documentation
|
||||
</IconLink>
|
||||
<IconLink
|
||||
href="https://github.com/better-auth/better-auth"
|
||||
icon={GitHubIcon}
|
||||
className="flex-none text-gray-600 dark:text-gray-300"
|
||||
>
|
||||
GitHub
|
||||
</IconLink>
|
||||
<IconLink
|
||||
href="https://discord.gg/better-auth"
|
||||
icon={DiscordLogoIcon}
|
||||
className="flex-none text-gray-600 dark:text-gray-300"
|
||||
>
|
||||
Community
|
||||
</IconLink>
|
||||
</div>
|
||||
<p className="flex items-baseline absolute bottom-4 max-md:left-1/2 max-md:-translate-x-1/2 gap-x-2 text-[0.8125rem]/6 text-gray-500">
|
||||
<IconLink href="https://x.com/better_auth" icon={XIcon} compact>
|
||||
BETTER-AUTH.
|
||||
</IconLink>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex-1 min-h-0 h-screen overflow-y-auto px-4 relative md:px-8 pb-12 md:py-12">
|
||||
<div className="absolute top-0 left-0 h-full -translate-x-full w-px bg-gradient-to-b from-black/5 dark:from-white/10 via-black/3 dark:via-white/5 to-transparent"></div>
|
||||
<div className="prose">
|
||||
<div className="relative mx-auto max-w-3xl px-4 md:px-0 pb-24 pt-12">
|
||||
<h1 className="text-center text-3xl md:text-5xl font-semibold tracking-tighter">
|
||||
{title}
|
||||
</h1>
|
||||
{description && (
|
||||
<p className="mt-3 text-center text-muted-foreground">
|
||||
{description}
|
||||
</p>
|
||||
)}
|
||||
<div className="my-2 flex items-center justify-center gap-3">
|
||||
{page.data?.author?.avatar && (
|
||||
<Image
|
||||
src={page.data.author.avatar}
|
||||
alt={page.data?.author?.name ?? "Author"}
|
||||
width={40}
|
||||
height={40}
|
||||
className="rounded-full border"
|
||||
/>
|
||||
)}
|
||||
<div className="flex items-center gap-2 text-sm text-muted-foreground">
|
||||
{page.data?.author?.name && (
|
||||
<span className="font-medium text-foreground">
|
||||
{page.data.author.name}
|
||||
</span>
|
||||
)}
|
||||
{page.data?.author?.twitter && (
|
||||
<>
|
||||
<span>·</span>
|
||||
<a
|
||||
href={`https://x.com/${page.data.author.twitter}`}
|
||||
target="_blank"
|
||||
rel="noreferrer noopener"
|
||||
className="inline-flex items-center gap-1 underline decoration-dashed"
|
||||
>
|
||||
<XIcon className="size-3" />@{page.data.author.twitter}
|
||||
</a>
|
||||
</>
|
||||
)}
|
||||
{date && (
|
||||
<>
|
||||
<span>·</span>
|
||||
<time dateTime={String(date)}>{formatDate(date)}</time>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-full flex items-center gap-2 my-4 mb-8">
|
||||
<div className="flex items-center gap-2 opacity-80">
|
||||
<ArrowLeftIcon className="size-4" />
|
||||
<Link href="/blog" className="">
|
||||
Blogs
|
||||
</Link>
|
||||
</div>
|
||||
<hr className="h-1 w-full opacity-80" />
|
||||
</div>
|
||||
|
||||
<article className="prose prose-neutral dark:prose-invert mx-auto max-w-3xl px-4 md:px-0">
|
||||
<MDX
|
||||
components={{
|
||||
...defaultMdxComponents,
|
||||
Link: ({
|
||||
className,
|
||||
...props
|
||||
}: React.ComponentProps<typeof Link>) => (
|
||||
<Link
|
||||
className={cn(
|
||||
"font-medium underline underline-offset-4",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
),
|
||||
a: ({ className, href, children, ...props }: any) => {
|
||||
const isExternal =
|
||||
typeof href === "string" && /^(https?:)?\/\//.test(href);
|
||||
const classes = cn(
|
||||
"inline-flex items-center gap-1 font-medium underline decoration-dashed",
|
||||
className,
|
||||
);
|
||||
if (isExternal) {
|
||||
return (
|
||||
<a
|
||||
className={classes}
|
||||
href={href}
|
||||
target="_blank"
|
||||
rel="noreferrer noopener"
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<ExternalLink className="ms-0.5 inline size-[0.9em] text-fd-muted-foreground" />
|
||||
</a>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Link className={classes} href={href} {...(props as any)}>
|
||||
{children}
|
||||
</Link>
|
||||
);
|
||||
},
|
||||
Link: ({ className, href, children, ...props }: any) => {
|
||||
const isExternal =
|
||||
typeof href === "string" && /^(https?:)?\/\//.test(href);
|
||||
const classes = cn(
|
||||
"inline-flex items-center gap-1 font-medium underline decoration-dashed",
|
||||
className,
|
||||
);
|
||||
if (isExternal) {
|
||||
return (
|
||||
<a
|
||||
className={classes}
|
||||
href={href}
|
||||
target="_blank"
|
||||
rel="noreferrer noopener"
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<ExternalLink className="ms-0.5 inline size-[0.9em] text-fd-muted-foreground" />
|
||||
</a>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Link className={classes} href={href} {...(props as any)}>
|
||||
{children}
|
||||
</Link>
|
||||
);
|
||||
},
|
||||
Step,
|
||||
Steps,
|
||||
File,
|
||||
@@ -164,9 +192,10 @@ export default async function Page({
|
||||
{children}
|
||||
</Callout>
|
||||
),
|
||||
Support,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</article>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -9,7 +9,9 @@ import { DiscordLogoIcon } from "@radix-ui/react-icons";
|
||||
import Image from "next/image";
|
||||
|
||||
export async function BlogPage() {
|
||||
const posts = blogs.getPages();
|
||||
const posts = blogs.getPages().sort((a, b) => {
|
||||
return new Date(b.data.date).getTime() - new Date(a.data.date).getTime();
|
||||
});
|
||||
return (
|
||||
<div className="md:grid md:grid-cols-2 items-start">
|
||||
<div className="bg-gradient-to-tr hidden md:block overflow-hidden px-12 py-24 md:py-0 -mt-[100px] md:h-dvh relative md:sticky top-0 from-transparent dark:via-stone-950/5 via-stone-100/30 to-stone-200/20 dark:to-transparent/10">
|
||||
@@ -75,8 +77,8 @@ export async function BlogPage() {
|
||||
<Image
|
||||
src={post.data.image}
|
||||
alt={post.data.title}
|
||||
width={402}
|
||||
height={252}
|
||||
width={1206}
|
||||
height={756}
|
||||
className="rounded-md w-full bg-muted transition-colors"
|
||||
/>
|
||||
)}
|
||||
|
||||
183
docs/app/blog/_components/support.tsx
Normal file
183
docs/app/blog/_components/support.tsx
Normal file
@@ -0,0 +1,183 @@
|
||||
"use client";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "@/components/ui/dialog";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from "@/components/ui/select";
|
||||
import { Textarea } from "@/components/ui/textarea";
|
||||
import { Callout } from "@/components/ui/callout";
|
||||
import * as React from "react";
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardFooter,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/components/ui/card";
|
||||
|
||||
export function Support() {
|
||||
const [open, setOpen] = React.useState(false);
|
||||
const [submitting, setSubmitting] = React.useState(false);
|
||||
const formRef = React.useRef<HTMLFormElement | null>(null);
|
||||
|
||||
async function onSubmit(event: React.FormEvent<HTMLFormElement>) {
|
||||
event.preventDefault();
|
||||
if (submitting) return;
|
||||
setSubmitting(true);
|
||||
const form = new FormData(event.currentTarget);
|
||||
const payload = {
|
||||
name: String(form.get("name") || ""),
|
||||
email: String(form.get("email") || ""),
|
||||
company: String(form.get("company") || ""),
|
||||
website: String(form.get("website") || ""),
|
||||
userCount: String(form.get("userCount") || ""),
|
||||
interest: String(form.get("interest") || ""),
|
||||
features: String(form.get("features") || ""),
|
||||
additional: String(form.get("additional") || ""),
|
||||
};
|
||||
try {
|
||||
const res = await fetch("/api/support", {
|
||||
method: "POST",
|
||||
headers: { "Content-Type": "application/json" },
|
||||
body: JSON.stringify(payload),
|
||||
});
|
||||
if (!res.ok) throw new Error("Failed to submit");
|
||||
setOpen(false);
|
||||
formRef.current?.reset();
|
||||
// optionally add a toast later
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
// optionally add error toast
|
||||
} finally {
|
||||
setSubmitting(false);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Card className="flex flex-col gap-3 rounded-none">
|
||||
<CardHeader>
|
||||
<CardTitle>Dedicated Support</CardTitle>
|
||||
<CardDescription>
|
||||
We're now offering on demand support for Better Auth and Auth.js.
|
||||
Including help out migrations, consultations, premium dedicated
|
||||
support and more. If you're interested, please get in touch.
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardFooter>
|
||||
<Dialog open={open} onOpenChange={setOpen}>
|
||||
<div>
|
||||
<DialogTrigger asChild>
|
||||
<Button
|
||||
type="button"
|
||||
className="bg-blue-500 text-white hover:bg-blue-600 transition-colors cursor-pointer"
|
||||
>
|
||||
Request support
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
</div>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>Request dedicated support</DialogTitle>
|
||||
<DialogDescription>
|
||||
Tell us about your team and what you're looking for.
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
<form ref={formRef} className="grid gap-4" onSubmit={onSubmit}>
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="name">Your name</Label>
|
||||
<Input id="name" name="name" placeholder="Jane Doe" required />
|
||||
</div>
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="email">Work email</Label>
|
||||
<Input
|
||||
id="email"
|
||||
name="email"
|
||||
type="email"
|
||||
placeholder="jane@company.com"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="company">Company</Label>
|
||||
<Input id="company" name="company" placeholder="Acme Inc." />
|
||||
</div>
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="website">Website</Label>
|
||||
<Input
|
||||
id="website"
|
||||
name="website"
|
||||
placeholder="https://acme.com"
|
||||
/>
|
||||
</div>
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="userCount">Users</Label>
|
||||
<Select name="userCount">
|
||||
<SelectTrigger id="userCount">
|
||||
<SelectValue placeholder="Select users" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="<1k">Less than 1k</SelectItem>
|
||||
<SelectItem value="1k-10k">1k - 10k</SelectItem>
|
||||
<SelectItem value=">10k">More than 10k</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="interest">What are you interested in?</Label>
|
||||
<Select name="interest">
|
||||
<SelectTrigger id="interest">
|
||||
<SelectValue placeholder="Choose a package" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="migration">Migration help</SelectItem>
|
||||
<SelectItem value="consultation">Consultation</SelectItem>
|
||||
<SelectItem value="support">Premium support</SelectItem>
|
||||
<SelectItem value="custom">Custom</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="features">
|
||||
Features or plugins of interest
|
||||
</Label>
|
||||
<Input
|
||||
id="features"
|
||||
name="features"
|
||||
placeholder="SAML, SIWE, WebAuthn, Organizations, ..."
|
||||
/>
|
||||
</div>
|
||||
<div className="grid gap-2">
|
||||
<Label htmlFor="additional">Anything else?</Label>
|
||||
<Textarea
|
||||
id="additional"
|
||||
name="additional"
|
||||
placeholder="Share more context, timelines, and expectations."
|
||||
/>
|
||||
</div>
|
||||
<DialogFooter>
|
||||
<Button type="submit" disabled={submitting}>
|
||||
{submitting ? "Submitting..." : "Submit"}
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</form>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</CardFooter>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
@@ -4,6 +4,7 @@ description: This migration guide aims to guide you move your auth from Supabase
|
||||
date: 2025-08-25
|
||||
author:
|
||||
name: "Dagmawi Esayas"
|
||||
avatar: "/avatars/beka.jpg"
|
||||
image: "/blogs/supabase-ps.png"
|
||||
tags: ["migration", "guides", "supabase", "planetscale"]
|
||||
---
|
||||
|
||||
@@ -4,7 +4,7 @@ description: "SSO with SAML, Multi Team Support, Additional Fields for Organizat
|
||||
date: 2025-07-19
|
||||
author:
|
||||
name: "Bereket Engida"
|
||||
avatar: "/blogs/bereket.png"
|
||||
avatar: "/avatars/beka.jpg"
|
||||
twitter: "iambereket"
|
||||
image: "/release-og/1-3.png"
|
||||
tags: ["1.3", "authentication", "oidc", "mcp", "sso", "organization"]
|
||||
|
||||
66
docs/content/blogs/authjs-joins-better-auth.mdx
Normal file
66
docs/content/blogs/authjs-joins-better-auth.mdx
Normal file
@@ -0,0 +1,66 @@
|
||||
---
|
||||
title: Auth.js is now part of Better Auth
|
||||
description: "Auth.js, formerly known as NextAuth.js, is now being maintained and overseen by Better Auth team"
|
||||
date: 2025-09-22
|
||||
author:
|
||||
name: "Bereket Engida"
|
||||
avatar: "/avatars/beka.jpg"
|
||||
twitter: "imbereket"
|
||||
image: "/blogs/authjs-joins.png"
|
||||
tags: ["seed round", "authentication", "funding"]
|
||||
---
|
||||
|
||||
We’re excited to announce that [Auth.js](https://authjs.dev), formerly known as NextAuth.js, is now being maintained and overseen by Better Auth team. If you haven't heard of Auth.js, it has long been one of the most widely used open source authentication libraries in the JavaScript ecosystem. Chances are, if you’ve used [ChatGPT](https://chatgpt.com), [Google Labs](https://labs.google), [Cal.com](https://cal.com) or a million other websites, you’ve already interacted with Auth.js.
|
||||
|
||||
## Back Story about Better Auth and Auth.js
|
||||
|
||||
Before Better Auth, Auth.js gave developers like us the ability to own our auth without spending months wrestling with OAuth integrations or session management. But as applications became more complex and authentication needs evolved, some of its limitations became harder to ignore. We found ourselves rebuilding the same primitives over and over.
|
||||
|
||||
The Auth.js team recognized these challenges and had big ideas for the future, but for various reasons couldn’t execute them as fully as they hoped.
|
||||
|
||||
That shared frustration and the vision of empowering everyone to truly own their auth started the creation of Better Auth. Since our goals aligned with the Auth.js team, we were excited to help maintain Auth.js and make auth better across the web. As we talked more, we realized that Better Auth was the best home for Auth.js.
|
||||
|
||||
## What does this mean for existing users?
|
||||
|
||||
We recognize how important this project is for countless applications, companies, and developers. If you’re using Auth.js/NextAuth.js today, you can continue doing so without disruption—we’ll keep addressing security patches and urgent issues as they come up.
|
||||
|
||||
But we strongly recommend new projects to start with Better Auth unless there are some very specific feature gaps (most notably stateless session management without a database). Our roadmap includes bringing those capabilities into Better Auth, so the ecosystem can converge rather than fragment.
|
||||
|
||||
<Callout>
|
||||
For teams considering migration, we’ve prepared a [guide](/docs/guides/next-auth-migration-guide) and we’ll be adding more guides and documentation soon.
|
||||
</Callout>
|
||||
|
||||
## Final Thoughts
|
||||
|
||||
We are deeply grateful to the Auth.js community who have carried the project to this point. In particular, the core maintainers-[Balázs](https://x.com/balazsorban44), who served as lead maintainer, [Thang Vu](https://x.com/thanghvu),[Nico Domino](https://ndo.dev), Lluis Agusti and [Falco Winkler](https://github.com/falcowinkler)-pushed through difficult phases, brought in new primitives, and kept the project alive long enough for this transition to even be possible.
|
||||
|
||||
Better Auth beginning was inspired by Auth.js, and now, together, the two projects can carry the ecosystem further. The end goal remains unchanged: you should own your auth!
|
||||
|
||||
### Learn More
|
||||
|
||||
<Cards>
|
||||
<Card
|
||||
href="https://www.better-auth.com/docs/introduction"
|
||||
title="Better Auth Setup"
|
||||
>
|
||||
Get started with installing Better Auth
|
||||
</Card>
|
||||
<Card
|
||||
href="https://www.better-auth.com/docs/comparison"
|
||||
title="Comparison"
|
||||
>
|
||||
Comparison between Better Auth and other options
|
||||
</Card>
|
||||
<Card
|
||||
href="https://www.better-auth.com/docs/guides/next-auth-migration-guide"
|
||||
title="NextAuth Migration Guide"
|
||||
>
|
||||
Migrate from NextAuth to Better Auth
|
||||
</Card>
|
||||
<Card
|
||||
href="https://www.better-auth.com/docs/guides/clerk-migration-guide"
|
||||
title="Clerk Migration Guide"
|
||||
>
|
||||
Migrate from Clerk to Better Auth
|
||||
</Card>
|
||||
</Cards>
|
||||
@@ -49,6 +49,7 @@
|
||||
"clsx": "^2.1.1",
|
||||
"cmdk": "1.1.1",
|
||||
"date-fns": "^4.1.0",
|
||||
"dotenv": "^17.2.2",
|
||||
"embla-carousel-react": "^8.6.0",
|
||||
"foxact": "^0.2.49",
|
||||
"framer-motion": "^12.23.12",
|
||||
|
||||
|
Before Width: | Height: | Size: 9.8 KiB After Width: | Height: | Size: 9.8 KiB |
BIN
docs/public/blogs/authjs-joins.png
Normal file
BIN
docs/public/blogs/authjs-joins.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 552 KiB |
@@ -30,6 +30,8 @@ export const blogCollection = defineCollections({
|
||||
date: z.date(),
|
||||
author: z.object({
|
||||
name: z.string(),
|
||||
avatar: z.string(),
|
||||
twitter: z.string().optional(),
|
||||
}),
|
||||
image: z.string(),
|
||||
tags: z.array(z.string()),
|
||||
|
||||
3
pnpm-lock.yaml
generated
3
pnpm-lock.yaml
generated
@@ -428,6 +428,9 @@ importers:
|
||||
date-fns:
|
||||
specifier: ^4.1.0
|
||||
version: 4.1.0
|
||||
dotenv:
|
||||
specifier: ^17.2.2
|
||||
version: 17.2.2
|
||||
embla-carousel-react:
|
||||
specifier: ^8.6.0
|
||||
version: 8.6.0(react@19.1.1)
|
||||
|
||||
Reference in New Issue
Block a user