Users And Accounts
Update User
Update User Information
auth.api.update_user(
headers: {"cookie" => cookie},
body: {
name: "Jane Doe",
image: "https://example.com/avatar.png"
}
)Email cannot be changed with update_user; use change_email.
Change Email
Enable email changes:
auth = BetterAuth.auth(
secret: ENV.fetch("BETTER_AUTH_SECRET"),
user: {
change_email: {
enabled: true
}
},
email_verification: {
send_verification_email: ->(data, _request) { AuthMailer.verify_email(data).deliver_later }
}
)Request the change:
auth.api.change_email(
headers: {"cookie" => cookie},
body: {
newEmail: "new@example.com",
callbackURL: "/settings"
}
)The new email becomes active after the verification link is used.
Confirming With Current Email
Require the current email to confirm first:
auth = BetterAuth.auth(
secret: ENV.fetch("BETTER_AUTH_SECRET"),
user: {
change_email: {
enabled: true,
send_change_email_confirmation: lambda do |data, _request|
AuthMailer.with(
user: data.fetch(:user),
new_email: data.fetch(:new_email),
url: data.fetch(:url),
token: data.fetch(:token)
).confirm_email_change.deliver_later
end
}
},
email_verification: {
send_verification_email: ->(data, _request) { AuthMailer.verify_email(data).deliver_later }
}
)The flow is:
change_emailsends a confirmation link to the current email.- The current email confirmation sends a verification link to the new email.
- The new email verification updates the user email and marks it verified.
Updating Without Verification
Allow unverified users to update email immediately:
user: {
change_email: {
enabled: true,
update_email_without_verification: true
}
}If a verification sender is configured, Better Auth sends a normal verification link for the new email after the update.
Client Usage
HTTP clients call:
curl -i http://localhost:3000/api/auth/change-email \
-H 'content-type: application/json' \
-H "cookie: $COOKIE" \
-d '{"newEmail":"new@example.com","callbackURL":"/settings"}'Change Password
auth.api.change_password(
headers: {"cookie" => cookie},
body: {
currentPassword: "old-password",
newPassword: "new-password",
revokeOtherSessions: true
}
)Set Password
Use set_password for users who signed in with OAuth and do not have a credential password.
auth.api.set_password(
headers: {"cookie" => cookie},
body: {
newPassword: "password123"
}
)Verify Password
auth.api.verify_password(
headers: {"cookie" => cookie},
body: {
password: "password123"
}
)Delete User
Enable user deletion:
user: {
delete_user: {
enabled: true
}
}Delete with password:
auth.api.delete_user(
headers: {"cookie" => cookie},
body: {
password: "password123"
}
)Adding Verification Before Deletion
user: {
delete_user: {
enabled: true,
send_delete_account_verification: lambda do |data, _request|
AuthMailer.with(
user: data.fetch(:user),
token: data.fetch(:token)
).delete_account.deliver_later
end
}
}Then complete deletion with the token:
auth.api.delete_user(
headers: {"cookie" => cookie},
body: {
token: params[:token]
}
)Authentication Requirements
Deletion requires one of:
- The correct password.
- A valid delete-account verification token.
- A fresh session when no password or token is supplied.
Callbacks
user: {
delete_user: {
enabled: true,
before_delete: ->(user, _request) { AuditLog.create!(user_id: user["id"], action: "before_delete") },
after_delete: ->(user, _request) { AuditLog.create!(user_id: user["id"], action: "after_delete") }
}
}Accounts
Accounts represent credentials and linked OAuth providers.
List User Accounts
auth.api.list_accounts(headers: {"cookie" => cookie})Token Encryption
Encrypt stored OAuth tokens:
account: {
encrypt_oauth_tokens: true
}get_access_token returns decrypted access tokens when the current user has access.
Account Linking
Configure account linking rules:
auth = BetterAuth.auth(
secret: ENV.fetch("BETTER_AUTH_SECRET"),
account: {
account_linking: {
enabled: true,
trusted_providers: ["google", "github"],
allow_different_emails: false,
update_user_info_on_link: true
}
}
)Forced Linking
Trusted providers can link accounts automatically when provider identity is verified and linking rules allow it.
account: {
account_linking: {
trusted_providers: ["google"]
}
}Manually Linking Accounts
auth.api.link_social(
headers: {"cookie" => cookie},
body: {
provider: "github",
callbackURL: "/settings/accounts"
}
)Native ID-token linking is available for providers with ID token verification.
Account Unlinking
auth.api.unlink_account(
headers: {"cookie" => cookie},
body: {
providerId: "github",
accountId: "github-user-id"
}
)By default, Better Auth prevents unlinking the user's last account. Set account.account_linking.allow_unlinking_all only when your app has another recovery path.