npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@startupkit/auth

v0.5.4

Published

Auth package for StartupKit

Readme

@startupkit/auth

Lightweight Authentication and Authorization components and hooks for StartupKit projects.

Part of StartupKit - The Zero to One Startup Framework.

Installation

pnpm add @startupkit/auth better-auth

Or use the StartupKit CLI to get started with a complete monorepo setup:

npx startupkit init

What's Included

This package provides lightweight wrappers around Better Auth:

  • 🎨 AuthProvider - React context provider for client components
  • 🪝 useAuth() - Authentication hook for client components
  • 🔒 Full TypeScript support

You call betterAuth() directly in your project for full control over configuration.

Usage

1. Configure Better Auth (Server-Side)

Create your auth configuration with Better Auth directly:

// lib/auth.ts
import { betterAuth } from "better-auth"
import { drizzleAdapter } from "better-auth/adapters/drizzle"
import { nextCookies } from "better-auth/next-js"
import { emailOTP } from "better-auth/plugins"
import { db } from "@/lib/db"

export const auth = betterAuth({
  basePath: "/auth",
  database: drizzleAdapter(db, {
    provider: "pg"
  }),
  session: {
    expiresIn: 60 * 60 * 24 * 7, // 7 days
    updateAge: 60 * 60 * 24 // Refresh every 24 hours
  },
  plugins: [
    emailOTP({
      sendVerificationOTP: async ({ email, otp }) => {
        // Send OTP via your email provider
        await sendEmail({
          to: email,
          subject: "Your verification code",
          template: "otp",
          data: { code: otp }
        })
      }
    }),
    nextCookies()
  ],
  socialProviders: {
    google: {
      clientId: process.env.GOOGLE_CLIENT_ID!,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET!
    }
  }
})

2. Create API Route Handler

Create the auth API route at app/auth/[...all]/route.ts:

// app/auth/[...all]/route.ts
import { auth } from "@/lib/auth"
import { toNextJsHandler } from "better-auth/next-js"

export const { GET, POST } = toNextJsHandler(auth.handler)

3. Create Auth Client (Client-Side)

Create your auth client using Better Auth:

// lib/auth-client.ts
import { createAuthClient } from "better-auth/react"
import { emailOTPClient } from "better-auth/client/plugins"

export const authClient = createAuthClient({
  basePath: "/auth",
  plugins: [emailOTPClient()]
})

4. Set Up Providers

Wrap your app with the AuthProvider from @startupkit/auth:

// app/providers.tsx
"use client"

import { AuthProvider } from "@startupkit/auth"
import { authClient } from "@/lib/auth-client"

interface ProvidersProps {
  children: React.ReactNode
  user?: User
}

export function Providers({ children, user }: ProvidersProps) {
  return (
    <AuthProvider 
      authClient={authClient}
      user={user}
      onIdentify={(user) => {
        // Optional: Track user identification (e.g., analytics)
        console.log("User identified:", user)
      }}
      onReset={() => {
        // Optional: Reset state on logout (e.g., clear analytics)
        console.log("User logged out")
      }}
    >
      {children}
    </AuthProvider>
  )
}

Pass the user from your root layout:

// app/layout.tsx
import { auth } from "@/lib/auth"
import { headers } from "next/headers"
import { Providers } from "./providers"

export default async function RootLayout({ children }) {
  const session = await auth.api.getSession({
    headers: await headers()
  })

  return (
    <html>
      <body>
        <Providers user={session?.user}>
          {children}
        </Providers>
      </body>
    </html>
  )
}

5. Use Authentication in Components

Access authentication state and methods with the useAuth hook:

"use client"

import { useAuth } from "@startupkit/auth"

export function UserProfile() {
  const { isAuthenticated, isLoading, user, logout } = useAuth()

  if (isLoading) {
    return <div>Loading...</div>
  }

  if (!isAuthenticated) {
    return <a href="/sign-in">Sign In</a>
  }

  return (
    <div>
      <p>Welcome, {user.name}</p>
      <button onClick={logout}>Sign Out</button>
    </div>
  )
}

Authentication Methods

Email OTP (One-Time Password)

"use client"

import { useAuth } from "@startupkit/auth"
import { useState } from "react"

