@liedsonc/core-auth-kit 0.1.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/README.md +802 -759
  2. package/auth-ui/bin/init.js +126 -0
  3. package/auth-ui/components/auth-card.tsx +49 -49
  4. package/auth-ui/components/auth-form.tsx +53 -53
  5. package/auth-ui/components/error-message.tsx +24 -24
  6. package/auth-ui/components/form-field.tsx +39 -39
  7. package/auth-ui/components/loading-spinner.tsx +19 -19
  8. package/auth-ui/components/oauth-buttons.tsx +49 -49
  9. package/auth-ui/components/password-input.tsx +93 -93
  10. package/auth-ui/components/success-message.tsx +24 -24
  11. package/auth-ui/package.json +59 -55
  12. package/auth-ui/pages/forgot-password/index.tsx +83 -83
  13. package/auth-ui/pages/login/index.tsx +119 -119
  14. package/auth-ui/pages/register/index.tsx +149 -149
  15. package/auth-ui/pages/reset-password/index.tsx +133 -133
  16. package/auth-ui/pages/verify-email/index.tsx +143 -143
  17. package/auth-ui/templates/app/(auth)/forgot-password/page.tsx +5 -0
  18. package/auth-ui/templates/app/(auth)/layout.tsx +12 -0
  19. package/auth-ui/templates/app/(auth)/login/page.tsx +5 -0
  20. package/auth-ui/templates/app/(auth)/register/page.tsx +5 -0
  21. package/auth-ui/templates/app/(auth)/reset-password/page.tsx +5 -0
  22. package/auth-ui/templates/app/(auth)/verify-email/page.tsx +5 -0
  23. package/auth-ui/templates/app/api/auth/forgot-password/route.ts +16 -0
  24. package/auth-ui/templates/app/api/auth/login/route.ts +16 -0
  25. package/auth-ui/templates/app/api/auth/logout/route.ts +8 -0
  26. package/auth-ui/templates/app/api/auth/register/route.ts +16 -0
  27. package/auth-ui/templates/app/api/auth/reset-password/route.ts +16 -0
  28. package/auth-ui/templates/app/api/auth/session/route.ts +8 -0
  29. package/auth-ui/templates/app/api/auth/verify-email/route.ts +16 -0
  30. package/auth-ui/templates/env.example +25 -0
  31. package/auth-ui/templates/lib/auth-client.ts +20 -0
  32. package/auth-ui/templates/lib/auth-config.ts +43 -0
  33. package/auth-ui/tsconfig.json +4 -15
  34. package/package.json +17 -6
  35. package/tailwind.config.ts +41 -41
