PhoenixKit.Users.Auth (phoenix_kit v1.6.15)
View SourceThe Auth context for user authentication and management.
This module provides functions for user registration, authentication, password management, and email confirmation. It serves as the main interface for all user-related operations in PhoenixKit.
Core Functions
User Registration and Authentication
register_user/1- Register a new user with email and passwordget_user_by_email_and_password/2- Authenticate user credentialsget_user_by_email/1- Find user by email address
Password Management
change_user_password/2- Update user passwordreset_user_password/2- Reset password with tokendeliver_user_reset_password_instructions/1- Send password reset email
Email Confirmation
deliver_user_confirmation_instructions/1- Send confirmation emailconfirm_user/1- Confirm user account with tokenupdate_user_email/2- Change user email with confirmation
Session Management
generate_user_session_token/1- Create session token for loginget_user_by_session_token/1- Get user from session tokendelete_user_session_token/1- Logout user session
Usage Examples
# Register a new user
{:ok, user} = PhoenixKit.Users.Auth.register_user(%{
email: "user@example.com",
password: "secure_password123"
})
# Authenticate user
case PhoenixKit.Users.Auth.get_user_by_email_and_password(email, password) do
{:ok, user} -> {:ok, user}
{:error, :invalid_credentials} -> {:error, :invalid_credentials}
{:error, :rate_limit_exceeded} -> {:error, :rate_limit_exceeded}
end
# Send confirmation email
PhoenixKit.Users.Auth.deliver_user_confirmation_instructions(user)Security Features
- Passwords are hashed using bcrypt
- Email confirmation prevents unauthorized account creation
- Session tokens provide secure authentication
- Password reset tokens expire for security
- All sensitive operations are logged
Summary
Functions
Manually confirms a user account (admin function).
Manually unconfirms a user account (admin function).
Updates the user password as an admin (bypasses current password validation).
Emulates that the email will change without actually changing it in the database.
Assigns a role to a user.
Assigns roles to existing users who don't have any PhoenixKit roles.
Bulk update multiple users with the same field values.
Calculate SHA256 hash of a file.
Returns an %Ecto.Changeset{} for changing the user email.
Returns an %Ecto.Changeset{} for changing the user password.
Returns an %Ecto.Changeset{} for changing the user profile.
Returns an %Ecto.Changeset{} for tracking user changes.
Confirms a user by the given token.
Deletes all session tokens for the given user.
Deletes a specific custom field for a user.
Deletes the signed token with the given context.
Delivers the confirmation email instructions to the given user.
Delivers the reset password email to the given user.
Delivers the update email instructions to the given user.
Demotes an admin user to regular user role.
Ensures the user is active by checking the is_active field.
Generates a session token.
Gets all active session tokens for the given user.
Gets the first admin user (Owner or Admin role).
Gets the ID of the first admin user.
Gets the first user in the system (by ID).
Gets the ID of the first user in the system.
Gets role statistics for dashboard display.
Gets the user token record for the given session token.
Gets a single user.
Gets a single user.
Gets a user by email.
Gets a user by email and password.
Gets the user by reset password token.
Gets the user with the given signed token.
Gets a specific custom field value for a user.
Gets a user field value from either schema fields or custom fields.
Gets a user by ID with minimal fields for selection interfaces.
Gets all active roles for a user.
Gets a user by ID with preloaded roles.
Lists all roles.
Lists users with pagination and optional role filtering.
Promotes a user to admin role.
Registers a user with automatic role assignment.
Registers a user with IP geolocation data.
Removes a role from a user.
Resets the user password.
Searches users by email or name for selection interfaces.
Sets a specific custom field value for a user.
Toggles user confirmation status (admin function).
Update a user's avatar by storing the file and saving the file ID.
Updates user custom fields.
Updates the user email using the given token.
Updates both schema and custom fields in a single call.
Updates user's preferred locale (dialect preference).
Updates the user password.
Updates a user's profile information.
Updates user status with Owner protection.
Checks if a user has a specific role.
Gets all users who have a specific role.
Verifies a session fingerprint against the stored token data.
Functions
Manually confirms a user account (admin function).
Examples
iex> admin_confirm_user(user)
{:ok, %User{}}
iex> admin_confirm_user(invalid_user)
{:error, %Ecto.Changeset{}}
Manually unconfirms a user account (admin function).
Examples
iex> admin_unconfirm_user(user)
{:ok, %User{}}
iex> admin_unconfirm_user(invalid_user)
{:error, %Ecto.Changeset{}}
Updates the user password as an admin (bypasses current password validation).
Parameters
user- The user whose password is being updatedattrs- Password attributes (password, password_confirmation)context- Optional context map containing::admin_user- The admin performing the action (for audit logging):ip_address- IP address of the admin (for audit logging):user_agent- User agent of the admin (for audit logging)
Examples
iex> admin_update_user_password(user, %{password: "new_password", password_confirmation: "new_password"})
{:ok, %User{}}
iex> admin_update_user_password(user, %{password: "new_password", password_confirmation: "new_password"}, %{admin_user: admin, ip_address: "192.168.1.1"})
{:ok, %User{}}
iex> admin_update_user_password(user, %{password: "short"})
{:error, %Ecto.Changeset{}}
Emulates that the email will change without actually changing it in the database.
Examples
iex> apply_user_email(user, "valid password", %{email: ...})
{:ok, %User{}}
iex> apply_user_email(user, "invalid password", %{email: ...})
{:error, %Ecto.Changeset{}}
Assigns a role to a user.
Examples
iex> assign_role(user, "Admin")
{:ok, %RoleAssignment{}}
iex> assign_role(user, "Admin", assigned_by_user)
{:ok, %RoleAssignment{}}
iex> assign_role(user, "NonexistentRole")
{:error, :role_not_found}
Assigns roles to existing users who don't have any PhoenixKit roles.
This is useful for migration scenarios where PhoenixKit is installed into an existing application with users.
Examples
iex> assign_roles_to_existing_users()
{:ok, %{assigned_owner: 1, assigned_users: 5, total_processed: 6}}
Bulk update multiple users with the same field values.
This function updates multiple users at once with the same set of fields. Each user is updated independently, and the function returns a list of results showing which updates succeeded and which failed.
Both schema fields and custom fields can be updated in the same call.
Parameters
users- List of User structs to updateattrs- Map of field names to values (can include both schema and custom fields)
Returns
Returns {:ok, results} where results is a list of tuples:
{:ok, user}- Successfully updated user{:error, changeset}- Failed update with error details
Examples
# Update multiple users with the same fields
iex> users = [user1, user2, user3]
iex> bulk_update_user_fields(users, %{status: "active", department: "Engineering"})
{:ok, [
{:ok, %User{status: "active", custom_fields: %{"department" => "Engineering"}}},
{:ok, %User{status: "active", custom_fields: %{"department" => "Engineering"}}},
{:error, %Ecto.Changeset{}}
]}
# Update both schema and custom fields
iex> bulk_update_user_fields(users, %{
...> first_name: "John", # Schema field
...> last_name: "Doe", # Schema field
...> custom_field_1: "value1", # Custom field
...> custom_field_2: "value2" # Custom field
...> })
{:ok, [results...]}
Calculate SHA256 hash of a file.
Used internally for file integrity verification.
Parameters
file_path- Path to the file
Returns
- String containing the lowercase hexadecimal SHA256 hash
Returns an %Ecto.Changeset{} for changing the user email.
Examples
iex> change_user_email(user)
%Ecto.Changeset{data: %User{}}
Returns an %Ecto.Changeset{} for changing the user password.
Examples
iex> change_user_password(user)
%Ecto.Changeset{data: %User{}}
Returns an %Ecto.Changeset{} for changing the user profile.
Examples
iex> change_user_profile(user)
%Ecto.Changeset{data: %User{}}
Returns an %Ecto.Changeset{} for tracking user changes.
Examples
iex> change_user_registration(user)
%Ecto.Changeset{data: %User{}}
Confirms a user by the given token.
If the token matches, the user account is marked as confirmed and the token is deleted.
Deletes all session tokens for the given user.
This function is useful when you need to force logout a user from all sessions, for example when their roles change and they need fresh authentication.
Deletes a specific custom field for a user.
Removes the key from the custom_fields map.
Examples
iex> delete_user_custom_field(user, "phone")
{:ok, %User{}}
Deletes the signed token with the given context.
Delivers the confirmation email instructions to the given user.
Examples
iex> deliver_user_confirmation_instructions(user, &PhoenixKit.Utils.Routes.url("/users/confirm/#{&1}"))
{:ok, %{to: ..., body: ...}}
iex> deliver_user_confirmation_instructions(confirmed_user, &PhoenixKit.Utils.Routes.url("/users/confirm/#{&1}"))
{:error, :already_confirmed}
Delivers the reset password email to the given user.
This function includes rate limiting protection to prevent mass password reset attacks.
After exceeding the rate limit (default: 3 requests per 5 minutes), subsequent
requests will be rejected with {:error, :rate_limit_exceeded}.
Examples
iex> deliver_user_reset_password_instructions(user, &PhoenixKit.Utils.Routes.url("/users/reset-password/#{&1}"))
{:ok, %{to: ..., body: ...}}
iex> deliver_user_reset_password_instructions(user, &PhoenixKit.Utils.Routes.url("/users/reset-password/#{&1}"))
{:error, :rate_limit_exceeded}
Delivers the update email instructions to the given user.
Examples
iex> deliver_user_update_email_instructions(user, current_email, &PhoenixKit.Utils.Routes.url("/users/settings/confirm_email/#{&1}"))
{:ok, %{to: ..., body: ...}}
Demotes an admin user to regular user role.
Examples
iex> demote_to_user(user)
{:ok, %RoleAssignment{}}
Ensures the user is active by checking the is_active field.
Returns nil for inactive users and logs a warning. Returns the user for active users or nil input.
Examples
iex> ensure_active_user(%User{is_active: true})
%User{is_active: true}
iex> ensure_active_user(%User{is_active: false, id: 123})
nil
iex> ensure_active_user(nil)
nil
Generates a session token.
Options
:fingerprint- Optional session fingerprint map with:ip_addressand:user_agent_hash
Examples
# Without fingerprinting (backward compatible)
token = generate_user_session_token(user)
# With fingerprinting
fingerprint = PhoenixKit.Utils.SessionFingerprint.create_fingerprint(conn)
token = generate_user_session_token(user, fingerprint: fingerprint)
Gets all active session tokens for the given user.
This is useful for finding all active sessions to broadcast logout messages.
Gets the first admin user (Owner or Admin role).
Useful for programmatic operations that require a user ID, such as creating entities via scripts or seeds.
Returns the first Owner if one exists, otherwise the first Admin, otherwise nil.
Examples
iex> get_first_admin()
%User{id: 1, email: "admin@example.com"}
iex> get_first_admin()
nil # No admin users exist
Gets the ID of the first admin user.
Convenience function that returns just the user ID, useful for
setting created_by fields programmatically.
Examples
iex> get_first_admin_id()
1
iex> get_first_admin_id()
nil # No admin users exist
# Common usage for creating entities
PhoenixKit.Entities.create_entity(%{
name: "contact",
display_name: "Contact",
created_by: PhoenixKit.Users.Auth.get_first_admin_id()
})
Gets the first user in the system (by ID).
Returns the user with the lowest ID, typically the first registered user. Useful as a fallback when no specific admin is needed.
Examples
iex> get_first_user()
%User{id: 1}
Gets the ID of the first user in the system.
Convenience function for getting a user ID for created_by fields.
Examples
iex> get_first_user_id()
1
Gets role statistics for dashboard display.
Examples
iex> get_role_stats()
%{
total_users: 10,
owner_count: 1,
admin_count: 2,
user_count: 7
}
Gets the user token record for the given session token.
This is useful for accessing fingerprint data stored with the token.
Examples
iex> get_session_token_record("valid_token")
%UserToken{ip_address: "192.168.1.1", user_agent_hash: "abc123"}
iex> get_session_token_record("invalid_token")
nil
Gets a single user.
Returns nil if the user does not exist.
Examples
iex> get_user(123)
%User{}
iex> get_user(456)
nil
Gets a single user.
Raises Ecto.NoResultsError if the User does not exist.
Examples
iex> get_user!(123)
%User{}
iex> get_user!(456)
** (Ecto.NoResultsError)
Gets a user by email.
Examples
iex> get_user_by_email("foo@example.com")
%User{}
iex> get_user_by_email("unknown@example.com")
nil
Gets a user by email and password.
This function includes rate limiting protection to prevent brute-force attacks.
After exceeding the rate limit (default: 5 attempts per minute), subsequent
attempts will be rejected with {:error, :rate_limit_exceeded}.
Examples
iex> get_user_by_email_and_password("foo@example.com", "correct_password")
{:ok, %User{}}
iex> get_user_by_email_and_password("foo@example.com", "invalid_password")
{:error, :invalid_credentials}
iex> get_user_by_email_and_password("foo@example.com", "password", "192.168.1.1")
{:ok, %User{}}
Gets the user by reset password token.
Examples
iex> get_user_by_reset_password_token("validtoken")
%User{}
iex> get_user_by_reset_password_token("invalidtoken")
nil
Gets the user with the given signed token.
Gets a specific custom field value for a user.
Returns the value if the key exists, or nil otherwise.
Examples
iex> get_user_custom_field(user, "phone")
"555-1234"
iex> get_user_custom_field(user, "nonexistent")
nil
Gets a user field value from either schema fields or custom fields.
This unified accessor provides O(1) performance by checking struct fields first using Map.has_key?/2, then falling back to custom_fields JSONB.
Certain sensitive fields are excluded for security:
- password, current_password (virtual fields)
- hashed_password (use authentication functions instead)
Examples
# Standard schema fields (O(1) struct access)
iex> get_user_field(user, "email")
"user@example.com"
iex> get_user_field(user, :first_name)
"John"
# Custom fields (O(1) JSONB lookup)
iex> get_user_field(user, "phone")
"555-1234"
# Nonexistent returns nil
iex> get_user_field(user, "nonexistent")
nil
# Excluded sensitive fields return nil
iex> get_user_field(user, "hashed_password")
nilPerformance
- Standard fields: ~0.5μs (direct struct access)
- Custom fields: ~1-2μs (JSONB lookup)
- No performance penalty from checking both locations
Gets a user by ID with minimal fields for selection interfaces.
Returns a user map with id, email, first_name, and last_name fields. Returns nil if user is not found.
Examples
iex> PhoenixKit.Users.Auth.get_user_for_selection(123)
%{id: 123, email: "user@example.com", first_name: "John", last_name: "Doe"}
iex> PhoenixKit.Users.Auth.get_user_for_selection(999)
nil
Gets all active roles for a user.
Examples
iex> get_user_roles(user)
["Admin", "User"]
iex> get_user_roles(user_with_no_roles)
[]
Gets a user by ID with preloaded roles.
Examples
iex> get_user_with_roles(123)
%User{roles: [%Role{}, %Role{}]}
iex> get_user_with_roles(999)
nil
Lists all roles.
Examples
iex> list_roles()
[%Role{}, %Role{}, %Role{}]
Lists users with pagination and optional role filtering.
Examples
iex> list_users_paginated(page: 1, page_size: 10)
%{users: [%User{}], total_count: 50, total_pages: 5}
iex> list_users_paginated(page: 1, page_size: 10, role: "Admin")
%{users: [%User{}], total_count: 3, total_pages: 1}
Promotes a user to admin role.
Examples
iex> promote_to_admin(user)
{:ok, %RoleAssignment{}}
iex> promote_to_admin(user, assigned_by_user)
{:ok, %RoleAssignment{}}
Registers a user with automatic role assignment.
Role assignment is handled by Elixir application logic:
- First user receives Owner role
- Subsequent users receive User role
- Uses database transactions to prevent race conditions
This function includes rate limiting protection to prevent spam account creation. Rate limits apply per email address and optionally per IP address.
Examples
iex> register_user(%{field: value})
{:ok, %User{}}
iex> register_user(%{field: bad_value})
{:error, %Ecto.Changeset{}}
iex> register_user(%{email: "user@example.com"}, "192.168.1.1")
{:ok, %User{}}
Registers a user with IP geolocation data.
This function attempts to look up geographical location information based on the provided IP address and includes it in the user registration. If geolocation lookup fails, the user is still registered with just the IP address.
This function automatically applies rate limiting based on the IP address.
Examples
iex> register_user_with_geolocation(%{email: "user@example.com", password: "password"}, "192.168.1.1")
{:ok, %User{registration_ip: "192.168.1.1", registration_country: "United States"}}
iex> register_user_with_geolocation(%{email: "invalid"}, "192.168.1.1")
{:error, %Ecto.Changeset{}}
Removes a role from a user.
Examples
iex> remove_role(user, "Admin")
{:ok, %RoleAssignment{}}
iex> remove_role(user, "NonexistentRole")
{:error, :assignment_not_found}
Resets the user password.
Examples
iex> reset_user_password(user, %{password: "new long password", password_confirmation: "new long password"})
{:ok, %User{}}
iex> reset_user_password(user, %{password: "valid", password_confirmation: "not the same"})
{:error, %Ecto.Changeset{}}
Searches users by email or name for selection interfaces.
Returns a list of users matching the search term, limited to 10 results for performance. Useful for autocomplete/typeahead interfaces.
Examples
iex> PhoenixKit.Users.Auth.search_users("john")
[%User{email: "john@example.com", first_name: "John"}, ...]
iex> PhoenixKit.Users.Auth.search_users("")
[]
Sets a specific custom field value for a user.
Updates a single key in the custom_fields map while preserving other fields.
Examples
iex> set_user_custom_field(user, "phone", "555-1234")
{:ok, %User{}}
iex> set_user_custom_field(user, "department", "Product")
{:ok, %User{}}
Toggles user confirmation status (admin function).
Examples
iex> toggle_user_confirmation(confirmed_user)
{:ok, %User{confirmed_at: nil}}
iex> toggle_user_confirmation(unconfirmed_user)
{:ok, %User{confirmed_at: ~N[2023-01-01 12:00:00]}}
Update a user's avatar by storing the file and saving the file ID.
This function handles the complete avatar upload workflow:
- Stores the file in configured storage buckets
- Automatically queues background job for variant generation
- Saves the file ID to the user's custom_fields
This is a convenience function that combines file storage with user update. Can be called from any context (LiveView, controllers, scripts, etc.) outside of the PhoenixKit project.
Parameters
user- The User struct to updatefile_path- Path to the uploaded file (temporary location)filename- Original filename for the uploaduser_id- The user ID owning this file (defaults to user.id)
Returns
{:ok, user}- Avatar saved successfully{:error, reason}- File storage or update failed
Examples
# Store avatar in default location with automatic variant generation
{:ok, updated_user} = Auth.update_user_avatar(user, "/tmp/upload_xyz", "avatar.jpg")
# Store with explicit user_id (for custom workflows)
{:ok, updated_user} = Auth.update_user_avatar(user, "/tmp/upload_xyz", "avatar.jpg", custom_user_id)Automatically Generated Variants
The storage layer automatically generates these image variants:
- original - Full-size image
- large - 800x800px
- medium - 400x400px
- small - 200x200px
- thumbnail - 100x100px
Updates user custom fields.
Custom fields are stored as JSONB and can contain arbitrary key-value pairs for extending user data without schema changes.
Examples
iex> update_user_custom_fields(user, %{"phone" => "555-1234", "department" => "Engineering"})
{:ok, %User{}}
iex> update_user_custom_fields(user, "invalid")
{:error, %Ecto.Changeset{}}
Updates the user email using the given token.
If the token matches, the user email is updated and the token is deleted. The confirmed_at date is also updated to the current time.
Updates both schema and custom fields in a single call.
This is a unified update function that automatically splits the provided attributes into schema fields and custom fields, updating both appropriately.
Schema Fields
- first_name, last_name, email, username, user_timezone
Custom Fields
- Any other keys are treated as custom fields
Examples
iex> update_user_fields(user, %{
...> "first_name" => "John",
...> "email" => "john@example.com",
...> "phone" => "555-1234",
...> "department" => "Engineering"
...> })
{:ok, %User{}}
iex> update_user_fields(user, %{email: "invalid"})
{:error, %Ecto.Changeset{}}
Updates user's preferred locale (dialect preference).
This allows users to select specific language dialects (e.g., en-GB, en-US) while URLs continue to use base codes (e.g., /en/).
Examples
iex> update_user_locale_preference(user, "en-GB")
{:ok, %User{preferred_locale: "en-GB"}}
iex> update_user_locale_preference(user, "invalid")
{:error, %Ecto.Changeset{}}
Updates the user password.
Examples
iex> update_user_password(user, "valid password", %{password: ...})
{:ok, %User{}}
iex> update_user_password(user, "invalid password", %{password: ...})
{:error, %Ecto.Changeset{}}
Updates a user's profile information.
Examples
iex> update_user_profile(user, %{first_name: "John", last_name: "Doe"})
{:ok, %User{}}
iex> update_user_profile(user, %{first_name: ""})
{:error, %Ecto.Changeset{}}
Updates user status with Owner protection.
Prevents deactivation of the last Owner to maintain system security.
Parameters
user: User to updateattrs: Status attributes (typically %{"is_active" => true/false})
Examples
iex> update_user_status(user, %{"is_active" => false})
{:ok, %User{}}
iex> update_user_status(last_owner, %{"is_active" => false})
{:error, :cannot_deactivate_last_owner}
Checks if a user has a specific role.
Examples
iex> user_has_role?(user, "Admin")
true
iex> user_has_role?(user, "Owner")
false
Gets all users who have a specific role.
Examples
iex> users_with_role("Admin")
[%User{}, %User{}]
iex> users_with_role("NonexistentRole")
[]
Verifies a session fingerprint against the stored token data.
Returns:
:okif fingerprint matches or fingerprinting is disabled{:warning, reason}if there's a partial mismatch (IP or UA changed){:error, :fingerprint_mismatch}if both IP and UA changed
Examples
iex> verify_session_fingerprint(conn, token)
:ok
iex> verify_session_fingerprint(conn, token)
{:warning, :ip_mismatch}