better-authで実現する!フレームワーク非依存の爆速認証機能実装ガイド
背景
Node.jsで認証機能を実装する際には、一般的にはauth.jsが利用されることが多いです。oauthのサポートはほぼ完璧ですが、2要素認証(2FA)、ユーザーネームとパスワードに基づいた認証、あるいはGoogle one tapなどを実装するときは、多くのコードを書く必要があります。
また、エンジニアにより、安全ではない認証機能を実装する可能性も高くなります。(例えば、ユーザーネームとパスワードで認証する機能を実装する際に、パスワードの暗号化と難易度確認は自分で実装する必要があります)
そこで、auth.js以外のライブラリーやサービスを探してみました。
探してみた結果、今回の記事で紹介する better-auth を見つけました。
本文の目的
-
better-auth
の紹介。 -
better-auth
を実際に使って、認証機能の実装を体験する。
注意点
- 本文は、TypeScript経験者向けのため、コアとなるコードのみを掲載しています、自分で検証したい方はGithubに公開したリポジトリの内容をチェックしてください。
- サンプルにNext.jsを使っていますが、
better-auth
はフレームワークに関係なく、どのフレームワークでも使えるので、Next.jsの知識が不要。 - Google one tap機能は本番環境が必要になります。
Next.js15とbetter-authで爆速実装
例として、ユーザーネームとパスワードでの認証、Google oauthとGoogle one tapを実装する。
では、早速、実装に入ります。
実行環境
Next.jsプロジェクトの初期化
-
新規プロジェクト作成
npm create next-app@latest
-
better-auth
のインストールnpm add better-auth
root directoryにauth.ts作成
import { betterAuth } from "better-auth";
import { oneTap } from "better-auth/plugins";
/*
本文はPrismaを使ってデーターベースを操作しています、Prismaを使わなくても動けます、詳細は
https://www.prisma.io/
と
https://www.better-auth.com/docs/installation
にて確認してください
*/
import { prismaAdapter } from "better-auth/adapters/prisma";
import { PrismaClient } from "@prisma/client";
const prisma = new PrismaClient();
export const auth = betterAuth({
database: prismaAdapter(prisma, {
provider: "postgresql",
}),
// ユーザーネームとパスワード認証をONにする
emailAndPassword: {
enabled: true,
},
// Google oauthを設定する
socialProviders: {
google: {
clientId: process.env.GOOGLE_CLIENT_ID!,
clientSecret: process.env.GOOGLE_CLIENT_SECRET!,
},
},
// Google one tapのプラグインをONにする
plugins: [oneTap()],
});
server api作成
/app/api/auth/[...all]/route.ts
import { auth } from "@/auth";
// Next.js専用のHandlerを導入する
// Next.js以外の場合はhttps://www.better-auth.com/docs/integrations/nodeを参照してください
import { toNextJsHandler } from "better-auth/next-js";
export const { POST, GET } = toNextJsHandler(auth);
client api作成
/lib/auth-client.ts
import { createAuthClient } from "better-auth/react"
import { oneTapClient } from "better-auth/client/plugins"
// Client side専用のapiを作成する
export const authClient = createAuthClient({
baseURL: NEXT_PUBLIC_APP_URL!,
plugins: [
oneTapClient({
clientId: process.env.NEXT_PUBLIC_GOOGLE_CLIENT_ID!
})
]
})
認証画面実装(ロジック部分抜粋)
/components/user-auth-form.tsx
画面実装はshadcn/uiを使用している。
詳細のコードはGithubでチェックできます。
async function onSubmit(event: React.SyntheticEvent) {
event.preventDefault()
setIsLoading(true)
if (!isLogin) {
try {
// 新規ユーザ登録処理
const { data, error } = await authClient.signUp.email(
{
email,
password,
name: email.split("@")[0],
},
{
onRequest: () => {
setIsLoading(true)
},
onSuccess: () => {
router.push("/dashboard")
},
onError: ctx => {
alert(ctx.error.message)
},
}
)
} finally {
setIsLoading(false)
}
} else {
try {
// ユーザーネームとパスワードでログイン処理
const { data, error } = await authClient.signIn.email(
{
email,
password,
},
{
onRequest: () => {
setIsLoading(true)
},
onSuccess: () => {
router.push("/dashboard")
},
onError: ctx => {
alert(ctx.error.message)
},
}
)
} finally {
setIsLoading(false)
}
}
}
async function handleGoogleSignIn() {
// Google oauth
try {
setIsLoading(true)
await authClient.signIn.social({
provider: "google",
callbackURL: "/dashboard",
})
} catch (error) {
console.error(error)
alert("Failed to sign in with Google")
} finally {
setIsLoading(false)
}
}
google-one-tap.tsx
// ここのcomponentはuser-auth-form.tsxに入れてあります、画面がmountされた後に実行されます
// 一点補足ですが、誤ってgoogle one tapをキャンセルしてしまった方はchrome://settings/content/federatedIdentityApiで権限をリセットしてください
"use client"
import { useEffectOnce } from 'react-use'
import { authClient } from '@/lib/auth-client'
import { useRouter } from 'next/navigation'
export const GoogleOneTap = () => {
const router = useRouter()
useEffectOnce(() => {
authClient.oneTap({
fetchOptions: {
onSuccess: () => {
router.push("/dashboard")
}
}
})
})
return null
}
これで、ユーザー認証がつかえるようになる
検証
こちらは認証画面
Google one tap認証中
認証完了後、ユーザー情報取得
最後に
better-auth
は、モダンなWeb開発における認証機能の実装を大幅に簡素化してくれます。特に以下の場合におすすめです:
- 短期間で認証機能を実装したい場合
セキュリティを重視しつつ、実装の手間を減らしたい場合 - フレームワークに依存せず、再利用可能な認証システムを構築したい場合
今回紹介した実装例は基本的な機能のみですが、better-authはより高度な認証機能(例:Passkey、SSOなど)も簡単に追加することができます。興味のある方は、公式ドキュメントや本記事のGithubリポジトリを参考し、チャレンジしてみてください。
最後まで読んでいただきありがとうございました!
Discussion