Skip to content

Conversation

rishiraj-58
Copy link

What kind of change does this PR introduce?

Bug fix

What is the current behavior?

When creating a user with email_confirm: true, the Confirm function in internal/models/user.go overwrites the user's existing metadata instead of merging the email_verified: true flag with it.

#2088

Root cause

The current implementation calls UpdateUserMetaData with only {"email_verified": true}, which replaces the entire metadata object instead of merging with existing data.

Example of data loss

// Before email confirmation
{
  "user_metadata": {
    "name": "John Doe",
    "age": 25,
    "preferences": {
      "theme": "dark",
      "language": "en"
    }
  }
}

// After email confirmation (BROKEN - data lost!)
{
  "user_metadata": {
    "email_verified": true
  }
}

What is the new behavior?

The Confirm function now properly preserves existing user metadata by:

  1. Reloading the user's latest state from the database to get the most recent metadata
  2. Merging the email_verified: true flag with existing metadata
  3. Using the existing UpdateUserMetaData function to properly update without data loss

Example of correct behaviour:

// Before email confirmation
{
  "user_metadata": {
    "name": "John Doe",
    "age": 25,
    "preferences": {
      "theme": "dark",
      "language": "en"
    }
  }
}

// After email confirmation (FIXED - data preserved!)
{
  "user_metadata": {
    "name": "John Doe",
    "age": 25,
    "email_verified": true,
    "preferences": {
      "theme": "dark",
      "language": "en"
    }
  }
}

## Problem
When creating a user with `email_confirm: true`, the `Confirm` function in `internal/models/user.go` overwrites the user's existing metadata instead of merging the `email_verified: true` flag with it.

## Root Cause
The current implementation calls `UpdateUserMetaData` with only `{"email_verified": true}`, which replaces the entire metadata object instead of merging with existing data.

## Solution
1. Reload the user's latest state from the database to get the most recent metadata
2. Merge the `email_verified: true` flag with existing metadata
3. Use the existing `UpdateUserMetaData` function to properly update without data loss

## Testing
- ✅ Created user with `email_confirm: true` and custom metadata
- ✅ Verified metadata is preserved and `email_verified: true` is merged
- ✅ Confirmed fix works through Kong API gateway
- ✅ Tested user creation, updates, and deletion operations

## Impact
Fixes data loss issue where user metadata was being overwritten during email confirmation, ensuring all custom user data is preserved.

Closes supabase#2088
@TheMythologist
Copy link

Thanks for the PR! But I don't think this solves the real issue. This is just a hotfix for this specific button, but not potentially other areas where a "BEFORE TRIGGER" could run.

I think the real fix should be to update here:

func (u *User) UpdateUserMetaData(tx *storage.Connection, updates map[string]interface{}) error {
if u.UserMetaData == nil {
u.UserMetaData = updates
} else {
for key, value := range updates {
if value != nil {
u.UserMetaData[key] = value
} else {
delete(u.UserMetaData, key)
}
}
}
return tx.UpdateOnly(u, "raw_user_meta_data")
}

This assumes that u.UserMetaData always has the latest data, which is a false assumption. We should switch to using a postgres JSON update instead.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants