TinyKit Pro Docs

Authentication System

TinyKit Pro includes a comprehensive authentication system supporting multiple providers and secure password management with context-aware navigation that ad...

TinyKit Pro includes a comprehensive authentication system supporting multiple providers and secure password management with context-aware navigation that adapts based on authentication state.

Authentication Methods

Email/Password Authentication

  • Secure password-based authentication with Better Auth
  • Password strength requirements and validation
  • Password reset support (implementation pending)
  • Email verification support (implementation pending)

OAuth Providers

GitHub OAuth

  1. Create an OAuth App at github.com/settings/applications/new
  2. Set callback URL: https://[your-convex-site].convex.site/api/auth/callback/github
  3. Add credentials to Convex environment:
    npx convex env set GITHUB_CLIENT_ID your_github_oauth_id
    npx convex env set GITHUB_CLIENT_SECRET your_github_oauth_secret

Google OAuth

  1. Create credentials at console.cloud.google.com
  2. Add authorized redirect URI: https://[your-convex-site].convex.site/api/auth/callback/google
  3. Add credentials to Convex environment:
    npx convex env set GOOGLE_CLIENT_ID your_google_oauth_id
    npx convex env set GOOGLE_CLIENT_SECRET your_google_oauth_secret

Apple OAuth (Optional)

  1. Create an Apple Sign In service at developer.apple.com
  2. Configure redirect URL: http://localhost:3000/api/auth/callback/apple
  3. Add credentials to Convex environment:
    npx convex env set AUTH_APPLE_ID your_apple_service_id
    npx convex env set AUTH_APPLE_SECRET your_apple_private_key

Note: Apple OAuth requires HTTPS and cannot be tested on localhost. The feature auto-enables when credentials are set.

Magic Link provides passwordless email sign-in. Users enter their email and receive a secure link that signs them in automatically.

Setup

  1. Enable magic link by setting the environment variable:

    npx convex env set MAGIC_LINK_ENABLED true
  2. Ensure Resend is configured (required for sending magic link emails):

    npx convex env set RESEND_API_KEY re_your_api_key
  3. Users can now sign in by entering their email and clicking the link sent to their inbox

How It Works

  1. User enters email on sign-in page
  2. System generates a secure magic link token
  3. Email is sent with a one-click sign-in link
  4. User clicks link and is automatically authenticated
  5. Link expires after 10 minutes for security

Features

  • Passwordless: No password to remember or manage
  • Secure: Cryptographically secure tokens with automatic expiration
  • Auto-Registration: New users are automatically registered when they click the link
  • Themed Emails: Uses database-driven theming matching your site's branding
  • Test Mode Support: In development, emails are redirected to test addresses

Note: Magic link requires explicit opt-in via MAGIC_LINK_ENABLED=true and Resend to be configured for email delivery.

OAuth Profile Images

OAuth providers automatically populate user profile pictures when users sign up. TinyKit Pro includes built-in support for displaying these images with proper fallback handling.

Supported Image Sources

  • GitHub: avatars.githubusercontent.com - Automatic GitHub profile avatars
  • Google: lh3.googleusercontent.com - Google profile pictures
  • Apple: appleid.cdn-apple.com - Apple ID profile images

Image Priority System

The application uses a helper function getUserPictureUrl that prioritizes images in this order:

  1. User-uploaded images (via pictureStorageId) - Takes priority when users upload custom avatars
  2. OAuth provider images (via image field) - Fallback to GitHub/Google/Apple profile pictures
  3. Default state - No image when neither is available

Next.js Image Configuration

OAuth profile images are automatically configured in next.config.ts:

images: {
  remotePatterns: [
    // OAuth provider image domains
    {
      protocol: "https",
      hostname: "avatars.githubusercontent.com",
      pathname: "/**",
    },
    {
      protocol: "https",
      hostname: "lh3.googleusercontent.com",
      pathname: "/**",
    },
    {
      protocol: "https",
      hostname: "appleid.cdn-apple.com",
      pathname: "/**",
    },
  ],
},

