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

@webdevarif/auth

v1.0.7

Published

A comprehensive authentication package for Next.js applications with customizable forms, pages, and middleware

Readme

@webdevarif/auth

A comprehensive authentication package for Next.js applications with customizable forms, pages, and middleware. Built on top of NextAuth.js v4 with Prisma integration.

Features

  • 🔐 Complete Authentication System - Login, register, email verification
  • 🎨 Customizable UI Components - Pre-built forms and pages with Tailwind CSS
  • 🛡️ Middleware Support - Route protection and authentication guards
  • 🔧 Flexible Configuration - Environment-based setup with custom callbacks
  • 📱 Responsive Design - Mobile-first approach with modern UI
  • 🌐 Internationalization Ready - Built-in i18n support
  • 🎯 TypeScript First - Full type safety and IntelliSense support
  • 🔌 Plugin Architecture - Easy to extend and customize

Installation

npm install @webdevarif/auth
# or
pnpm add @webdevarif/auth
# or
yarn add @webdevarif/auth

Peer Dependencies

Make sure you have these packages installed:

npm install next@>=14.0.0 react@>=18.0.0 react-dom@>=18.0.0 next-auth@>=4.24.0 @auth/prisma-adapter@>=1.0.0 prisma@>=5.0.0

Quick Start

1. Environment Variables

Create a .env.local file:

# Database
DATABASE_URL="your-database-url"

# NextAuth
NEXTAUTH_SECRET="your-secret-key"
NEXTAUTH_URL="http://localhost:3000"

# OAuth Providers (optional)
AUTH_GOOGLE_ID="your-google-client-id"
AUTH_GOOGLE_SECRET="your-google-client-secret"

# Email Configuration (optional)
EMAIL_FROM="[email protected]"
EMAIL_SERVER_HOST="smtp.gmail.com"
EMAIL_SERVER_PORT=587
EMAIL_SERVER_USER="[email protected]"
EMAIL_SERVER_PASSWORD="your-app-password"

2. Prisma Schema

Add the required models to your schema.prisma:

model User {
  id            Int      @id @default(autoincrement())
  name          String?
  username      String   @unique
  email         String   @unique
  emailVerified DateTime?
  image         String?
  password      String?
  phone         String?
  role          String   @default("USER")
  plan          String   @default("FREE")
  website_url   String?
  is_active     Boolean  @default(true)
  is_superuser  Boolean  @default(false)
  created_at    DateTime @default(now())
  updated_at    DateTime @updatedAt

  accounts Account[]
  sessions Session[]
}

model Account {
  id                String  @id @default(cuid())
  userId            Int
  type              String
  provider          String
  providerAccountId String
  refresh_token     String? @db.Text
  access_token      String? @db.Text
  expires_at        Int?
  token_type        String?
  scope             String?
  id_token          String? @db.Text
  session_state     String?

  user User @relation(fields: [userId], references: [id], onDelete: Cascade)

  @@unique([provider, providerAccountId])
}

model Session {
  id           String   @id @default(cuid())
  sessionToken String   @unique
  userId       Int
  expires      DateTime
  user         User     @relation(fields: [userId], references: [id], onDelete: Cascade)

  @@map("sessions")
}

model VerificationToken {
  identifier String
  token      String   @unique
  expires    DateTime

  @@unique([identifier, token])
}

3. Setup Authentication

Create lib/auth.ts:

import { createAuth, AuthConfig } from '@webdevarif/auth';

const authConfig: AuthConfig = {
  databaseUrl: process.env.DATABASE_URL!,
  nextAuthSecret: process.env.NEXTAUTH_SECRET!,
  nextAuthUrl: process.env.NEXTAUTH_URL!,
  
  // Optional: Google OAuth
  google: {
    clientId: process.env.AUTH_GOOGLE_ID!,
    clientSecret: process.env.AUTH_GOOGLE_SECRET!,
  },
  
  // Optional: Email configuration
  email: {
    from: process.env.EMAIL_FROM!,
    server: {
      host: process.env.EMAIL_SERVER_HOST!,
      port: parseInt(process.env.EMAIL_SERVER_PORT!),
      auth: {
        user: process.env.EMAIL_SERVER_USER!,
        pass: process.env.EMAIL_SERVER_PASSWORD!,
      },
    },
  },
  
  // Optional: Custom pages
  pages: {
    signIn: '/auth/login',
    error: '/auth/error',
    verifyRequest: '/auth/verify-email',
  },
};

export const { auth, handlers, signIn, signOut } = createAuth(authConfig);

4. Setup API Routes

Create app/api/auth/[...nextauth]/route.ts:

import { handlers } from '@/lib/auth';

export const { GET, POST } = handlers;

5. Setup Middleware