export function EmailSignIn() {
  const { sendAuthCode, verifyAuthCode } = useAuth()
  const [email, setEmail] = useState("")
  const [code, setCode] = useState("")
  const [step, setStep] = useState<"email" | "code">("email")

  const handleSendCode = async (e: React.FormEvent) => {
    e.preventDefault()
    await sendAuthCode(email)
    setStep("code")
  }

  const handleVerifyCode = async (e: React.FormEvent) => {
    e.preventDefault()
    await verifyAuthCode(email, code)
    // User is now authenticated
  }

  if (step === "email") {
    return (
      <form onSubmit={handleSendCode}>
        <input
          type="email"
          value={email}
          onChange={(e) => setEmail(e.target.value)}
          placeholder="Enter your email"
          required
        />
        <button type="submit">Send Code</button>
      </form>
    )
  }

  return (
    <form onSubmit={handleVerifyCode}>
      <input
        type="text"
        value={code}
        onChange={(e) => setCode(e.target.value)}
        placeholder="Enter verification code"
        required
      />
      <button type="submit">Verify</button>
    </form>
  )
}

Google OAuth

"use client"

import { useAuth } from "@startupkit/auth"

export function GoogleSignIn() {
  const { googleAuth } = useAuth()

  return (
    <button onClick={googleAuth}>
      Sign in with Google
    </button>
  )
}

Sign Out

"use client"

import { useAuth } from "@startupkit/auth"

export function SignOutButton() {
  const { logout } = useAuth()

  return (
    <button onClick={logout}>
      Sign Out
    </button>
  )
}

Server-Side Authentication

Protect Server Components

// app/dashboard/page.tsx
import { auth } from "@/lib/auth"
import { headers } from "next/headers"
import { redirect } from "next/navigation"

export default async function DashboardPage() {
  const session = await auth.api.getSession({
    headers: await headers()
  })

  if (!session) {
    redirect("/sign-in")
  }

  return (
    <div>
      <h1>Dashboard</h1>
      <p>Welcome, {session.user.name}</p>
    </div>
  )
}

Use in API Routes

// app/api/profile/route.ts
import { auth } from "@/lib/auth"
import { headers } from "next/headers"
import { NextResponse } from "next/server"

export async function GET() {
  const session = await auth.api.getSession({
    headers: await headers()
  })

  if (!session) {
    return NextResponse.json(
      { error: "Unauthorized" },
      { status: 401 }
    )
  }

  return NextResponse.json({
    user: session.user
  })
}

Features

Supported Authentication Methods

  • Email OTP - One-time password via email (10-minute expiration)
  • Google OAuth - Sign in with Google
  • Session Management - 7-day sessions with 24-hour auto-refresh
  • TypeScript - Full type safety

Built With

This package is a lightweight wrapper around Better Auth, providing:

  • React context and hooks for easy integration
  • Server utilities for Next.js
  • TypeScript type definitions
  • Minimal configuration required

API Reference

Client Exports

AuthProvider

React context provider wrapping Better Auth client.

interface AuthProviderProps {
  children: React.ReactNode
  user?: User
  authClient: BetterAuthClient
  onIdentify?: (user: User) => void
  onReset?: () => void
}

useAuth()

Hook to access authentication state and methods.

const {
  isAuthenticated,    // boolean - Is user authenticated?
  isLoading,          // boolean - Is session loading?
  user,               // User | null | undefined - Current user
  logout,             // () => Promise<void> - Sign out user
  sendAuthCode,       // (email: string) => Promise<void> - Send OTP
  verifyAuthCode,     // (email: string, code: string) => Promise<void> - Verify OTP
  googleAuth          // () => Promise<void> - Sign in with Google
} = useAuth()

AuthContext

React context (if you need direct access).

import { AuthContext } from "@startupkit/auth"

Configuration

All authentication configuration happens in Better Auth directly. See the Better Auth documentation for complete configuration options including:

  • Email/password authentication
  • Social providers (Google, GitHub, etc.)
  • Magic links
  • Two-factor authentication
  • Custom database adapters
  • Hooks and middleware

Environment Variables

Required for Google OAuth:

GOOGLE_CLIENT_ID=your_google_client_id
GOOGLE_CLIENT_SECRET=your_google_client_secret

Learn More

Support

Having issues? Open an issue on GitHub

License

ISC © 2025 01 Studio