Implementation Details

  • Automatic Detection: OAuth images are displayed immediately upon user registration
  • Seamless Updates: User-uploaded images automatically override OAuth images
  • Performance Optimized: Uses Next.js Image component with proper optimization
  • Consistent API: All components use the same pictureUrl field regardless of image source

Better Auth Configuration

TinyKit Pro uses Better Auth v1.4.7 with the @convex-dev/better-auth adapter for seamless Convex integration.

Version 1.4.7 Enhancements

The upgrade to Better Auth v1.4.7 brings several key improvements:

  • Improved Configuration Management: Uses createAuthOptions() function for better separation of concerns
  • Enhanced Type Safety: Better TypeScript integration with BetterAuthOptions type
  • Optimized Authentication: Improved JWT token handling and session management
  • createdAt Field: Better Auth now automatically includes createdAt field for tracking entity creation time
  • Server-Side Token Hydration: ConvexClientProvider now supports initial token hydration for improved server-side rendering performance

Configuration Architecture

Better Auth is configured in convex/auth.ts with a modular architecture:

// Create auth options configuration
export const createAuthOptions = (ctx: GenericCtx<DataModel>) => {
  return {
    baseURL: siteUrl,
    secret: secret,
    trustedOrigins: [siteUrl],
    database: authComponent.adapter(ctx),
    emailAndPassword: {
      enabled: true,
      requireEmailVerification: false,
    },
    socialProviders: {
      github: {
        /* ... */
      },
      google: {
        /* ... */
      },
    },
    // Additional configuration...
  } satisfies BetterAuthOptions;
};

// Create Better Auth instance for HTTP handler
export const createAuth = (ctx: GenericCtx<DataModel>) => {
  return betterAuth(createAuthOptions(ctx));
};

This architecture provides:

  • Reusability: Auth options can be used in different contexts
  • Type Safety: BetterAuthOptions ensures configuration correctness
  • Testability: Easier to test auth configuration independently
  • Flexibility: Can create multiple auth instances with different configurations if needed

Required Environment Variables

# Better Auth Secret (generate with: openssl rand -base64 32)
# Set in Convex environment:
npx convex env set BETTER_AUTH_SECRET "your-random-secret"

# Site URL (set in Convex environment)
npx convex env set SITE_URL "http://localhost:3000"

# Frontend Site URL (.env.local)
NEXT_PUBLIC_SITE_URL=http://localhost:3000

Authentication Provider Configuration

Better Auth automatically detects enabled providers based on Convex environment variables. Add the credentials for the providers you want to enable using npx convex env set.

Linked Account Management

Features

  • 🔗 Multiple Authentication Methods: Users can add multiple authentication methods to their account
  • 🔒 Smart Safety Checks: Prevents users from removing their last authentication method
  • 🔄 Add Password Authentication: OAuth users can add password authentication to their existing accounts
  • Remove Authentication Methods: Users can disconnect OAuth providers and password authentication
  • 🛡️ Secure Confirmation: Disconnect actions require confirmation to prevent accidental removal
  • 👁️ Password Visibility Toggle: All password fields include an eye icon to show/hide passwords

Enhanced Social Authentication Components

TinyKit Pro includes reusable social authentication components with configurable redirect handling:

import {
  SignInWithGitHub,
  SignInWithGoogle,
  SignInWithApple
} from "@/components/auth/SocialAuthButtons";

// Default redirect to /home
<SignInWithGitHub />

// Custom redirect for account linking
<SignInWithGitHub redirectTo="/home/account?tab=accounts" />

// Dynamic redirect based on current page
<SignInWithGoogle redirectTo={window.location.href} />

Enhanced Features:

  • Configurable Redirects: redirectTo parameter controls post-authentication destination
  • Account Linking: Seamless integration with account management flows
  • URL-based Navigation: Support for tab navigation via query parameters
  • Consistent Interface: All social auth buttons share the same SocialAuthButtonProps interface
  • Smart Defaults: Default redirect to /home when no redirect is specified