Create middleware.ts:

import { createAuthMiddleware, AuthMiddlewareConfig } from '@webdevarif/auth';
import { authConfig } from '@/lib/auth';

const middlewareConfig: AuthMiddlewareConfig = {
  protectedRoutes: ['/dashboard', '/profile'],
  authRoutes: ['/auth/login', '/auth/register'],
  publicRoutes: ['/', '/about', '/contact'],
  apiRoutes: ['/api'],
  defaultLoginRedirect: '/dashboard',
  loginPath: '/auth/login',
};

export default createAuthMiddleware(authConfig, middlewareConfig);

export const config = {
  matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)'],
};

6. Create Authentication Pages

Create app/auth/login/page.tsx:

'use client';

import { LoginPage } from '@webdevarif/auth';
import { authConfig } from '@/lib/auth';

export default function Login() {
  return (
    <LoginPage
      config={authConfig}
      onSubmit={async (values) => {
        // Custom login logic
        const response = await fetch('/api/auth/login', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify(values),
        });
        return response.json();
      }}
      translations={{
        title: 'Sign In',
        description: 'Welcome back!',
        fields: {
          username: 'Email or Username',
          password: 'Password',
        },
      }}
    />
  );
}

Create app/auth/register/page.tsx:

'use client';

import { RegisterPage } from '@webdevarif/auth';
import { authConfig } from '@/lib/auth';

export default function Register() {
  return (
    <RegisterPage
      config={authConfig}
      onSubmit={async (values) => {
        // Custom registration logic
        const response = await fetch('/api/auth/register', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify(values),
        });
        return response.json();
      }}
      plans={[
        { handle: 'FREE', name: 'Free', price: 0, description: 'Basic features' },
        { handle: 'PRO', name: 'Pro', price: 29, description: 'All features' },
      ]}
      translations={{
        title: 'Create Account',
        description: 'Join us today!',
      }}
    />
  );
}

7. Use Authentication Hooks

'use client';

import { useAuth, useRole, useIsSuperuser } from '@webdevarif/auth';

export default function Dashboard() {
  const { user, isAuthenticated, isLoading } = useAuth();
  const isAdmin = useRole('ADMIN');
  const isSuperuser = useIsSuperuser();

  if (isLoading) return <div>Loading...</div>;
  if (!isAuthenticated) return <div>Please log in</div>;

  return (
    <div>
      <h1>Welcome, {user?.name}!</h1>
      {isAdmin && <p>Admin Panel</p>}
      {isSuperuser && <p>Superuser Access</p>}
    </div>
  );
}

API Reference

Components

LoginForm

A customizable login form component.

<LoginForm
  onSubmit={(values) => Promise<{success: boolean, error?: string}>}
  onSuccess={() => void}
  onError={(error: string) => void}
  redirectTo="/dashboard"
  showResendVerification={true}
  onResendVerification={(identifier) => Promise<{success: boolean}>}
  translations={object}
/>

RegisterForm

A customizable single-step registration form similar to Clerk.

<RegisterForm
  onSubmit={(values) => Promise<{success: boolean, error?: string}>}
  onSuccess={() => void}
  onError={(error: string) => void}
  fields={[
    {
      name: 'name',
      label: 'Full Name',
      placeholder: 'John Doe',
      type: 'text',
      required: true,
    },
    {
      name: 'username',
      label: 'Username',
      placeholder: 'johndoe',
      type: 'text',
      required: true,
      uniquenessCheck: async (value) => {
        const response = await fetch(`/api/check-username?value=${value}`);
        return response.json();
      },
    },
    {
      name: 'email',
      label: 'Email',
      placeholder: '[email protected]',
      type: 'email',
      required: true,
      uniquenessCheck: async (value) => {
        const response = await fetch(`/api/check-email?value=${value}`);
        return response.json();
      },
    },
    {
      name: 'password',
      label: 'Password',
      placeholder: 'Enter your password',
      type: 'password',
      required: true,
    },
    {
      name: 'confirmPassword',
      label: 'Confirm Password',
      placeholder: 'Confirm your password',
      type: 'password',
      required: true,
    },
  ]}
  translations={object}
  onCheckUniqueness={object}
/>

ForgotPasswordForm

A form for requesting password reset emails.

<ForgotPasswordForm
  onSubmit={(values) => Promise<{success: boolean, error?: string}>}
  onSuccess={() => void}
  onError={(error: string) => void}
  onBackToLogin={() => void}
  translations={object}
/>

ResetPasswordForm

A form for resetting passwords with a token.

<ResetPasswordForm
  onSubmit={(values) => Promise<{success: boolean, error?: string}>}
  onSuccess={() => void}
  onError={(error: string) => void}
  token="reset-token"
  translations={object}
