スキル一覧に戻る
oakoss

auth

by oakoss

Open-source SaaS starter kit with React, TanStack, and Better Auth

0🍴 0📅 2026年1月26日
GitHubで見るManusで実行

SKILL.md


name: auth description: Better Auth authentication. Use for auth, login, logout, session, user, signup, register, protect, middleware, password, oauth, social

For advanced patterns, OAuth configuration, and session middleware, see reference.md.

Better Auth

Package Structure

packages/auth/
├── src/
│   ├── client.ts      # Auth client (React hooks)
│   ├── server.ts      # Auth server (Better Auth config)
│   └── index.ts       # Public exports
└── package.json

Server Configuration

// packages/auth/src/server.ts
import { drizzleAdapter } from 'better-auth/adapters/drizzle';
import { betterAuth } from 'better-auth';
import { tanstackStartCookies } from 'better-auth/tanstack-start';
import { db } from '@oakoss/database';

export const auth = betterAuth({
  database: drizzleAdapter(db, {
    provider: 'pg',
    usePlural: true, // Uses 'users', 'sessions', etc.
  }),
  emailAndPassword: { enabled: true },
  plugins: [tanstackStartCookies()], // Must be last plugin in array
});

Client Configuration

// packages/auth/src/client.ts
import { createAuthClient } from 'better-auth/client';
import { inferAdditionalFields } from 'better-auth/client/plugins';
import { type auth } from '@oakoss/auth/server';

export const authClient = createAuthClient({
  baseURL: process.env.PUBLIC_APP_URL ?? 'http://localhost:3000',
  plugins: [inferAdditionalFields<typeof auth>()],
});

API Route Handler

// apps/web/src/routes/api/auth/$.ts
import { createFileRoute } from '@tanstack/react-router';
import { auth } from '@oakoss/auth/server';

export const Route = createFileRoute('/api/auth/$')({
  server: {
    handlers: {
      GET: ({ request }) => auth.handler(request),
      POST: ({ request }) => auth.handler(request),
    },
  },
});

Sign In/Sign Up

import { authClient } from '@oakoss/auth/client';

// Sign up with email
await authClient.signUp.email({
  name: 'John Doe',
  email: 'john@example.com',
  password: 'password123',
});

// Sign in with email
await authClient.signIn.email({
  email: 'john@example.com',
  password: 'password123',
  callbackURL: '/dashboard',
});

// Sign in with social provider
await authClient.signIn.social({
  provider: 'github',
  callbackURL: '/dashboard',
});

Session Management

// Reactive hook
function UserProfile() {
  const { data: session, isPending } = authClient.useSession();

  if (isPending) return <Spinner />;
  if (!session) return <LoginPrompt />;

  return <div>Welcome, {session.user.name}</div>;
}

// One-time fetch
const { data: session } = await authClient.getSession();

Route Protection (beforeLoad)

// apps/web/src/routes/_app/route.tsx
import { createFileRoute, redirect } from '@tanstack/react-router';
import { auth } from '@oakoss/auth/server';

export const Route = createFileRoute('/_app')({
  beforeLoad: async ({ context }) => {
    const session = await auth.api.getSession({
      headers: context.request.headers,
    });

    if (!session) {
      throw redirect({ to: '/login' });
    }

    return { user: session.user };
  },
  component: AppLayout,
});

Server Function Auth Check

import { createServerFn } from '@tanstack/react-start';
import { auth } from '@oakoss/auth/server';

const deletePost = createServerFn({ method: 'POST' })
  .inputValidator(z.object({ id: z.string() }))
  .handler(async ({ data, request }) => {
    const session = await auth.api.getSession({ headers: request.headers });

    if (!session) {
      return { error: 'Unauthorized', code: 'AUTH_REQUIRED' };
    }

    // Check ownership
    const post = await db.query.posts.findFirst({
      where: eq(posts.id, data.id),
    });

    if (post?.authorId !== session.user.id) {
      return { error: 'Not authorized', code: 'FORBIDDEN' };
    }

    await db.delete(posts).where(eq(posts.id, data.id));
    return { success: true };
  });

Sign Out

await authClient.signOut({
  fetchOptions: {
    onSuccess: () => (window.location.href = '/login'),
  },
});

Common Mistakes

MistakeCorrect Pattern
Client-side auth checks onlyValidate session server-side in beforeLoad
Missing request headersPass { headers: request.headers } to API
Not handling loading statesCheck isPending before rendering
Hardcoding callback URLsUse environment variables
Storing session in useStateUse authClient.useSession() hook
Missing auth handler routeCreate /api/auth/$.ts catch-all route
Not using usePlural in adapterSet usePlural: true for Better Auth
Importing server code in clientUse @oakoss/auth/server only server-side

Delegation

  • Route protection: For beforeLoad patterns, see tanstack-router skill
  • Server functions: For auth in server functions, see tanstack-start skill
  • Database: For user queries, see database skill
  • Code review: After implementing auth, delegate to code-reviewer agent

Topic References

  • Auth Reference - Social providers, plugins, session types, error handling

スコア

総合スコア

65/100

リポジトリの品質指標に基づく評価

SKILL.md

SKILL.mdファイルが含まれている

+20
LICENSE

ライセンスが設定されている

+10
説明文

100文字以上の説明がある

0/10
人気

GitHub Stars 100以上

0/15
最近の活動

3ヶ月以内に更新

+5
フォーク

10回以上フォークされている

0/5
Issue管理

オープンIssueが50未満

+5
言語

プログラミング言語が設定されている

+5
タグ

1つ以上のタグが設定されている

+5

レビュー

💬

レビュー機能は近日公開予定です