PasswordInput Component

TinyKit Pro includes a reusable PasswordInput component that enhances the user experience across all authentication forms:

import { PasswordInput } from "@/components/ui/password-input";

// Usage in forms
<PasswordInput
  placeholder="Enter your password"
  autoComplete="current-password"
  {...field}
/>

Features:

  • Visibility Toggle: Eye icon to show/hide password text
  • Consistent Design: Matches shadcn/ui Input component styling
  • Accessibility: Proper ARIA attributes and semantic HTML
  • Form Integration: Works seamlessly with React Hook Form and Zod validation
  • Responsive: Optimized for mobile and desktop interactions

Account Management Interface

Users can manage their authentication methods from /home/account with enhanced navigation:

  1. URL-based Tab Navigation: Direct access via /home/account?tab=accounts
  2. View Linked Accounts: See all connected authentication methods (OAuth providers and password)
  3. Add Password: OAuth-only users can add password authentication through a secure dialog
  4. Connect Social Accounts: Social auth buttons redirect back to account page after linking
  5. Disconnect Methods: Remove OAuth providers or password authentication with safety checks
  6. Smart Validation: System prevents removal of the last authentication method

Enhanced Redirect Handling

The authentication system now supports sophisticated redirect patterns:

// Account linking flow
<SignInWithGitHub redirectTo="/home/account?tab=accounts" />
<SignInWithGoogle redirectTo="/home/account?tab=accounts" />
<SignInWithApple redirectTo="/home/account?tab=accounts" />

// Password reset flows
signIn("resend-otp", {
  email: data.email,
  redirectTo: window.location.href, // Stay on current page
});

// Email verification
signIn("password", {
  code: data.code,
  email: data.email,
  password: data.password,
  redirectTo: window.location.href, // Stay on current page
});

Benefits:

  • Seamless Account Linking: Users return to the accounts tab after connecting social providers
  • Context Preservation: Password reset and verification maintain current page context
  • Flexible Routing: Components can specify where users should land after authentication
  • Enhanced UX: Reduced navigation friction in multi-step authentication flows

Disconnect Safety System

The disconnect functionality includes comprehensive safety measures:

  • Last Method Protection: Users cannot remove their last authentication method
  • Clear Warnings: Confirmation dialogs explain the consequences of disconnection
  • Account Recovery: Users are warned about losing access if they disconnect their only method
  • Graceful Handling: Clear error messages guide users to safe account management

Technical Implementation

The linked account management system follows Convex best practices:

Backend Functions (Three-Tier Pattern):

  • Private Mutations: removeAccountLink and addPasswordToAccount handle frontend requests
  • Internal Actions: addPasswordToAccount action handles account creation requiring action context
  • Safety Validation: Comprehensive checks prevent users from locking themselves out

Frontend Components:

  • LinkedAccountsSettings: Main management interface showing all connected methods
  • SetPasswordDialog: Secure dialog for adding password authentication
  • DisconnectConfirmDialog: Confirmation dialog with clear warnings about account access
  • PasswordInput: Reusable component with visibility toggle used across all auth forms

Safety Mechanisms:

// Prevent removal of last authentication method
const linkedAccounts = await ctx.db
  .query("authAccounts")
  .withIndex("userIdAndProvider", (q) => q.eq("userId", userId))
  .collect();

if (linkedAccounts.length <= 1) {
  throw new Error(
    "Cannot remove the last authentication method from your account.",
  );
}

Password Reset System

Features

  • 🔐 Secure OTP Codes: Cryptographically secure 8-digit random codes for password reset verification
  • 📧 React Email Templates: Modern React Email components with consistent application styling
  • ⏱️ Time-Limited: Reset codes expire after 20 minutes for security (extended from 10 minutes)
  • 🔗 Multiple Access Points: Available from sign-in page and user settings
  • 🎨 Theme Integration: Uses semantic colors that adapt to site branding
  • 🛡️ Enhanced Security: Comprehensive validation, test mode support, and fraud prevention messaging
  • 📱 Mobile-Optimized: Responsive design using Tailwind CSS with @react-email optimization
  • 🏗️ Modern Architecture: Uses @convex-dev/auth Email provider instead of direct Resend integration
  • 👁️ Password Visibility: PasswordInput component used for consistent UX across all password fields