/>

ChangePasswordForm

A form for changing passwords (requires current password).

<ChangePasswordForm
  onSubmit={(values) => Promise<{success: boolean, error?: string}>}
  onSuccess={() => void}
  onError={(error: string) => void}
  translations={object}
/>

VerifyEmailForm

A form for email verification with resend functionality.

<VerifyEmailForm
  onSubmit={(values) => Promise<{success: boolean, error?: string}>}
  onSuccess={() => void}
  onError={(error: string) => void}
  onResendVerification={() => Promise<{success: boolean}>}
  token="verification-token"
  email="[email protected]"
  translations={object}
/>

UpdateProfileForm

A form for updating user profile information.

<UpdateProfileForm
  onSubmit={(values) => Promise<{success: boolean, error?: string}>}
  onSuccess={() => void}
  onError={(error: string) => void}
  initialValues={object}
  translations={object}
  onCheckUniqueness={object}
/>

Page Components

Complete page components with layout for all forms:

  • LoginPage & RegisterPage
  • ForgotPasswordPage & ResetPasswordPage
  • ChangePasswordPage & VerifyEmailPage
  • UpdateProfilePage

Hooks

useAuth()

Returns authentication state and user information.

const { user, session, isAuthenticated, isLoading, isError, error } = useAuth();

useRole(role: string)

Checks if the current user has a specific role.

const isAdmin = useRole('ADMIN');

useIsSuperuser()

Checks if the current user is a superuser.

const isSuperuser = useIsSuperuser();

usePlan(plan: string)

Checks if the current user has a specific plan.

const isPro = usePlan('PRO');

useIsActive()

Checks if the current user account is active.

const isActive = useIsActive();

Services

AuthService

Core authentication service with database operations.

import { AuthService } from '@webdevarif/auth';

// Initialize with database URL
AuthService.initialize(process.env.DATABASE_URL!);

// Get user by identifier
const user = await AuthService.getUserByIdentifier('[email protected]');

// Create new user
const result = await AuthService.createUser({
  name: 'John Doe',
  username: 'johndoe',
  email: '[email protected]',
  password: 'password123',
  phone: '+1234567890',
});

// Verify credentials
const authResult = await AuthService.verifyCredentials('username', 'password');

Middleware

createAuthMiddleware(config, middlewareConfig)

Creates authentication middleware for route protection.

const middleware = createAuthMiddleware(authConfig, {
  protectedRoutes: ['/dashboard'],
  authRoutes: ['/auth/login'],
  publicRoutes: ['/'],
  apiRoutes: ['/api'],
  defaultLoginRedirect: '/dashboard',
  loginPath: '/auth/login',
});

Configuration

AuthConfig Interface

interface AuthConfig {
  // Required
  databaseUrl: string;
  nextAuthSecret: string;
  nextAuthUrl: string;
  
  // Optional
  google?: {
    clientId: string;
    clientSecret: string;
  };
  
  email?: {
    from: string;
    server: {
      host: string;
      port: number;
      auth: {
        user: string;
        pass: string;
      };
    };
  };
  
  pages?: {
    signIn?: string;
    error?: string;
    verifyRequest?: string;
  };
  
  callbacks?: {
    signIn?: (params: {user: AuthUser, account: any}) => boolean | Promise<boolean>;
    jwt?: (params: {token: any, user: AuthUser, account: any}) => any;
    session?: (params: {session: AuthSession, token: any}) => AuthSession;
  };
  
  events?: {
    linkAccount?: (params: {user: AuthUser, account: any}) => void | Promise<void>;
  };
}

Customization

Custom Styling

The package uses Tailwind CSS classes. You can customize the appearance by:

  1. Overriding CSS classes in your global styles
  2. Using the className prop on components
  3. Creating custom themes with Tailwind configuration

Custom Translations

All text is customizable through the translations prop:

const translations = {
  title: 'Custom Login Title',
  description: 'Custom description',
  fields: {
    username: 'Custom Username Label',
    password: 'Custom Password Label',
  },
  submit: 'Custom Submit Button',
  // ... more translations
};

Custom Validation

You can provide custom validation functions:

<RegisterForm
  onCheckUniqueness={{
    username: async (value) => {
      const response = await fetch(`/api/check-username?value=${value}`);
      return response.json();
    },
    email: async (value) => {
      const response = await fetch(`/api/check-email?value=${value}`);
      return response.json();
    },
  }}
/>

Examples

Check out the examples directory for complete implementation examples:

Contributing

Contributions are welcome! Please read our Contributing Guide for details.

License

This project is licensed under the MIT License - see the LICENSE file for details.

Support

Changelog

See CHANGELOG.md for a list of changes and version history.