All files / app/api/auth/password/check route.ts

80.76% Statements 42/52
81.81% Branches 18/22
100% Functions 1/1
80.76% Lines 42/52

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 941x       5x 5x 5x   5x 5x 5x 5x   5x 1x 1x     5x     5x     5x     5x             5x   5x 5x     5x 5x 5x 5x 5x   5x 1x 5x       2x   2x                                     2x 5x           3x 3x 3x 3x 5x   5x 5x 5x 1x 1x 1x 5x  
import { NextResponse } from 'next/server';
import { createClient } from '@/lib/supabase/server';
import { createAdminClient } from '@/lib/supabase/admin';
 
export async function GET() {
  try {
    const supabase = await createClient();
 
    const {
      data: { user },
      error: authError,
    } = await supabase.auth.getUser();
 
    if (authError || !user) {
      return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
    }
 
    // Check user's identities to determine auth method
    const identities = user.identities || [];
 
    // Check if user signed up via phone only
    const hasPhoneOnly = identities.length === 1 && identities[0]?.provider === 'phone';
 
    // Check if user has a placeholder email (phone-only user)
    const isPlaceholderEmail = user.email?.endsWith('@proofid.internal') || false;
 
    // Check if user has a real email to use for password auth
    const hasRealEmail = !!(user.email && !isPlaceholderEmail);
 
    // To determine if user has a password, we check multiple sources:
    // 1. Our users table has_password flag (set when user changes password via settings)
    // 2. Check if user signed up with email provider (indicates password signup)
    //
    // The challenge is Supabase doesn't expose "has password" directly.
    let hasPassword = false;
 
    try {
      const supabaseAdmin = createAdminClient();
 
      // First, check our users table for explicit flag
      const { data: userData } = await supabaseAdmin
        .from('users')
        .select('has_password')
        .eq('id', user.id)
        .single();
 
      if (userData?.has_password === true) {
        hasPassword = true;
      } else {
        // If no explicit flag, check if user signed up with email+password
        // Users who signed up with password have email identity AND their
        // user_metadata doesn't indicate magic link signup
        const emailIdentity = identities.find((i) => i.provider === 'email');
 
        if (emailIdentity && hasRealEmail) {
          // Check if this was a password signup by looking at identity_data
          // Password signups have identity_data.email set and no pending confirmation
          // Also check app_metadata for provider hints
          const appMetadata = user.app_metadata || {};
 
          // If user has email identity and their provider is 'email' (not 'magiclink'),
          // they likely signed up with password
          if (appMetadata.provider === 'email' || appMetadata.providers?.includes('email')) {
            // User signed up with email - check if they have confirmed email
            // (confirmed email + email provider = password signup)
            if (user.email_confirmed_at) {
              hasPassword = true;
 
              // Update our flag for future checks
              await supabaseAdmin.from('users').update({ has_password: true }).eq('id', user.id);
            }
          }
        }
      }
    } catch {
      // If we can't check the database, assume no password
      // This errs on the side of letting users set a password
      hasPassword = false;
    }
 
    return NextResponse.json({
      hasPassword,
      hasRealEmail,
      hasPhoneOnly,
      email: hasRealEmail ? user.email : null,
      // If no password but has real email, user can set one
      canSetPassword: !hasPassword && hasRealEmail,
    });
  } catch (error) {
    console.error('Password check error:', error);
    return NextResponse.json({ error: 'Failed to check password status' }, { status: 500 });
  }
}