TabletAuth
A secure authentication system designed for tablet and mobile device applications requiring simple PIN-based access with device registration capabilities.
It provides a simple way to do pin based registration of an ipad or tablet acting as a display so that the user does not need to enter a password on the display. Similar to when apple tv asks you for a pin to register your new apple tv to your account.
One use case is if you have a website that you want to display on a tablet or mobile app without logging in so if the tablet is stolen you are not worried about your information being taken as the tablet only knows about a website address like tablets/:secret. Or another way to think about it is you have a nice web page that you want your users to share with their friends they can do that without sharing their username/password.
The app needs some work and here is a prompt that worked for me to integrate with a web app. This creates a panel on /settings page to add/delete displays.
Features
- PIN-based Authentication: Secure numeric PIN authentication with configurable length
- Device Registration: Register mobile devices to user accounts via HTTPS API
- PIN Strength Validation: Prevents weak PINs (sequential, repetitive, common patterns)
- Session Management: Track user activity and session validity
- Flexible Integration: Designed to work with any Ecto-compatible database
Prompt Based Installation
Prompt 1
add hex package 'tablet_auth' package to mix.exs.
run mix deps.get after adding to mix.exs.
run all tests to ensure they still work.Prompt 2
review the hex documentation for 'tablet_auth' then
create a section in the /settings page to manage tablets/displays with functioinality as follows using the tablet_auth package.
page to show from a tablet /conditions
Tablet Registration from /settings Page:
1. Generate PIN for New Tablet
- Click "Generate PIN for New Tablet" button (lines 62-69)
- Creates a new Display record with a 6-hour valid PIN
- Shows the PIN and registration URL /tablets/register
2. Registration Process
- Tablet goes to /tablets/register and enters the PIN
- PIN expires after 6 hours for security
- Once registered, tablet appears in the list on the /settings page
3. Manage Registered Tablets
- Shows all registered tablets with their friendly names associated with a user.
- Each tablet shows:
- Name
- Copy URL button to get tablet access link
- Open in new tab button
- Remove tablet button
5. Access Methods
- Each tablet gets a unique access URL: /tablets/{secret_key}
- PIN-based registration for new devices
- the access URL will display the page defined at top of the prompt in this case /conditions
create tests and ensure passing.
Installation
Add tablet_auth to your list of dependencies in mix.exs:
def deps do
[
{:tablet_auth, "~> 0.1.0"}
]
endUsage
TabletAuth supports two registration patterns:
- Tablet User Authentication - Direct PIN authentication for tablet users
- Display-Based Registration - PIN-based tablet registration using display entities (recommended for family photo sharing apps)
Display-Based Tablet Registration (Recommended)
This is the primary approach for applications that manage displays/frames that can have tablets registered to them.
Generating a Registration PIN
# Generate a PIN for a display that tablets can use to register
case TabletAuth.generate_display_pin(display, repo: MyApp.Repo) do
{:ok, updated_display} ->
# Display now has registration_pin and pin_expires_at set
# Share this PIN with users to register their tablets
{:error, changeset} ->
# Handle validation errors
endRegistering a Tablet with PIN
attrs = %{friendly_name: "Kitchen Tablet"}
opts = [
repo: MyApp.Repo,
display_schema: MyApp.Display, # Your display schema (optional if using default)
user_display_schema: MyApp.UsersDisplays, # Association schema (optional)
post_schema: MyApp.Post, # For finding best parent display (optional)
pubsub_module: Phoenix.PubSub, # For broadcasting updates (optional)
broadcast_topic: "user_settings:{owner_id}" # Topic pattern (optional)
]
case TabletAuth.register_tablet_with_pin("123456", attrs, opts) do
{:ok, %{tablet: tablet, association: association}} ->
# Tablet registered successfully
# tablet.secret_key can be used for tablet access
{:error, :invalid_or_expired_pin} ->
# Wrong or expired PIN
{:error, changeset} ->
# Handle registration failure
endLooking Up Tablets
# Validate a PIN (useful for API endpoints)
case TabletAuth.validate_pin("123456", repo: MyApp.Repo) do
%Display{} = display ->
# PIN is valid, display can be used for registration
nil ->
# Invalid or expired PIN
end
# Get tablet by secret key (for tablet access)
case TabletAuth.get_tablet_by_secret(secret_key, repo: MyApp.Repo) do
%Display{} = tablet ->
# Tablet found
nil ->
# Tablet not found
endCreating a Tablet User
attrs = %{
name: "John Doe",
pin: "1357"
}
opts = [
pin_length: 4,
max_attempts: 3,
lockout_duration: 15 # minutes
]
case TabletAuth.create_tablet_user(attrs, opts) do
{:ok, changeset} ->
# Save changeset to your database
MyApp.Repo.insert(changeset)
{:error, :weak_pin} ->
# Handle weak PIN error
{:error, changeset} ->
# Handle validation errors
endAuthenticating with PIN
# For tablet authentication (finds active tablet user)
case TabletAuth.authenticate_pin("1357") do
{:ok, user} ->
# Authentication successful
{:error, :invalid_pin} ->
# Wrong PIN
{:error, :account_locked} ->
# Too many failed attempts
end
# For device authentication
case TabletAuth.authenticate_device("1357", "device_123") do
{:ok, user} ->
# Device authentication successful
{:error, reason} ->
# Handle authentication failure
endDevice Registration
device_attrs = %{
device_id: "mobile_device_abc123",
device_name: "John's iPhone"
}
user_lookup = %{
email: "john@example.com"
# or user_id: "user_123"
# or external_user_id: "external_456"
}
case TabletAuth.register_device(device_attrs, user_lookup) do
{:ok, registration} ->
# Device registered successfully
{:error, :device_already_registered} ->
# Device is already registered
{:error, reason} ->
# Handle registration failure
endSession Management
# Update user activity
TabletAuth.update_last_activity(user_id)
# Check if session is valid
if TabletAuth.session_valid?(user_id, session_timeout_minutes: 60) do
# Session is still active
else
# Session expired, require re-authentication
end
# Revoke device access
case TabletAuth.revoke_device("device_123") do
{:ok, revocation} ->
# Device access revoked
{:error, reason} ->
# Handle revocation failure
endDatabase Schema
For Display-Based Registration
Create a migration for the displays table:
defmodule MyApp.Repo.Migrations.CreateDisplays do
use Ecto.Migration
def change do
create table(:displays, primary_key: false) do
add :id, :binary_id, primary_key: true
add :title, :string, null: false
add :registration_pin, :string
add :pin_expires_at, :utc_datetime
add :secret_key, :string
add :friendly_name, :string
add :is_tablet, :boolean, default: false
add :tablet_parent_display, :binary_id
add :owner_id, :binary_id, null: false
timestamps(type: :utc_datetime)
end
create index(:displays, [:owner_id])
create index(:displays, [:registration_pin])
create index(:displays, [:secret_key])
create index(:displays, [:is_tablet])
create index(:displays, [:tablet_parent_display])
end
endFor Tablet User Authentication
Create a migration for the tablet users table:
defmodule MyApp.Repo.Migrations.CreateTabletUsers do
use Ecto.Migration
def change do
create table(:tablet_users, primary_key: false) do
add :id, :binary_id, primary_key: true
add :name, :string, null: false
add :pin_hash, :string, null: false
add :active, :boolean, default: true
add :last_activity, :utc_datetime
add :failed_attempts, :integer, default: 0
add :locked_until, :utc_datetime
add :device_id, :string
add :device_name, :string
add :registered_at, :utc_datetime
add :external_user_id, :string
timestamps()
end
create unique_index(:tablet_users, [:device_id])
create index(:tablet_users, [:external_user_id])
create index(:tablet_users, [:active])
end
endSecurity Features
PIN Strength Validation
The system automatically rejects weak PINs including:
- All same digits (0000, 1111, etc.)
- Sequential patterns (1234, 4321, etc.)
- Common weak patterns
- Repetitive patterns (more than half digits the same)
Account Security
- Failed Attempt Tracking: Counts consecutive failed login attempts
- Account Lockout: Temporarily locks accounts after too many failures
- Secure Hashing: Uses bcrypt with 12 rounds for PIN storage
- No Plaintext Storage: PINs are never stored in plaintext
Session Security
- Activity Tracking: Updates last activity timestamp on successful auth
- Session Timeouts: Configurable session timeout validation
- Device Revocation: Ability to remotely revoke device access
Configuration Options
All functions accept an opts keyword list for configuration:
:pin_length- Required PIN length (default: 4):max_attempts- Maximum failed attempts before lockout (default: 3):lockout_duration- Lockout duration in minutes (default: 15):session_timeout_minutes- Session timeout in minutes (default: 60):repo- Ecto repo module for database operations
Integration with Your App
This library is designed to be framework-agnostic. You'll need to:
- Add the schema to your app and customize fields as needed
- Implement the database operations in your context modules
- Add API endpoints for device registration and authentication
- Configure security settings based on your requirements
Security Considerations
- Always use HTTPS for device registration and authentication APIs
- Implement rate limiting on authentication endpoints
- Consider additional security measures for high-value applications
- Regularly review and update PIN strength requirements
- Monitor failed authentication attempts for suspicious activity
License
MIT License. See LICENSE file for details.