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

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"}
  ]
end

Usage

TabletAuth supports two registration patterns:

  1. Tablet User Authentication - Direct PIN authentication for tablet users
  2. 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
end

Registering 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
end

Looking 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
end

Creating 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
end

Authenticating 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
end

Device 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
end

Session 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
end

Database 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
end

For 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
end

Security Features

PIN Strength Validation

The system automatically rejects weak PINs including:

Account Security

Session Security

Configuration Options

All functions accept an opts keyword list for configuration:

Integration with Your App

This library is designed to be framework-agnostic. You'll need to:

  1. Add the schema to your app and customize fields as needed
  2. Implement the database operations in your context modules
  3. Add API endpoints for device registration and authentication
  4. Configure security settings based on your requirements

Security Considerations

License

MIT License. See LICENSE file for details.