Email Template Features

The enhanced password reset email includes:

  • Professional Layout: Clean, branded design matching TinyKit Pro visual identity
  • Security Alerts: Prominent warnings about security implications
  • Clear Instructions: Step-by-step guidance for password reset process
  • Fraud Prevention: Security tips and contact information for suspicious activity
  • Accessibility: Both HTML and plain text versions for maximum compatibility
  • Mobile-First: Responsive design optimized for mobile email clients

Setup Requirements

Add these environment variables to your .env.local file:

# Required in .env.local (frontend environment)
RESEND_API_KEY=re_your_api_key_here

Additional Convex Environment Variables: The following variables are configured in the Convex environment (not .env.local):

# Set these via: npx convex env set VARIABLE_NAME value
RESEND_TEST_MODE=true                  # Redirect emails to test address in development

Email Configuration: Support email, domain, and site URL are now configured through the database via "Site Settings → Email Configuration" in the admin panel.

Note: The password reset system runs in the auth provider context and cannot use the standard Convex Resend component or database-driven configuration.

Configuration Steps

  1. Get Resend API Key:

  2. Add Environment Variables:

    # Add to your .env.local file
    RESEND_API_KEY=re_your_actual_api_key_here
    
    # Configure Convex environment variables
    npx convex env set RESEND_TEST_MODE true
    
    # Configure email settings via admin panel
    # Go to /admin → Site Settings → Email Configuration
    # Set: Support Email, Support Email Name, Resend Domain, Site URL
  3. Configuration Validation: The system validates email configuration with detailed error messages:

    • Support Email: Complete email address for reply-to headers
    • Support Email Name: Organization name for email headers
    • Resend Domain: Valid domain without protocol, subdomain recommended (e.g., 'mail.yourdomain.com')
    • Site URL: Base URL for email links
    • All email settings are configured via admin panel and stored in database
  4. Test Configuration:

    • Test password reset flow from /auth/sign-in
    • Check emails appear in Resend dashboard
    • Verify reset code works on /auth/reset-password

How Password Reset Works

  1. Request Reset: User enters email on sign-in page or reset page
  2. Code Generation: System generates 8-digit random code
  3. Email Delivery: Styled HTML email sent with reset code
  4. Code Verification: User enters code and new password
  5. Password Update: System securely updates user password

Security Features

  • Rate Limiting: Built-in protection against brute force attempts
  • Code Expiration: Codes expire after 20 minutes (configurable via maxAge)
  • Single Use: Each code can only be used once
  • Secure Generation: Cryptographically secure random code generation using @oslojs/crypto
  • Email Validation: Verification that email exists before sending reset
  • Test Mode Protection: Development emails safely redirected to test addresses
  • Environment Validation: Comprehensive validation of email configuration with helpful error messages
  • Subdomain Best Practices: Automatic mail subdomain configuration for better deliverability

Access Points

Users can initiate password reset from:

  1. Sign-In Page: "Forgot your password?" link
  2. User Settings: Password reset button in security settings
  3. Direct URL: /auth/reset-password page

Context-Aware Navigation

TinyKit Pro features smart navigation that adapts based on authentication state using Convex Auth components.

Authentication State Components

The header navigation uses three Convex Auth components for seamless state handling:

import { Authenticated, Unauthenticated, AuthLoading } from "convex/react";