package/README.md CHANGED
@@ -1,759 +1,802 @@
1
- # @liedsonc/core-auth-kit
2
-
3
- Production-ready authentication UI package for Next.js App Router. Built with TypeScript, React Server Components, and shadcn/ui. Provides ready-to-use authentication pages and components that integrate with any backend via a simple `AuthClient` interface.
4
-
5
- ## Features
6
-
7
- - 🔐 **Complete Auth Flows** - Login, Register, Forgot Password, Reset Password, Email Verification
8
- - 🎨 **Beautiful UI** - Built with shadcn/ui components, fully themeable and accessible
9
- - 🔌 **Backend Agnostic** - Works with any authentication backend via `AuthClient` interface
10
- - 📱 **Mobile-First** - Responsive design that works on all devices
11
- - ♿ **Accessible** - WCAG compliant with proper ARIA attributes and keyboard navigation
12
- - 🎯 **Type-Safe** - Full TypeScript support with strict typing
13
- - 🚀 **Zero Config** - Works out-of-the-box with sensible defaults
14
- - 🎨 **Customizable** - Override components, styles, and behavior as needed
15
- - 🌙 **Dark Mode** - Built-in dark mode support via Tailwind CSS
16
- - ⚙️ **Environment Configurable** - OAuth providers and settings via environment variables
17
- - 📧 **Email Integration** - Built-in Resend email service support for verification and password reset emails
18
-
19
- ## Installation
20
-
21
- Simply install the package - all UI dependencies will be installed automatically:
22
-
23
- ```bash
24
- npm install @liedsonc/core-auth-kit
25
- ```
26
-
27
- ### Peer Dependencies
28
-
29
- The following peer dependencies are required but should already be installed in your Next.js project:
30
-
31
- - `next` (^15.0.0) - Next.js framework
32
- - `react` (^19.0.0) - React library
33
- - `react-dom` (^19.0.0) - React DOM library
34
-
35
- If you're not using Next.js or these aren't installed, install them:
36
-
37
- ```bash
38
- npm install next react react-dom
39
- ```
40
-
41
- **Note:** The following dependencies are automatically installed with the package:
42
- - `@radix-ui/react-label` - For accessible form labels
43
- - `@radix-ui/react-slot` - For component composition
44
- - `class-variance-authority` - For component variants
45
- - `clsx` - For conditional class names
46
- - `tailwind-merge` - For merging Tailwind classes
47
-
48
- ### Email Service (Optional)
49
-
50
- For email verification and password reset functionality, install Resend:
51
-
52
- ```bash
53
- npm install resend
54
- ```
55
-
56
- ### shadcn/ui Components
57
-
58
- The package includes shadcn/ui components by default. Ensure your project has the shadcn/ui setup:
59
-
60
- 1. Install shadcn/ui components (if not already installed):
61
- ```bash
62
- npx shadcn@latest add button input card label
63
- ```
64
-
65
- 2. Ensure your `tailwind.config.ts` includes the auth-ui styles:
66
- ```ts
67
- import type { Config } from "tailwindcss";
68
-
69
- const config: Config = {
70
- content: [
71
- "./app/**/*.{js,ts,jsx,tsx,mdx}",
72
- "./components/**/*.{js,ts,jsx,tsx,mdx}",
73
- "./node_modules/@liedsonc/core-auth-kit/**/*.{js,ts,jsx,tsx}",
74
- ],
75
- // ... rest of config
76
- };
77
- ```
78
-
79
- 3. Import the styles in your root layout:
80
- ```tsx
81
- import "@liedsonc/core-auth-kit/styles";
82
- ```
83
-
84
- ## Environment Variables
85
-
86
- Create a `.env.local` file (or `.env`) with the following variables:
87
-
88
- ```bash
89
- NEXT_PUBLIC_APP_URL=http://localhost:3000
90
-
91
- NEXT_PUBLIC_AUTH_REDIRECT_AFTER_LOGIN=/
92
- NEXT_PUBLIC_AUTH_REDIRECT_AFTER_REGISTER=/login
93
- NEXT_PUBLIC_AUTH_REDIRECT_AFTER_RESET=/login
94
-
95
- NEXT_PUBLIC_OAUTH_GOOGLE_ENABLED=false
96
- NEXT_PUBLIC_OAUTH_GOOGLE_CLIENT_ID=your_google_client_id
97
- NEXT_PUBLIC_OAUTH_GOOGLE_REDIRECT_URI=http://localhost:3000/api/auth/google
98
- OAUTH_GOOGLE_CLIENT_SECRET=your_google_client_secret
99
-
100
- NEXT_PUBLIC_OAUTH_APPLE_ENABLED=false
101
- NEXT_PUBLIC_OAUTH_APPLE_CLIENT_ID=your_apple_client_id
102
- NEXT_PUBLIC_OAUTH_APPLE_REDIRECT_URI=http://localhost:3000/api/auth/apple
103
- OAUTH_APPLE_CLIENT_SECRET=your_apple_client_secret
104
-
105
- RESEND_API_KEY=re_your_resend_api_key
106
- RESEND_FROM_EMAIL=noreply@yourdomain.com
107
- RESEND_FROM_NAME=Your App Name
108
- NEXT_PUBLIC_APP_NAME=Your App Name
109
- ```
110
-
111
- ### Environment Variable Reference
112
-
113
- | Variable | Description | Required | Default |
114
- |----------|-------------|----------|---------|
115
- | `NEXT_PUBLIC_APP_URL` | Your application base URL | No | `http://localhost:3000` |
116
- | `NEXT_PUBLIC_AUTH_REDIRECT_AFTER_LOGIN` | Redirect URL after successful login | No | `/` |
117
- | `NEXT_PUBLIC_AUTH_REDIRECT_AFTER_REGISTER` | Redirect URL after registration | No | `/login` |
118
- | `NEXT_PUBLIC_AUTH_REDIRECT_AFTER_RESET` | Redirect URL after password reset | No | `/login` |
119
- | `NEXT_PUBLIC_OAUTH_GOOGLE_ENABLED` | Enable/disable Google OAuth | No | `false` |
120
- | `NEXT_PUBLIC_OAUTH_GOOGLE_CLIENT_ID` | Google OAuth Client ID | Yes (if Google enabled) | - |
121
- | `NEXT_PUBLIC_OAUTH_GOOGLE_REDIRECT_URI` | Google OAuth redirect URI | Yes (if Google enabled) | - |
122
- | `OAUTH_GOOGLE_CLIENT_SECRET` | Google OAuth Client Secret (server-only) | Yes (if Google enabled) | - |
123
- | `NEXT_PUBLIC_OAUTH_APPLE_ENABLED` | Enable/disable Apple OAuth | No | `false` |
124
- | `NEXT_PUBLIC_OAUTH_APPLE_CLIENT_ID` | Apple OAuth Client ID | Yes (if Apple enabled) | - |
125
- | `NEXT_PUBLIC_OAUTH_APPLE_REDIRECT_URI` | Apple OAuth redirect URI | Yes (if Apple enabled) | - |
126
- | `OAUTH_APPLE_CLIENT_SECRET` | Apple OAuth Client Secret (server-only) | Yes (if Apple enabled) | - |
127
- | `RESEND_API_KEY` | Resend API key for sending emails | Yes (if using email features) | - |
128
- | `RESEND_FROM_EMAIL` | Email address to send from (must be verified in Resend) | Yes (if using email features) | - |
129
- | `RESEND_FROM_NAME` | Display name for email sender | No | - |
130
- | `NEXT_PUBLIC_APP_NAME` | Your application name (used in emails) | No | `App` |
131
-
132
- **Note:** Variables prefixed with `NEXT_PUBLIC_` are exposed to the browser. Secrets should NOT use this prefix.
133
-
134
- ## Quick Start
135
-
136
- ### 1. Implement AuthClient
137
-
138
- Create an `AuthClient` that connects to your backend:
139
-
140
- ```typescript
141
- import type { AuthClient } from "@liedsonc/core-auth-kit";
142
-
143
- export const myAuthClient: AuthClient = {
144
- async login(email, password) {
145
- const response = await fetch("/api/auth/login", {
146
- method: "POST",
147
- headers: { "Content-Type": "application/json" },
148
- body: JSON.stringify({ email, password }),
149
- });
150
-
151
- if (!response.ok) {
152
- return {
153
- success: false,
154
- error: { code: "INVALID_CREDENTIALS", message: "Invalid email or password" },
155
- };
156
- }
157
-
158
- return { success: true };
159
- },
160
-
161
- async register(email, password) {
162
- const response = await fetch("/api/auth/register", {
163
- method: "POST",
164
- headers: { "Content-Type": "application/json" },
165
- body: JSON.stringify({ email, password }),
166
- });
167
-
168
- if (!response.ok) {
169
- const data = await response.json();
170
- return {
171
- success: false,
172
- error: { code: data.code || "REGISTRATION_FAILED", message: data.message },
173
- };
174
- }
175
-
176
- return { success: true };
177
- },
178
-
179
- async logout() {
180
- await fetch("/api/auth/logout", { method: "POST" });
181
- },
182
-
183
- async forgotPassword(email) {
184
- const response = await fetch("/api/auth/forgot-password", {
185
- method: "POST",
186
- headers: { "Content-Type": "application/json" },
187
- body: JSON.stringify({ email }),
188
- });
189
-
190
- return response.ok ? { success: true } : {
191
- success: false,
192
- error: { code: "FAILED", message: "Failed to send reset email" },
193
- };
194
- },
195
-
196
- async resetPassword(token, newPassword) {
197
- const response = await fetch("/api/auth/reset-password", {
198
- method: "POST",
199
- headers: { "Content-Type": "application/json" },
200
- body: JSON.stringify({ token, newPassword }),
201
- });
202
-
203
- if (!response.ok) {
204
- return {
205
- success: false,
206
- error: { code: "INVALID_TOKEN", message: "Invalid or expired token" },
207
- };
208
- }
209
-
210
- return { success: true };
211
- },
212
-
213
- async verifyEmail(token) {
214
- const response = await fetch("/api/auth/verify-email", {
215
- method: "POST",
216
- headers: { "Content-Type": "application/json" },
217
- body: JSON.stringify({ token }),
218
- });
219
-
220
- if (!response.ok) {
221
- const data = await response.json();
222
- return {
223
- success: false,
224
- error: { code: data.code || "INVALID", message: data.message },
225
- };
226
- }
227
-
228
- return { success: true };
229
- },
230
-
231
- async getSession() {
232
- const response = await fetch("/api/auth/session");
233
- if (!response.ok) return null;
234
- return response.json();
235
- },
236
- };
237
- ```
238
-
239
- ### 2. Setup Provider with Environment Variables
240
-
241
- Create a utility to load OAuth config from environment variables:
242
-
243
- ```typescript
244
- // lib/oauth-config.ts
245
- import type { OAuthProvider } from "@liedsonc/core-auth-kit";
246
-
247
- export interface OAuthProviderConfig {
248
- provider: OAuthProvider;
249
- enabled: boolean;
250
- clientId?: string;
251
- redirectUri?: string;
252
- }
253
-
254
- export function getOAuthProvidersFromEnv(): OAuthProviderConfig[] {
255
- const providers: OAuthProviderConfig[] = [];
256
-
257
- if (process.env.NEXT_PUBLIC_OAUTH_GOOGLE_ENABLED === "true") {
258
- providers.push({
259
- provider: "google",
260
- enabled: true,
261
- clientId: process.env.NEXT_PUBLIC_OAUTH_GOOGLE_CLIENT_ID,
262
- redirectUri: process.env.NEXT_PUBLIC_OAUTH_GOOGLE_REDIRECT_URI,
263
- });
264
- }
265
-
266
- if (process.env.NEXT_PUBLIC_OAUTH_APPLE_ENABLED === "true") {
267
- providers.push({
268
- provider: "apple",
269
- enabled: true,
270
- clientId: process.env.NEXT_PUBLIC_OAUTH_APPLE_CLIENT_ID,
271
- redirectUri: process.env.NEXT_PUBLIC_OAUTH_APPLE_REDIRECT_URI,
272
- });
273
- }
274
-
275
- return providers;
276
- }
277
- ```
278
-
279
- Wrap your auth routes with `AuthUIProvider`:
280
-
281
- ```tsx
282
- // app/(auth)/layout.tsx
283
- "use client";
284
-
285
- import { AuthUIProvider } from "@liedsonc/core-auth-kit";
286
- import { myAuthClient } from "@/lib/auth-client";
287
- import { getOAuthProvidersFromEnv } from "@/lib/oauth-config";
288
-
289
- export default function AuthLayout({ children }: { children: React.ReactNode }) {
290
- return (
291
- <AuthUIProvider
292
- config={{
293
- authClient: myAuthClient,
294
- oauthProviders: getOAuthProvidersFromEnv(),
295
- redirectAfterLogin: process.env.NEXT_PUBLIC_AUTH_REDIRECT_AFTER_LOGIN || "/",
296
- redirectAfterRegister: process.env.NEXT_PUBLIC_AUTH_REDIRECT_AFTER_REGISTER || "/login",
297
- redirectAfterReset: process.env.NEXT_PUBLIC_AUTH_REDIRECT_AFTER_RESET || "/login",
298
- }}
299
- >
300
- {children}
301
- </AuthUIProvider>
302
- );
303
- }
304
- ```
305
-
306
- ### 3. Create Auth Pages
307
-
308
- Use the pre-built page components:
309
-
310
- ```tsx
311
- // app/(auth)/login/page.tsx
312
- import { LoginPage } from "@liedsonc/core-auth-kit";
313
-
314
- export default function Login() {
315
- return <LoginPage />;
316
- }
317
- ```
318
-
319
- ```tsx
320
- // app/(auth)/register/page.tsx
321
- import { RegisterPage } from "@liedsonc/core-auth-kit";
322
-
323
- export default function Register() {
324
- return <RegisterPage />;
325
- }
326
- ```
327
-
328
- ```tsx
329
- // app/(auth)/forgot-password/page.tsx
330
- import { ForgotPasswordPage } from "@liedsonc/core-auth-kit";
331
-
332
- export default function ForgotPassword() {
333
- return <ForgotPasswordPage />;
334
- }
335
- ```
336
-
337
- ```tsx
338
- // app/(auth)/reset-password/page.tsx
339
- import { ResetPasswordPage } from "@liedsonc/core-auth-kit";
340
-
341
- export default function ResetPassword() {
342
- return <ResetPasswordPage />;
343
- }
344
- ```
345
-
346
- ```tsx
347
- // app/(auth)/verify-email/page.tsx
348
- import { VerifyEmailPage } from "@liedsonc/core-auth-kit";
349
-
350
- export default function VerifyEmail() {
351
- return <VerifyEmailPage />;
352
- }
353
- ```
354
-
355
- ## Email Integration with Resend
356
-
357
- The package includes utilities for sending verification and password reset emails via Resend. Here's how to integrate it:
358
-
359
- ### 1. Setup Resend
360
-
361
- 1. Sign up for a [Resend account](https://resend.com)
362
- 2. Get your API key from the dashboard
363
- 3. Verify your domain (or use Resend's test domain for development)
364
- 4. Add your credentials to `.env.local`:
365
-
366
- ```bash
367
- RESEND_API_KEY=re_your_api_key_here
368
- RESEND_FROM_EMAIL=noreply@yourdomain.com
369
- RESEND_FROM_NAME=Your App Name
370
- NEXT_PUBLIC_APP_NAME=Your App Name
371
- ```
372
-
373
- ### 2. Use Resend Email Service
374
-
375
- Import and use the Resend email service in your AuthClient implementation:
376
-
377
- ```typescript
378
- // lib/auth-client.ts
379
- import type { AuthClient } from "@liedsonc/core-auth-kit";
380
- import { createResendEmailService } from "@/lib/resend-email";
381
- import { randomBytes } from "crypto";
382
-
383
- const emailService = createResendEmailService({
384
- apiKey: process.env.RESEND_API_KEY!,
385
- from: process.env.RESEND_FROM_EMAIL!,
386
- fromName: process.env.RESEND_FROM_NAME,
387
- appName: process.env.NEXT_PUBLIC_APP_NAME || "App",
388
- });
389
-
390
- const appUrl = process.env.NEXT_PUBLIC_APP_URL || "http://localhost:3000";
391
-
392
- export const myAuthClient: AuthClient = {
393
- async register(email, password) {
394
- // Your registration logic here
395
- // ... save user to database
396
-
397
- // Generate verification token
398
- const token = randomBytes(32).toString("hex");
399
- // Store token in database with expiration
400
- // await db.verificationTokens.create({ email, token, expiresAt: ... });
401
-
402
- // Send verification email
403
- const verificationUrl = `${appUrl}/verify-email?token=${token}`;
404
- const emailResult = await emailService.sendVerificationEmail({
405
- email,
406
- token,
407
- verificationUrl,
408
- });
409
-
410
- if (!emailResult.success) {
411
- return {
412
- success: false,
413
- error: { code: "EMAIL_SEND_FAILED", message: "Failed to send verification email" },
414
- };
415
- }
416
-
417
- return { success: true };
418
- },
419
-
420
- async forgotPassword(email) {
421
- // Generate reset token
422
- const token = randomBytes(32).toString("hex");
423
- // Store token in database with expiration (e.g., 1 hour)
424
- // await db.resetTokens.create({ email, token, expiresAt: ... });
425
-
426
- // Send password reset email
427
- const resetUrl = `${appUrl}/reset-password?token=${token}`;
428
- const emailResult = await emailService.sendPasswordResetEmail({
429
- email,
430
- token,
431
- resetUrl,
432
- expiresIn: "1 hour",
433
- });
434
-
435
- if (!emailResult.success) {
436
- return {
437
- success: false,
438
- error: { code: "EMAIL_SEND_FAILED", message: "Failed to send reset email" },
439
- };
440
- }
441
-
442
- return { success: true };
443
- },
444
-
445
- // ... other AuthClient methods
446
- };
447
- ```
448
-
449
- ### 3. Example Implementation
450
-
451
- See `lib/auth-client-with-resend.ts` for a complete example implementation that includes:
452
- - Token generation and validation
453
- - Email sending with Resend
454
- - Token expiration handling
455
- - Error handling
456
-
457
- ### 4. Customizing Email Templates
458
-
459
- The email templates are built into the `ResendEmailService` class. To customize them:
460
-
461
- 1. Extend the `ResendEmailService` class
462
- 2. Override the template methods (`getVerificationEmailTemplate`, `getPasswordResetEmailTemplate`)
463
- 3. Use your custom service instance
464
-
465
- ```typescript
466
- class CustomEmailService extends ResendEmailService {
467
- private getVerificationEmailTemplate({ verificationUrl, appName }: { verificationUrl: string; appName: string }): string {
468
- // Your custom HTML template
469
- return `...`;
470
- }
471
- }
472
- ```
473
-
474
- ### 5. Email Service API
475
-
476
- ```typescript
477
- import { createResendEmailService, ResendEmailService } from "@/lib/resend-email";
478
-
479
- // Create service instance
480
- const emailService = createResendEmailService({
481
- apiKey: process.env.RESEND_API_KEY!,
482
- from: process.env.RESEND_FROM_EMAIL!,
483
- fromName: "Your App",
484
- appName: "Your App Name",
485
- });
486
-
487
- // Send verification email
488
- await emailService.sendVerificationEmail({
489
- email: "user@example.com",
490
- token: "verification_token",
491
- verificationUrl: "https://yourapp.com/verify-email?token=...",
492
- appName: "Your App", // Optional, uses service default if not provided
493
- });
494
-
495
- // Send password reset email
496
- await emailService.sendPasswordResetEmail({
497
- email: "user@example.com",
498
- token: "reset_token",
499
- resetUrl: "https://yourapp.com/reset-password?token=...",
500
- appName: "Your App", // Optional
501
- expiresIn: "1 hour", // Optional, default is "1 hour"
502
- });
503
- ```
504
-
505
- ## API Reference
506
-
507
- ### Components
508
-
509
- #### Pages
510
-
511
- - **`LoginPage`** - Complete login page with email/password and OAuth
512
- - **`RegisterPage`** - Registration page with password strength indicator
513
- - **`ForgotPasswordPage`** - Password reset request page
514
- - **`ResetPasswordPage`** - Password reset form (requires token query param)
515
- - **`VerifyEmailPage`** - Email verification page (requires token query param)
516
-
517
- #### UI Components
518
-
519
- - **`AuthCard`** - Reusable card layout for auth pages
520
- - **`AuthForm`** - Form wrapper with loading/error states
521
- - **`FormField`** - Form field with label and error display
522
- - **`PasswordInput`** - Password input with show/hide toggle and strength indicator
523
- - **`OAuthButtons`** - OAuth provider buttons (Google, Apple)
524
- - **`ErrorMessage`** - Error message display component
525
- - **`SuccessMessage`** - Success message display component
526
- - **`LoadingSpinner`** - Loading spinner component
527
-
528
- ### Hooks
529
-
530
- #### `useAuth()`
531
-
532
- Main authentication hook that provides all auth methods:
533
-
534
- ```typescript
535
- const {
536
- login, // (email: string, password: string) => Promise<AuthResult>
537
- register, // (email: string, password: string) => Promise<AuthResult>
538
- logout, // () => Promise<void>
539
- forgotPassword, // (email: string) => Promise<AuthResult>
540
- resetPassword, // (token: string, newPassword: string) => Promise<AuthResult>
541
- verifyEmail, // (token: string) => Promise<AuthResult>
542
- session, // AuthSession | null
543
- loadSession, // () => Promise<AuthSession | null>
544
- loading, // boolean
545
- error, // AuthError | null
546
- clearError, // () => void
547
- } = useAuth();
548
- ```
549
-
550
- #### `useOAuth(onRedirect)`
551
-
552
- OAuth authentication hook:
553
-
554
- ```typescript
555
- const { signIn, loadingProvider } = useOAuth(
556
- (provider) => `/api/auth/${provider}`
557
- );
558
- ```
559
-
560
- ### Types
561
-
562
- ```typescript
563
- interface AuthClient {
564
- login: (email: string, password: string) => Promise<AuthResult>;
565
- register: (email: string, password: string) => Promise<AuthResult>;
566
- logout: () => Promise<void>;
567
- forgotPassword: (email: string) => Promise<AuthResult>;
568
- resetPassword: (token: string, newPassword: string) => Promise<AuthResult>;
569
- verifyEmail: (token: string) => Promise<AuthResult>;
570
- getSession?: () => Promise<AuthSession | null>;
571
- }
572
-
573
- interface AuthUIConfig {
574
- authClient: AuthClient;
575
- oauthProviders?: { provider: OAuthProvider; enabled: boolean }[];
576
- logo?: ReactNode;
577
- redirectAfterLogin?: string;
578
- redirectAfterRegister?: string;
579
- redirectAfterReset?: string;
580
- }
581
-
582
- type AuthResult =
583
- | { success: true }
584
- | { success: false; error: AuthError };
585
-
586
- interface AuthError {
587
- code: string;
588
- message: string;
589
- }
590
-
591
- type OAuthProvider = "google" | "apple";
592
- ```
593
-
594
- ## Customization
595
-
596
- ### Custom Logo
597
-
598
- ```tsx
599
- <AuthUIProvider
600
- config={{
601
- authClient: myAuthClient,
602
- logo: <img src="/logo.svg" alt="Logo" />,
603
- }}
604
- >
605
- {children}
606
- </AuthUIProvider>
607
- ```
608
-
609
- ### OAuth Configuration via Environment Variables
610
-
611
- Enable/disable OAuth providers and configure credentials via environment variables:
612
-
613
- ```bash
614
- NEXT_PUBLIC_OAUTH_GOOGLE_ENABLED=true
615
- NEXT_PUBLIC_OAUTH_GOOGLE_CLIENT_ID=your_client_id
616
- NEXT_PUBLIC_OAUTH_GOOGLE_REDIRECT_URI=https://yourapp.com/api/auth/google
617
- OAUTH_GOOGLE_CLIENT_SECRET=your_client_secret
618
- ```
619
-
620
- The `getOAuthProvidersFromEnv()` utility automatically reads these and configures providers.
621
-
622
- ### Custom Redirects
623
-
624
- Set redirects via environment variables or config:
625
-
626
- ```tsx
627
- <AuthUIProvider
628
- config={{
629
- authClient: myAuthClient,
630
- redirectAfterLogin: process.env.NEXT_PUBLIC_AUTH_REDIRECT_AFTER_LOGIN || "/dashboard",
631
- redirectAfterRegister: process.env.NEXT_PUBLIC_AUTH_REDIRECT_AFTER_REGISTER || "/onboarding",
632
- redirectAfterReset: process.env.NEXT_PUBLIC_AUTH_REDIRECT_AFTER_RESET || "/login?reset=success",
633
- }}
634
- >
635
- {children}
636
- </AuthUIProvider>
637
- ```
638
-
639
- ### Using Individual Components
640
-
641
- You can also use components individually to build custom pages:
642
-
643
- ```tsx
644
- import { AuthCard, AuthForm, FormField, PasswordInput, Button } from "@liedsonc/core-auth-kit";
645
-
646
- export function CustomLoginPage() {
647
- return (
648
- <AuthCard title="Sign In">
649
- <AuthForm onSubmit={handleSubmit}>
650
- <FormField label="Email" htmlFor="email">
651
- <Input id="email" type="email" />
652
- </FormField>
653
- <FormField label="Password" htmlFor="password">
654
- <PasswordInput id="password" />
655
- </FormField>
656
- <Button type="submit">Sign In</Button>
657
- </AuthForm>
658
- </AuthCard>
659
- );
660
- }
661
- ```
662
-
663
- ## Production Setup
664
-
665
- ### 1. Environment Variables
666
-
667
- Copy `.env.example` to `.env.local` and fill in your production values:
668
-
669
- ```bash
670
- cp .env.example .env.local
671
- ```
672
-
673
- **Important:** Never commit `.env.local` to version control. Add it to `.gitignore`.
674
-
675
- ### 2. OAuth Provider Setup
676
-
677
- #### Google OAuth
678
-
679
- 1. Go to [Google Cloud Console](https://console.cloud.google.com/)
680
- 2. Create a new project or select existing
681
- 3. Enable Google+ API
682
- 4. Create OAuth 2.0 credentials
683
- 5. Add authorized redirect URIs
684
- 6. Copy Client ID and Client Secret to `.env.local`
685
-
686
- #### Apple OAuth
687
-
688
- 1. Go to [Apple Developer Portal](https://developer.apple.com/)
689
- 2. Create an App ID
690
- 3. Create a Services ID
691
- 4. Configure Sign in with Apple
692
- 5. Add redirect URIs
693
- 6. Copy Client ID and Client Secret to `.env.local`
694
-
695
- ### 3. Build and Deploy
696
-
697
- ```bash
698
- npm run build
699
- npm start
700
- ```
701
-
702
- ## Styling
703
-
704
- The package uses Tailwind CSS and follows shadcn/ui conventions. Customize colors via CSS variables:
705
-
706
- ```css
707
- :root {
708
- --primary: 222.2 47.4% 11.2%;
709
- --primary-foreground: 210 40% 98%;
710
- /* ... other variables */
711
- }
712
- ```
713
-
714
- See [shadcn/ui theming](https://ui.shadcn.com/docs/theming) for details.
715
-
716
- ## Security Considerations
717
-
718
- - **No User Enumeration**: Error messages don't reveal if an email exists
719
- - **Secure Defaults**: Password inputs prevent autofill leaks
720
- - **CSRF Protection**: Implement CSRF tokens in your `AuthClient`
721
- - **Rate Limiting**: Implement rate limiting in your backend
722
- - **Token Security**: Handle tokens securely in your `AuthClient`
723
- - **Environment Variables**: Never expose secrets in client-side code (use `NEXT_PUBLIC_` prefix only for public values)
724
-
725
- ## Browser Support
726
-
727
- - Chrome (latest)
728
- - Firefox (latest)
729
- - Safari (latest)
730
- - Edge (latest)
731
-
732
- ## Project Structure
733
-
734
- ```
735
- core-auth-kit/
736
- ├── auth-ui/ # Package source code
737
- │ ├── components/ # UI components
738
- │ ├── hooks/ # React hooks
739
- │ ├── pages/ # Page components
740
- │ ├── types/ # TypeScript types
741
- │ ├── styles/ # CSS styles
742
- │ └── index.ts # Main export
743
- ├── app/ # Example Next.js app
744
- ├── lib/ # Utilities (oauth-config, auth-client)
745
- ├── .env.example # Environment variables template
746
- └── README.md # This file
747
- ```
748
-
749
- ## Contributing
750
-
751
- Contributions are welcome! Please read our contributing guidelines first.
752
-
753
- ## License
754
-
755
- MIT
756
-
757
- ## Support
758
-
759
- For issues, questions, or contributions, please open an issue on GitHub.
1
+ # @liedsonc/core-auth-kit
2
+
3
+ This is a core authentication UI package for Next.js for lazy people like me 😂.
4
+
5
+ I don't want to make Login, Register, and Forgot Password page for every project 🤢 (sooooo boring).
6
+ That's why I created this package that makes all UI using my fav tech's `shadcn/ui`, `Tailwind CSS`, `Resend` for mailing.
7
+ Make my auth UI with a single command, and it is also customizable for your project. Just install the package and connect it with the services keys.
8
+
9
+
10
+ ## Features
11
+
12
+ - 🔐 **Complete Auth Flows** - Login, Register, Forgot Password, Reset Password, Email Verification
13
+ - 🎨 **Beautiful UI** - Built with shadcn/ui components, fully themeable and accessible
14
+ - 🔌 **Backend Agnostic** - Works with any authentication backend via `AuthClient` interface
15
+ - 📱 **Mobile-First** - Responsive design that works on all devices
16
+ - **Accessible** - WCAG compliant with proper ARIA attributes and keyboard navigation
17
+ - 🎯 **Type-Safe** - Full TypeScript support with strict typing
18
+ - 🚀 **Zero Config** - Works out-of-the-box with sensible defaults
19
+ - 🎨 **Customizable** - Override components, styles, and behavior as needed
20
+ - 🌙 **Dark Mode** - Built-in dark mode support via Tailwind CSS
21
+ - ⚙️ **Environment Configurable** - OAuth providers and settings via environment variables
22
+ - 📧 **Email Integration** - Built-in Resend email service support for verification and password reset emails
23
+
24
+ ## Installation
25
+
26
+ For plug-and-play, run **one command** from your Next.js app root (see [Plug and Play](#plug-and-play-recommended)):
27
+
28
+ ```bash
29
+ npx @liedsonc/core-auth-kit init
30
+ ```
31
+
32
+ Or install the package yourself; all UI dependencies are installed automatically:
33
+
34
+ ```bash
35
+ npm install @liedsonc/core-auth-kit
36
+ ```
37
+
38
+ ### Peer Dependencies
39
+
40
+ The following peer dependencies are required but should already be installed in your Next.js project:
41
+
42
+ - `next` (^15.0.0) - Next.js framework
43
+ - `react` (^19.0.0) - React library
44
+ - `react-dom` (^19.0.0) - React DOM library
45
+
46
+ If you're not using Next.js or these aren't installed, install them:
47
+
48
+ ```bash
49
+ npm install next react react-dom
50
+ ```
51
+
52
+ **Note:** The following dependencies are automatically installed with the package:
53
+ - `@radix-ui/react-label` - For accessible form labels
54
+ - `@radix-ui/react-slot` - For component composition
55
+ - `class-variance-authority` - For component variants
56
+ - `clsx` - For conditional class names
57
+ - `tailwind-merge` - For merging Tailwind classes
58
+
59
+ ### Email Service (Optional)
60
+
61
+ For email verification and password reset functionality, install Resend:
62
+
63
+ ```bash
64
+ npm install resend
65
+ ```
66
+
67
+ ### shadcn/ui Components
68
+
69
+ The package includes shadcn/ui components by default. Ensure your project has the shadcn/ui setup:
70
+
71
+ 1. Install shadcn/ui components (if not already installed):
72
+ ```bash
73
+ npx shadcn@latest add button input card label
74
+ ```
75
+
76
+ 2. Ensure your `tailwind.config.ts` includes the auth-ui styles:
77
+ ```ts
78
+ import type { Config } from "tailwindcss";
79
+
80
+ const config: Config = {
81
+ content: [
82
+ "./app/**/*.{js,ts,jsx,tsx,mdx}",
83
+ "./components/**/*.{js,ts,jsx,tsx,mdx}",
84
+ "./node_modules/@liedsonc/core-auth-kit/**/*.{js,ts,jsx,tsx}",
85
+ ],
86
+ // ... rest of config
87
+ };
88
+ ```
89
+
90
+ 3. Import the styles in your root layout:
91
+ ```tsx
92
+ import "@liedsonc/core-auth-kit/styles";
93
+ ```
94
+
95
+ ## Plug and Play (Recommended)
96
+
97
+ From your Next.js app root, a single command installs the package (if needed) and creates all auth pages, layout, config, and optional API route stubs:
98
+
99
+ ```bash
100
+ npx @liedsonc/core-auth-kit init
101
+ ```
102
+
103
+ The CLI installs `@liedsonc/core-auth-kit` when it is not already in your project, then scaffolds the files. Use `--force` to overwrite existing files. The CLI detects `app` vs `src/app` and `lib` vs `src/lib` automatically.
104
+
105
+ **Next steps:**
106
+
107
+ 1. Implement `lib/auth-client.ts` (or `src/lib/auth-client.ts`) with your backend (e.g. Supabase, custom API). The stub returns "NOT_IMPLEMENTED" until you replace it.
108
+ 2. Copy `.env.example` to `.env.local` and set your environment variables.
109
+ 3. If your `AuthClient` calls `/api/auth/*`, implement the scaffolded API routes in `app/api/auth/` (or `src/app/api/auth/`); each stub returns 501 until you wire it to your backend.
110
+ 4. Ensure Tailwind content includes the package and you import `@liedsonc/core-auth-kit/styles` in your root layout (see above).
111
+
112
+ After that, auth routes are available at `/login`, `/register`, `/forgot-password`, `/reset-password`, and `/verify-email`. The only required integration point is your `AuthClient` implementation; the rest is wiring and optional API handlers.
113
+
114
+ ### Scaffolded files
115
+
116
+ | Path | Purpose | What to do |
117
+ |------|---------|------------|
118
+ | `app/(auth)/layout.tsx` | Wraps auth routes with `AuthUIProvider` and config from `lib/auth-config.ts`. | Usually no change. |
119
+ | `app/(auth)/login/page.tsx` | Login page (and similar for register, forgot-password, reset-password, verify-email). | Usually no change. |
120
+ | `lib/auth-config.ts` | Builds `AuthUIConfig` (authClient, OAuth from env, redirects). | Edit only if you need custom redirects or OAuth config. |
121
+ | `lib/auth-client.ts` | **AuthClient implementation.** | **Replace the stub** with your real backend (Supabase, custom API, etc.). |
122
+ | `.env.example` | Example environment variables. | Copy to `.env.local` and fill in your values. |
123
+ | `app/api/auth/*/route.ts` | API route stubs (login, register, logout, forgot-password, reset-password, verify-email, session). | Implement each handler to call your backend; stubs return 501 until then. |
124
+
125
+ ## Environment Variables
126
+
127
+ Create a `.env.local` file (or `.env`) with the following variables:
128
+
129
+ ```bash
130
+ NEXT_PUBLIC_APP_URL=http://localhost:3000
131
+
132
+ NEXT_PUBLIC_AUTH_REDIRECT_AFTER_LOGIN=/
133
+ NEXT_PUBLIC_AUTH_REDIRECT_AFTER_REGISTER=/login
134
+ NEXT_PUBLIC_AUTH_REDIRECT_AFTER_RESET=/login
135
+
136
+ NEXT_PUBLIC_OAUTH_GOOGLE_ENABLED=false
137
+ NEXT_PUBLIC_OAUTH_GOOGLE_CLIENT_ID=your_google_client_id
138
+ NEXT_PUBLIC_OAUTH_GOOGLE_REDIRECT_URI=http://localhost:3000/api/auth/google
139
+ OAUTH_GOOGLE_CLIENT_SECRET=your_google_client_secret
140
+
141
+ NEXT_PUBLIC_OAUTH_APPLE_ENABLED=false
142
+ NEXT_PUBLIC_OAUTH_APPLE_CLIENT_ID=your_apple_client_id
143
+ NEXT_PUBLIC_OAUTH_APPLE_REDIRECT_URI=http://localhost:3000/api/auth/apple
144
+ OAUTH_APPLE_CLIENT_SECRET=your_apple_client_secret
145
+
146
+ RESEND_API_KEY=re_your_resend_api_key
147
+ RESEND_FROM_EMAIL=noreply@yourdomain.com
148
+ RESEND_FROM_NAME=Your App Name
149
+ NEXT_PUBLIC_APP_NAME=Your App Name
150
+ ```
151
+
152
+ ### Environment Variable Reference
153
+
154
+ | Variable | Description | Required | Default |
155
+ |----------|-------------|----------|---------|
156
+ | `NEXT_PUBLIC_APP_URL` | Your application base URL | No | `http://localhost:3000` |
157
+ | `NEXT_PUBLIC_AUTH_REDIRECT_AFTER_LOGIN` | Redirect URL after successful login | No | `/` |
158
+ | `NEXT_PUBLIC_AUTH_REDIRECT_AFTER_REGISTER` | Redirect URL after registration | No | `/login` |
159
+ | `NEXT_PUBLIC_AUTH_REDIRECT_AFTER_RESET` | Redirect URL after password reset | No | `/login` |
160
+ | `NEXT_PUBLIC_OAUTH_GOOGLE_ENABLED` | Enable/disable Google OAuth | No | `false` |
161
+ | `NEXT_PUBLIC_OAUTH_GOOGLE_CLIENT_ID` | Google OAuth Client ID | Yes (if Google enabled) | - |
162
+ | `NEXT_PUBLIC_OAUTH_GOOGLE_REDIRECT_URI` | Google OAuth redirect URI | Yes (if Google enabled) | - |
163
+ | `OAUTH_GOOGLE_CLIENT_SECRET` | Google OAuth Client Secret (server-only) | Yes (if Google enabled) | - |
164
+ | `NEXT_PUBLIC_OAUTH_APPLE_ENABLED` | Enable/disable Apple OAuth | No | `false` |
165
+ | `NEXT_PUBLIC_OAUTH_APPLE_CLIENT_ID` | Apple OAuth Client ID | Yes (if Apple enabled) | - |
166
+ | `NEXT_PUBLIC_OAUTH_APPLE_REDIRECT_URI` | Apple OAuth redirect URI | Yes (if Apple enabled) | - |
167
+ | `OAUTH_APPLE_CLIENT_SECRET` | Apple OAuth Client Secret (server-only) | Yes (if Apple enabled) | - |
168
+ | `RESEND_API_KEY` | Resend API key for sending emails | Yes (if using email features) | - |
169
+ | `RESEND_FROM_EMAIL` | Email address to send from (must be verified in Resend) | Yes (if using email features) | - |
170
+ | `RESEND_FROM_NAME` | Display name for email sender | No | - |
171
+ | `NEXT_PUBLIC_APP_NAME` | Your application name (used in emails) | No | `App` |
172
+
173
+ **Note:** Variables prefixed with `NEXT_PUBLIC_` are exposed to the browser. Secrets should NOT use this prefix.
174
+
175
+ ## Quick Start
176
+
177
+ If you ran `npx @liedsonc/core-auth-kit init`, the layout and pages already exist; go to **1. Implement AuthClient** and replace the stub in `lib/auth-client.ts` with your backend. Otherwise, follow steps 1–3 below.
178
+
179
+ ### 1. Implement AuthClient
180
+
181
+ Create an `AuthClient` that connects to your backend (or replace the stub in `lib/auth-client.ts` if you used init):
182
+
183
+ ```typescript
184
+ import type { AuthClient } from "@liedsonc/core-auth-kit";
185
+
186
+ export const myAuthClient: AuthClient = {
187
+ async login(email, password) {
188
+ const response = await fetch("/api/auth/login", {
189
+ method: "POST",
190
+ headers: { "Content-Type": "application/json" },
191
+ body: JSON.stringify({ email, password }),
192
+ });
193
+
194
+ if (!response.ok) {
195
+ return {
196
+ success: false,
197
+ error: { code: "INVALID_CREDENTIALS", message: "Invalid email or password" },
198
+ };
199
+ }
200
+
201
+ return { success: true };
202
+ },
203
+
204
+ async register(email, password) {
205
+ const response = await fetch("/api/auth/register", {
206
+ method: "POST",
207
+ headers: { "Content-Type": "application/json" },
208
+ body: JSON.stringify({ email, password }),
209
+ });
210
+
211
+ if (!response.ok) {
212
+ const data = await response.json();
213
+ return {
214
+ success: false,
215
+ error: { code: data.code || "REGISTRATION_FAILED", message: data.message },
216
+ };
217
+ }
218
+
219
+ return { success: true };
220
+ },
221
+
222
+ async logout() {
223
+ await fetch("/api/auth/logout", { method: "POST" });
224
+ },
225
+
226
+ async forgotPassword(email) {
227
+ const response = await fetch("/api/auth/forgot-password", {
228
+ method: "POST",
229
+ headers: { "Content-Type": "application/json" },
230
+ body: JSON.stringify({ email }),
231
+ });
232
+
233
+ return response.ok ? { success: true } : {
234
+ success: false,
235
+ error: { code: "FAILED", message: "Failed to send reset email" },
236
+ };
237
+ },
238
+
239
+ async resetPassword(token, newPassword) {
240
+ const response = await fetch("/api/auth/reset-password", {
241
+ method: "POST",
242
+ headers: { "Content-Type": "application/json" },
243
+ body: JSON.stringify({ token, newPassword }),
244
+ });
245
+
246
+ if (!response.ok) {
247
+ return {
248
+ success: false,
249
+ error: { code: "INVALID_TOKEN", message: "Invalid or expired token" },
250
+ };
251
+ }
252
+
253
+ return { success: true };
254
+ },
255
+
256
+ async verifyEmail(token) {
257
+ const response = await fetch("/api/auth/verify-email", {
258
+ method: "POST",
259
+ headers: { "Content-Type": "application/json" },
260
+ body: JSON.stringify({ token }),
261
+ });
262
+
263
+ if (!response.ok) {
264
+ const data = await response.json();
265
+ return {
266
+ success: false,
267
+ error: { code: data.code || "INVALID", message: data.message },
268
+ };
269
+ }
270
+
271
+ return { success: true };
272
+ },
273
+
274
+ async getSession() {
275
+ const response = await fetch("/api/auth/session");
276
+ if (!response.ok) return null;
277
+ return response.json();
278
+ },
279
+ };
280
+ ```
281
+
282
+ ### 2. Setup Provider with Environment Variables
283
+
284
+ Create a utility to load OAuth config from environment variables:
285
+
286
+ ```typescript
287
+ // lib/oauth-config.ts
288
+ import type { OAuthProvider } from "@liedsonc/core-auth-kit";
289
+
290
+ export interface OAuthProviderConfig {
291
+ provider: OAuthProvider;
292
+ enabled: boolean;
293
+ clientId?: string;
294
+ redirectUri?: string;
295
+ }
296
+
297
+ export function getOAuthProvidersFromEnv(): OAuthProviderConfig[] {
298
+ const providers: OAuthProviderConfig[] = [];
299
+
300
+ if (process.env.NEXT_PUBLIC_OAUTH_GOOGLE_ENABLED === "true") {
301
+ providers.push({
302
+ provider: "google",
303
+ enabled: true,
304
+ clientId: process.env.NEXT_PUBLIC_OAUTH_GOOGLE_CLIENT_ID,
305
+ redirectUri: process.env.NEXT_PUBLIC_OAUTH_GOOGLE_REDIRECT_URI,
306
+ });
307
+ }
308
+
309
+ if (process.env.NEXT_PUBLIC_OAUTH_APPLE_ENABLED === "true") {
310
+ providers.push({
311
+ provider: "apple",
312
+ enabled: true,
313
+ clientId: process.env.NEXT_PUBLIC_OAUTH_APPLE_CLIENT_ID,
314
+ redirectUri: process.env.NEXT_PUBLIC_OAUTH_APPLE_REDIRECT_URI,
315
+ });
316
+ }
317
+
318
+ return providers;
319
+ }
320
+ ```
321
+
322
+ Wrap your auth routes with `AuthUIProvider`:
323
+
324
+ ```tsx
325
+ // app/(auth)/layout.tsx
326
+ "use client";
327
+
328
+ import { AuthUIProvider } from "@liedsonc/core-auth-kit";
329
+ import { myAuthClient } from "@/lib/auth-client";
330
+ import { getOAuthProvidersFromEnv } from "@/lib/oauth-config";
331
+
332
+ export default function AuthLayout({ children }: { children: React.ReactNode }) {
333
+ return (
334
+ <AuthUIProvider
335
+ config={{
336
+ authClient: myAuthClient,
337
+ oauthProviders: getOAuthProvidersFromEnv(),
338
+ redirectAfterLogin: process.env.NEXT_PUBLIC_AUTH_REDIRECT_AFTER_LOGIN || "/",
339
+ redirectAfterRegister: process.env.NEXT_PUBLIC_AUTH_REDIRECT_AFTER_REGISTER || "/login",
340
+ redirectAfterReset: process.env.NEXT_PUBLIC_AUTH_REDIRECT_AFTER_RESET || "/login",
341
+ }}
342
+ >
343
+ {children}
344
+ </AuthUIProvider>
345
+ );
346
+ }
347
+ ```
348
+
349
+ ### 3. Create Auth Pages
350
+
351
+ Use the pre-built page components:
352
+
353
+ ```tsx
354
+ // app/(auth)/login/page.tsx
355
+ import { LoginPage } from "@liedsonc/core-auth-kit";
356
+
357
+ export default function Login() {
358
+ return <LoginPage />;
359
+ }
360
+ ```
361
+
362
+ ```tsx
363
+ // app/(auth)/register/page.tsx
364
+ import { RegisterPage } from "@liedsonc/core-auth-kit";
365
+
366
+ export default function Register() {
367
+ return <RegisterPage />;
368
+ }
369
+ ```
370
+
371
+ ```tsx
372
+ // app/(auth)/forgot-password/page.tsx
373
+ import { ForgotPasswordPage } from "@liedsonc/core-auth-kit";
374
+
375
+ export default function ForgotPassword() {
376
+ return <ForgotPasswordPage />;
377
+ }
378
+ ```
379
+
380
+ ```tsx
381
+ // app/(auth)/reset-password/page.tsx
382
+ import { ResetPasswordPage } from "@liedsonc/core-auth-kit";
383
+
384
+ export default function ResetPassword() {
385
+ return <ResetPasswordPage />;
386
+ }
387
+ ```
388
+
389
+ ```tsx
390
+ // app/(auth)/verify-email/page.tsx
391
+ import { VerifyEmailPage } from "@liedsonc/core-auth-kit";
392
+
393
+ export default function VerifyEmail() {
394
+ return <VerifyEmailPage />;
395
+ }
396
+ ```
397
+
398
+ ## Email Integration with Resend
399
+
400
+ The package includes utilities for sending verification and password reset emails via Resend. Here's how to integrate it:
401
+
402
+ ### 1. Setup Resend
403
+
404
+ 1. Sign up for a [Resend account](https://resend.com)
405
+ 2. Get your API key from the dashboard
406
+ 3. Verify your domain (or use Resend's test domain for development)
407
+ 4. Add your credentials to `.env.local`:
408
+
409
+ ```bash
410
+ RESEND_API_KEY=re_your_api_key_here
411
+ RESEND_FROM_EMAIL=noreply@yourdomain.com
412
+ RESEND_FROM_NAME=Your App Name
413
+ NEXT_PUBLIC_APP_NAME=Your App Name
414
+ ```
415
+
416
+ ### 2. Use Resend Email Service
417
+
418
+ Import and use the Resend email service in your AuthClient implementation:
419
+
420
+ ```typescript
421
+ // lib/auth-client.ts
422
+ import type { AuthClient } from "@liedsonc/core-auth-kit";
423
+ import { createResendEmailService } from "@/lib/resend-email";
424
+ import { randomBytes } from "crypto";
425
+
426
+ const emailService = createResendEmailService({
427
+ apiKey: process.env.RESEND_API_KEY!,
428
+ from: process.env.RESEND_FROM_EMAIL!,
429
+ fromName: process.env.RESEND_FROM_NAME,
430
+ appName: process.env.NEXT_PUBLIC_APP_NAME || "App",
431
+ });
432
+
433
+ const appUrl = process.env.NEXT_PUBLIC_APP_URL || "http://localhost:3000";
434
+
435
+ export const myAuthClient: AuthClient = {
436
+ async register(email, password) {
437
+ // Your registration logic here
438
+ // ... save user to database
439
+
440
+ // Generate verification token
441
+ const token = randomBytes(32).toString("hex");
442
+ // Store token in database with expiration
443
+ // await db.verificationTokens.create({ email, token, expiresAt: ... });
444
+
445
+ // Send verification email
446
+ const verificationUrl = `${appUrl}/verify-email?token=${token}`;
447
+ const emailResult = await emailService.sendVerificationEmail({
448
+ email,
449
+ token,
450
+ verificationUrl,
451
+ });
452
+
453
+ if (!emailResult.success) {
454
+ return {
455
+ success: false,
456
+ error: { code: "EMAIL_SEND_FAILED", message: "Failed to send verification email" },
457
+ };
458
+ }
459
+
460
+ return { success: true };
461
+ },
462
+
463
+ async forgotPassword(email) {
464
+ // Generate reset token
465
+ const token = randomBytes(32).toString("hex");
466
+ // Store token in database with expiration (e.g., 1 hour)
467
+ // await db.resetTokens.create({ email, token, expiresAt: ... });
468
+
469
+ // Send password reset email
470
+ const resetUrl = `${appUrl}/reset-password?token=${token}`;
471
+ const emailResult = await emailService.sendPasswordResetEmail({
472
+ email,
473
+ token,
474
+ resetUrl,
475
+ expiresIn: "1 hour",
476
+ });
477
+
478
+ if (!emailResult.success) {
479
+ return {
480
+ success: false,
481
+ error: { code: "EMAIL_SEND_FAILED", message: "Failed to send reset email" },
482
+ };
483
+ }
484
+
485
+ return { success: true };
486
+ },
487
+
488
+ // ... other AuthClient methods
489
+ };
490
+ ```
491
+
492
+ ### 3. Example Implementation
493
+
494
+ See `lib/auth-client-with-resend.ts` for a complete example implementation that includes:
495
+ - Token generation and validation
496
+ - Email sending with Resend
497
+ - Token expiration handling
498
+ - Error handling
499
+
500
+ ### 4. Customizing Email Templates
501
+
502
+ The email templates are built into the `ResendEmailService` class. To customize them:
503
+
504
+ 1. Extend the `ResendEmailService` class
505
+ 2. Override the template methods (`getVerificationEmailTemplate`, `getPasswordResetEmailTemplate`)
506
+ 3. Use your custom service instance
507
+
508
+ ```typescript
509
+ class CustomEmailService extends ResendEmailService {
510
+ private getVerificationEmailTemplate({ verificationUrl, appName }: { verificationUrl: string; appName: string }): string {
511
+ // Your custom HTML template
512
+ return `...`;
513
+ }
514
+ }
515
+ ```
516
+
517
+ ### 5. Email Service API
518
+
519
+ ```typescript
520
+ import { createResendEmailService, ResendEmailService } from "@/lib/resend-email";
521
+
522
+ // Create service instance
523
+ const emailService = createResendEmailService({
524
+ apiKey: process.env.RESEND_API_KEY!,
525
+ from: process.env.RESEND_FROM_EMAIL!,
526
+ fromName: "Your App",
527
+ appName: "Your App Name",
528
+ });
529
+
530
+ // Send verification email
531
+ await emailService.sendVerificationEmail({
532
+ email: "user@example.com",
533
+ token: "verification_token",
534
+ verificationUrl: "https://yourapp.com/verify-email?token=...",
535
+ appName: "Your App", // Optional, uses service default if not provided
536
+ });
537
+
538
+ // Send password reset email
539
+ await emailService.sendPasswordResetEmail({
540
+ email: "user@example.com",
541
+ token: "reset_token",
542
+ resetUrl: "https://yourapp.com/reset-password?token=...",
543
+ appName: "Your App", // Optional
544
+ expiresIn: "1 hour", // Optional, default is "1 hour"
545
+ });
546
+ ```
547
+
548
+ ## API Reference
549
+
550
+ ### Components
551
+
552
+ #### Pages
553
+
554
+ - **`LoginPage`** - Complete login page with email/password and OAuth
555
+ - **`RegisterPage`** - Registration page with password strength indicator
556
+ - **`ForgotPasswordPage`** - Password reset request page
557
+ - **`ResetPasswordPage`** - Password reset form (requires token query param)
558
+ - **`VerifyEmailPage`** - Email verification page (requires token query param)
559
+
560
+ #### UI Components
561
+
562
+ - **`AuthCard`** - Reusable card layout for auth pages
563
+ - **`AuthForm`** - Form wrapper with loading/error states
564
+ - **`FormField`** - Form field with label and error display
565
+ - **`PasswordInput`** - Password input with show/hide toggle and strength indicator
566
+ - **`OAuthButtons`** - OAuth provider buttons (Google, Apple)
567
+ - **`ErrorMessage`** - Error message display component
568
+ - **`SuccessMessage`** - Success message display component
569
+ - **`LoadingSpinner`** - Loading spinner component
570
+
571
+ ### Hooks
572
+
573
+ #### `useAuth()`
574
+
575
+ Main authentication hook that provides all auth methods:
576
+
577
+ ```typescript
578
+ const {
579
+ login, // (email: string, password: string) => Promise<AuthResult>
580
+ register, // (email: string, password: string) => Promise<AuthResult>
581
+ logout, // () => Promise<void>
582
+ forgotPassword, // (email: string) => Promise<AuthResult>
583
+ resetPassword, // (token: string, newPassword: string) => Promise<AuthResult>
584
+ verifyEmail, // (token: string) => Promise<AuthResult>
585
+ session, // AuthSession | null
586
+ loadSession, // () => Promise<AuthSession | null>
587
+ loading, // boolean
588
+ error, // AuthError | null
589
+ clearError, // () => void
590
+ } = useAuth();
591
+ ```
592
+
593
+ #### `useOAuth(onRedirect)`
594
+
595
+ OAuth authentication hook:
596
+
597
+ ```typescript
598
+ const { signIn, loadingProvider } = useOAuth(
599
+ (provider) => `/api/auth/${provider}`
600
+ );
601
+ ```
602
+
603
+ ### Types
604
+
605
+ ```typescript
606
+ interface AuthClient {
607
+ login: (email: string, password: string) => Promise<AuthResult>;
608
+ register: (email: string, password: string) => Promise<AuthResult>;
609
+ logout: () => Promise<void>;
610
+ forgotPassword: (email: string) => Promise<AuthResult>;
611
+ resetPassword: (token: string, newPassword: string) => Promise<AuthResult>;
612
+ verifyEmail: (token: string) => Promise<AuthResult>;
613
+ getSession?: () => Promise<AuthSession | null>;
614
+ }
615
+
616
+ interface AuthUIConfig {
617
+ authClient: AuthClient;
618
+ oauthProviders?: { provider: OAuthProvider; enabled: boolean }[];
619
+ logo?: ReactNode;
620
+ redirectAfterLogin?: string;
621
+ redirectAfterRegister?: string;
622
+ redirectAfterReset?: string;
623
+ }
624
+
625
+ type AuthResult =
626
+ | { success: true }
627
+ | { success: false; error: AuthError };
628
+
629
+ interface AuthError {
630
+ code: string;
631
+ message: string;
632
+ }
633
+
634
+ type OAuthProvider = "google" | "apple";
635
+ ```
636
+
637
+ ## Customization
638
+
639
+ ### Custom Logo
640
+
641
+ ```tsx
642
+ <AuthUIProvider
643
+ config={{
644
+ authClient: myAuthClient,
645
+ logo: <img src="/logo.svg" alt="Logo" />,
646
+ }}
647
+ >
648
+ {children}
649
+ </AuthUIProvider>
650
+ ```
651
+
652
+ ### OAuth Configuration via Environment Variables
653
+
654
+ Enable/disable OAuth providers and configure credentials via environment variables:
655
+
656
+ ```bash
657
+ NEXT_PUBLIC_OAUTH_GOOGLE_ENABLED=true
658
+ NEXT_PUBLIC_OAUTH_GOOGLE_CLIENT_ID=your_client_id
659
+ NEXT_PUBLIC_OAUTH_GOOGLE_REDIRECT_URI=https://yourapp.com/api/auth/google
660
+ OAUTH_GOOGLE_CLIENT_SECRET=your_client_secret
661
+ ```
662
+
663
+ The `getOAuthProvidersFromEnv()` utility automatically reads these and configures providers.
664
+
665
+ ### Custom Redirects
666
+
667
+ Set redirects via environment variables or config:
668
+
669
+ ```tsx
670
+ <AuthUIProvider
671
+ config={{
672
+ authClient: myAuthClient,
673
+ redirectAfterLogin: process.env.NEXT_PUBLIC_AUTH_REDIRECT_AFTER_LOGIN || "/dashboard",
674
+ redirectAfterRegister: process.env.NEXT_PUBLIC_AUTH_REDIRECT_AFTER_REGISTER || "/onboarding",
675
+ redirectAfterReset: process.env.NEXT_PUBLIC_AUTH_REDIRECT_AFTER_RESET || "/login?reset=success",
676
+ }}
677
+ >
678
+ {children}
679
+ </AuthUIProvider>
680
+ ```
681
+
682
+ ### Using Individual Components
683
+
684
+ You can also use components individually to build custom pages:
685
+
686
+ ```tsx
687
+ import { AuthCard, AuthForm, FormField, PasswordInput, Button } from "@liedsonc/core-auth-kit";
688
+
689
+ export function CustomLoginPage() {
690
+ return (
691
+ <AuthCard title="Sign In">
692
+ <AuthForm onSubmit={handleSubmit}>
693
+ <FormField label="Email" htmlFor="email">
694
+ <Input id="email" type="email" />
695
+ </FormField>
696
+ <FormField label="Password" htmlFor="password">
697
+ <PasswordInput id="password" />
698
+ </FormField>
699
+ <Button type="submit">Sign In</Button>
700
+ </AuthForm>
701
+ </AuthCard>
702
+ );
703
+ }
704
+ ```
705
+
706
+ ## Production Setup
707
+
708
+ ### 1. Environment Variables
709
+
710
+ Copy `.env.example` to `.env.local` and fill in your production values:
711
+
712
+ ```bash
713
+ cp .env.example .env.local
714
+ ```
715
+
716
+ **Important:** Never commit `.env.local` to version control. Add it to `.gitignore`.
717
+
718
+ ### 2. OAuth Provider Setup
719
+
720
+ #### Google OAuth
721
+
722
+ 1. Go to [Google Cloud Console](https://console.cloud.google.com/)
723
+ 2. Create a new project or select existing
724
+ 3. Enable Google+ API
725
+ 4. Create OAuth 2.0 credentials
726
+ 5. Add authorized redirect URIs
727
+ 6. Copy Client ID and Client Secret to `.env.local`
728
+
729
+ #### Apple OAuth
730
+
731
+ 1. Go to [Apple Developer Portal](https://developer.apple.com/)
732
+ 2. Create an App ID
733
+ 3. Create a Services ID
734
+ 4. Configure Sign in with Apple
735
+ 5. Add redirect URIs
736
+ 6. Copy Client ID and Client Secret to `.env.local`
737
+
738
+ ### 3. Build and Deploy
739
+
740
+ ```bash
741
+ npm run build
742
+ npm start
743
+ ```
744
+
745
+ ## Styling
746
+
747
+ The package uses Tailwind CSS and follows shadcn/ui conventions. Customize colors via CSS variables:
748
+
749
+ ```css
750
+ :root {
751
+ --primary: 222.2 47.4% 11.2%;
752
+ --primary-foreground: 210 40% 98%;
753
+ /* ... other variables */
754
+ }
755
+ ```
756
+
757
+ See [shadcn/ui theming](https://ui.shadcn.com/docs/theming) for details.
758
+
759
+ ## Security Considerations
760
+
761
+ - **No User Enumeration**: Error messages don't reveal if an email exists
762
+ - **Secure Defaults**: Password inputs prevent autofill leaks
763
+ - **CSRF Protection**: Implement CSRF tokens in your `AuthClient`
764
+ - **Rate Limiting**: Implement rate limiting in your backend
765
+ - **Token Security**: Handle tokens securely in your `AuthClient`
766
+ - **Environment Variables**: Never expose secrets in client-side code (use `NEXT_PUBLIC_` prefix only for public values)
767
+
768
+ ## Browser Support
769
+
770
+ - Chrome (latest)
771
+ - Firefox (latest)
772
+ - Safari (latest)
773
+ - Edge (latest)
774
+
775
+ ## Project Structure
776
+
777
+ ```
778
+ core-auth-kit/
779
+ ├── auth-ui/ # Package source code
780
+ │ ├── components/ # UI components
781
+ │ ├── hooks/ # React hooks
782
+ │ ├── pages/ # Page components
783
+ │ ├── types/ # TypeScript types
784
+ │ ├── styles/ # CSS styles
785
+ │ └── index.ts # Main export
786
+ ├── app/ # Example Next.js app
787
+ ├── lib/ # Utilities (oauth-config, auth-client)
788
+ ├── .env.example # Environment variables template
789
+ └── README.md # This file
790
+ ```
791
+
792
+ ## Contributing
793
+
794
+ Contributions are welcome! Please read our contributing guidelines first.
795
+
796
+ ## License
797
+
798
+ MIT
799
+
800
+ ## Support
801
+
802
+ For issues, questions, or contributions, please open an issue on GitHub.