supabase-rb-rb
Auth

Update a user (admin)

Update any field on any user via the admin API.

Update a user's email, phone, password, metadata, ban status, or role from the server. Unlike update_user (which mutates the current signed-in user), this method can target any user in the project.

Service-role key required

This endpoint requires the project's service_role key. Never call it from a browser, mobile app, or any client you don't fully control. In particular, app_metadata and role MUST never be writeable by end-users — that's the whole point of routing those changes through this admin endpoint.

Signature

supabase.auth.admin.update_user_by_id(uid, attributes)

uid is a positional UUID String; attributes is a positional hash. Raises ArgumentError synchronously if uid isn't a syntactically valid UUID.

Parameters

NameTypeRequiredDescription
uidStringRequiredThe user's UUID (the value of user.id). Must be a syntactically valid UUID v4.
attributesHashRequiredFields to mutate. Any omitted field is left unchanged. See attribute keys below.

attributes keys

NameTypeRequiredDescription
emailStringOptionalChange the user's email. Skips the normal email-confirmation flow — the new address is set immediately.
phoneStringOptionalChange the user's phone (E.164 format). Skips the normal SMS-confirmation flow.
passwordStringOptionalReset the user's password directly. The user's current sessions remain valid; revoke them with sign_out if you need to force reauthentication.
email_confirmBooleanOptionalForce the email to be marked confirmed without sending a confirmation link.
phone_confirmBooleanOptionalForce the phone to be marked confirmed without sending a confirmation code.
user_metadataHashOptionalReplace user_metadata. NOT a merge — pass the full desired hash. Visible in JWT claims and editable by the user themselves via update_user.
app_metadataHashOptionalReplace app_metadata. NOT a merge. Only writeable via the admin API — safe to use for roles, plan tier, feature flags.
roleStringOptionalPostgres role embedded in the JWT for RLS (defaults to "authenticated"). Set to "service_role" only with extreme caution.
ban_durationStringOptionalGo duration string (e.g. "24h"). Set to "none" to lift an active ban.
nonceStringOptionalUsed internally for the password-recovery reauthentication flow — rarely set directly.

Returns

Returns
Supabase::Auth::Types::UserResponse

A Struct with a single :user field carrying the updated Types::User. Raises Supabase::Auth::Errors::AuthApiError (status 404) if the user does not exist, or status 422 on validation failures (e.g. duplicate email). Raises ArgumentError synchronously if uid isn't a valid UUID.

Example — promote a user to a paid plan

response = supabase.auth.admin.update_user_by_id(
  "8d7f5c4b-1234-4abc-9def-1234567890ab",
  app_metadata: { plan: "pro", plan_started_at: Time.now.iso8601 }
)

response.user.app_metadata["plan"]  # => "pro"

Example — force-reset a password

supabase.auth.admin.update_user_by_id(
  user_id,
  password: SecureRandom.base64(32)
)

# Existing sessions remain valid! Pair with sign_out if you need to force reauth.
supabase.auth.admin.sign_out(user_access_token, "global")

Example — ban a user for 24 hours

supabase.auth.admin.update_user_by_id(user_id, ban_duration: "24h")

# Later, lift the ban early:
supabase.auth.admin.update_user_by_id(user_id, ban_duration: "none")

Example — change email without confirmation

# Set the new email AND mark it confirmed in one call to skip the email-link round-trip.
supabase.auth.admin.update_user_by_id(
  user_id,
  email: "new-address@example.com",
  email_confirm: true
)

Validates the uid UUID format client-side with Helpers.is_valid_uuid and raises ArgumentError before any HTTP call.

On this page