export function HeaderNav() {
  return (
    <>
      <AuthLoading>
        <div className="flex items-center gap-2">
          <AnimatedThemeToggler aria-label="Toggle theme" />
        </div>
      </AuthLoading>

      <Unauthenticated>
        <div className="flex items-center gap-2">
          <AnimatedThemeToggler aria-label="Toggle theme" />
          <Button variant="ghost" asChild>
            <Link href="/auth/sign-in">Sign In</Link>
          </Button>
          <Button asChild>
            <Link href="/auth/sign-up">Sign Up</Link>
          </Button>
        </div>
      </Unauthenticated>

      <Authenticated>
        <div className="flex items-center gap-2">
          <AnimatedThemeToggler aria-label="Toggle theme" />
          <UserMenu />
        </div>
      </Authenticated>
    </>
  );
}
  • AuthLoading: Shows minimal UI (theme toggle) while authentication state loads
  • Unauthenticated: Shows Sign In and Sign Up buttons for guest users
  • Authenticated: Shows UserMenu with personalized navigation options

UserMenu Features

The authenticated UserMenu includes:

  • Essential Navigation: Home, Account, Teams (if enabled)
  • Role-Based Access: Admin Panel for admin users
  • Feature Toggles: Teams functionality controlled by NEXT_PUBLIC_ENABLE_TEAMS
  • Theme Toggle: Consistent theming across all states
  • Sign Out: Secure logout functionality

Role-Based Menu Filtering

Menu items are automatically filtered based on user permissions:

const accessibleMenuItems = getAccessibleMenuItems(
  getRegisteredUserMenu(),
  userRole,
  !!currentUser,
);

Authentication Method Tracking

TinyKit Pro tracks and displays the last authentication method used by each user:

Features

  • Last Used Method: Records which authentication method was last used (OAuth provider or password)
  • Timestamp Tracking: Stores when each authentication method was last used
  • Sign-In Page Integration: Shows "Last used" indicator next to authentication options
  • User Preferences: Helps users quickly identify their preferred sign-in method

Implementation

// Schema extension for auth tracking
const schema = defineSchema({
  users: defineTable({
    lastAuthMethod: v.optional(v.string()), // "github", "google", "password", etc.
    lastAuthAt: v.optional(v.number()), // Timestamp of last authentication
  }).index("by_lastAuthMethod", ["lastAuthMethod"]),
});

// Update last used method via Better Auth helper
export const updateLastAuthMethod = internalMutation({
  args: {
    userId: v.string(), // Better Auth uses string IDs
    method: v.string(),
  },
  handler: async (ctx, args) => {
    // Use Better Auth helper to update user record
    await updateUserById(ctx, args.userId, {
      lastAuthMethod: args.method,
      lastAuthAt: Date.now(),
    });
  },
});

Sign-In Integration

The sign-in page uses this information to highlight the user's preferred method:

// In SignInPage component
const lastAuthMethod = user?.lastAuthMethod;
const lastAuthAt = user?.lastAuthAt;

return (
  <div>
    {Object.entries(authMethods).map(([method, component]) => (
      <div
        key={method}
        className={cn(
          "relative",
          lastAuthMethod === method && "ring-2 ring-primary"
        )}
      >
        {lastAuthMethod === method && (
          <Badge className="absolute -top-2 -right-2">
            Last used {formatRelative(lastAuthAt)}
          </Badge>
        )}
        {component}
      </div>
    ))}
  </div>
);

Session Management

  • JWT Tokens: Secure JWT-based authentication with Convex Auth
  • Session Persistence: Sessions persist across browser restarts
  • Auto-Expiration: Sessions automatically expire after inactivity
  • Multi-Device: Users can be authenticated on multiple devices
  • Real-time Updates: Navigation updates immediately when authentication state changes

Security Best Practices

Implementation

  • Password Hashing: Secure password hashing with bcrypt
  • CSRF Protection: Built-in CSRF protection
  • Rate Limiting: Protection against brute force attacks
  • Secure Cookies: HTTP-only, secure cookies for session management

User Security

  • Password Requirements: Minimum length and complexity requirements
  • Account Verification: Built-in email verification that blocks access until verified
  • Secure Verification Flow: Users must verify email before accessing authenticated features
  • Two-Factor Ready: Architecture supports future 2FA implementation

Email Verification System

TinyKit Pro uses Convex Auth's built-in email verification system that securely blocks access until email addresses are verified.

Features

  • Security-First: Users cannot access authenticated features until email is verified
  • Built-in Verification: Uses Convex Auth's secure verification system with encrypted OTP codes
  • Seamless Flow: Automatic redirects to verification page during sign-up and sign-in
  • Resend Functionality: Users can request new verification codes on the verification page
  • Real-time: Instant access granted after successful verification

Technical Implementation

The verification system uses Convex Auth's built-in providers:

  • Password Provider Configuration: verify: ResendOTPEmailVerification in convex/auth.ts
  • Verification Page: /auth/verification handles OTP code submission
  • Email Templates: React Email templates with semantic color theming
  • Database Storage: Verification codes stored securely in authVerificationCodes table

User Flow

  1. Sign-up: User creates account → redirected to /auth/verification → email sent automatically
  2. Sign-in (Unverified): User attempts sign-in → automatically redirected to /auth/verification
  3. Verification: User enters OTP code → instant access granted to authenticated features
  4. Resend: Users can request new codes if needed

Authentication Flow Protection

  • Sign-in Detection: System detects unverified users and redirects to verification page
  • Middleware Protection: Verification page accessible to unverified users
  • Real-time Checks: Uses authentication state to determine user verification status

Troubleshooting

Common Issues

"Missing environment variables" error

  • Solution: Ensure all required environment variables are set
  • For Better Auth: BETTER_AUTH_SECRET must be set in Convex dashboard
  • For magic link: RESEND_API_KEY must be set in Convex environment variables

Password reset emails not being sent

  • Solution: Verify all required configuration:
    • RESEND_API_KEY: Valid Resend API key in Convex environment (npx convex env set RESEND_API_KEY re_...)
    • Email settings configured in admin panel ("Site Settings → Email Configuration")
    • Check: Support Email, Support Email Name, Resend Domain, Site URL
  • Check Resend dashboard for delivery status and errors
  • Verify domain format doesn't include protocol or paths

Magic link not sending

  • Solution: Verify RESEND_API_KEY is set in Convex environment variables
  • Check Resend dashboard for API key status and sending limits

Environment variable configuration errors

  • Solution: The system provides detailed error messages for missing or invalid configuration
  • Email configuration is now database-driven via admin panel
  • Domain values must not start or end with dots
  • Configure through "Site Settings → Email Configuration" for immediate updates

"Provider resend-otp is not configured" error

  • Solution: Ensure custom provider is included in Convex auth configuration
  • Verify environment variables are loaded properly in .env.local
  • Check that the auth provider context has access to environment variables

OAuth login not working

  • Solution: Verify callback URLs match your domain
  • Check OAuth app credentials are correct in .env.local
  • Ensure redirectTo parameter is a valid URL when using custom redirects

Account linking redirect issues

  • Solution: Use proper URL format for redirectTo parameter: /home/account?tab=accounts
  • Verify the target page properly handles the tab query parameter
  • Check that authentication state is properly updated before redirect

Reset codes not working

  • Solution: Check codes haven't expired (10-minute limit)
  • Verify email matches registered user account
  • Ensure code is entered exactly as received (8-digit numeric)

Emails have inconsistent styling

  • This is expected: Password reset emails use inline HTML styling rather than React Email templates
  • Reason: Auth providers cannot access React Email rendering or database theming
  • The enhanced HTML template provides professional styling while respecting auth context limitations

Development Tips

Testing Authentication

# View authentication logs
npx convex logs --tail | grep "auth\|login\|password"

# Test email delivery
# Check Resend dashboard at resend.com/emails

User Management

  • Admin users can manage other users through the admin interface
  • Role-based access control system (see authorization.md)

← Back to Features | Next: Authorization →

On this page

Ship your startup faster. In minutes.

Get TinyKit Pro