Skip to content

Users and Roles

The Ioto authentication system uses a role-based authorization model where users are assigned roles that define their access capabilities. This page describes how to configure roles and manage users.

Access Roles

Access roles define user authorization levels and their specific abilities. Ioto uses a two-level authorization system where roles map to arrays of abilities.

Authentication roles for the Ioto web server are defined in the web.json5 configuration file via the auth.roles property.

Configuring Roles

Roles are configured as an object where each role name maps to an array of abilities:

js
{
    auth: {
        // Two-level roles structure: role name -> abilities
        roles: {
            public: [],
            user: ['view', 'read'],
            admin: ['user', 'edit', 'delete'],
            owner: ['admin', 'billing', 'manage'],
        },
        login: '/api/public/login',
        logout: '/api/public/logout',
    }
}

Role Definition Structure:

  • Level 1: Role names (the object keys) - e.g., public, user, admin, owner
  • Level 2: Abilities (array values) - specific capabilities or included roles

Ability Types:

  • Specific abilities: Strings like 'view', 'read', 'edit', 'delete', 'manage'
  • Included roles: References to other roles (e.g., 'user', 'admin')

In the example above:

  • public - No specific abilities, typically for unauthenticated access
  • user - Has view and read abilities
  • admin - Includes all user abilities plus edit and delete
  • owner - Includes all admin abilities plus billing and manage

When a role includes another role (e.g., admin: ['user', ...]), it inherits all abilities from that role.

Role-Based Route Protection

The Ioto web server controls access to resources by assigning a specific "role" on a route that provides access to a document or resource. If the authenticated user has the required role or better, then the user is granted access.

Example route configuration:

js
web: {
    routes: [
        {match: '/api/admin/', role: 'admin'},
        {match: '/api/user/', role: 'user'},
        {match: '/api/'},
        {match: '/admin/', role: 'admin'},
        {match: '/user/', role: 'user'},
        {},
    ],
}

Each route specifies a matching URL prefix except for the last route which is a catchall. To restrict access, the route provides a "role" property that specifies the required user role to permit access.

In this example:

  • Routes matching /api/admin/ and /admin/ require the "admin" role
  • Routes matching /api/user/ and /user/ require at least the "user" role (which "admin" users also have)
  • Routes matching /api/ (but not /api/admin/ or /api/user/) are public
  • The catchall route {} matches all other URLs and requires no authentication

Route Evaluation Order

Routes are evaluated in order from top to bottom. The first matching route determines the access requirements. More specific routes should be listed before more general routes.

For example, /api/admin/ must be listed before /api/ to ensure admin routes are properly protected.

Users and Passwords

Users are stored in the Ioto database together with their hashed and salted passwords and assigned access role.

User Database Schema

Each user entry typically contains:

  • username - Unique user identifier
  • password - Hashed and salted password
  • role - Assigned access role (e.g., "user", "admin")

Password Security

Ioto uses strong password hashing with salts to protect user credentials:

  • Passwords are never stored in plain text
  • Each password is hashed with a unique salt
  • The cryptMakePassword API uses industry-standard algorithms

Creating Users

User entries can be created in several ways:

1. Device Management Apps

In production, users are typically created by device management or admin applications using the cryptMakePassword API.

Example:

c
#include "ioto.h"

cchar *hashedPassword = cryptMakePassword("username", "plain-password", 0);
// Store hashedPassword in database with user record

2. Development: Using the password Command

During development, you can generate hashed passwords using the password command-line utility.

Generate a hashed password:

bash
password --password demo-pass ralph

This will generate a hashed password for user "ralph" with password "demo-pass" using SHA-256 (the default algorithm).

You can specify different algorithms:

bash
# Using bcrypt (most secure for session-based auth)
password --algorithm bcrypt --password demo-pass alice

# Using MD5 (legacy, for compatibility only)
password --algorithm md5 --password demo-pass bob

# Using SHA-512
password --algorithm sha512 --password demo-pass charlie

The command will output the password hash in a format ready to add to your web.json5 users section.

3. Development: Configure Users in web.json5

For development and testing, you can define users directly in the web.json5 configuration file:

js
{
    web: {
        auth: {
            roles: {
                public: [],
                user: ['view', 'read'],
                admin: ['user', 'edit', 'delete'],
            },
            // Test users (for development only - NEVER use in production)
            users: {
                alice: {
                    password: 'SHA256:11c66702489123a02c7dd0860e47fc4989bb0805ba5835fbbb36f316ec83eb83',
                    role: 'admin'
                },
                bob: {
                    password: 'BF1:00128:ErbpOzVtv19JV20U:+i8PT5V/4GiR9Ti6NhoEkVG99dG78GuP',
                    role: 'user'
                }
            },
            login: '/api/public/login',
            logout: '/api/public/logout',
        }
    }
}

To generate password hashes for your users:

bash
# Generate a password hash for a user
password --password secret123 alice

# Copy the generated hash into web.json5 users section

SECURITY WARNING: The users section in web.json5 is for development and testing only. In production, users should be managed through your application's user management interface and stored in the database.

User Role Hierarchy

Roles can be hierarchical by including other roles in their ability arrays. A role that includes another role inherits all of that role's abilities.

Example hierarchy:

js
roles: {
    guest: ['view'],
    user: ['guest', 'read', 'comment'],
    support: ['user', 'help-users', 'view-logs'],
    admin: ['support', 'edit', 'delete', 'configure'],
}

In this configuration:

  • guest - Can only view content
  • user - Inherits view from guest, plus read and comment abilities
  • support - Inherits all user abilities (view, read, comment), plus help-users and view-logs
  • admin - Inherits all support abilities, plus edit, delete, and configure

A user with the "admin" role can:

  • Access any resource requiring "support", "user", or "guest" roles
  • Perform any action requiring abilities: view, read, comment, help-users, view-logs, edit, delete, configure

Checking Abilities

When the web server checks if a user can access a route with role: 'user':

  1. If the user's role is exactly 'user', access is granted
  2. If the user's role includes 'user' in its abilities array (e.g., 'admin' includes 'user'), access is granted
  3. Otherwise, access is denied

Best Practices

Role Design

  • Keep the role hierarchy simple and clear
  • Use descriptive role names that reflect their purpose (e.g., user, admin, moderator)
  • Use descriptive ability names that clearly indicate what they permit (e.g., edit, delete, view-logs)
  • Don't create too many roles - typically 3-5 roles are sufficient
  • Build roles hierarchically by including lower-privilege roles in higher-privilege roles
  • Group related abilities together logically (e.g., all billing-related abilities in billing management role)

Password Security

  • Always use hashed passwords, never plain text
  • Use TLS/HTTPS for all authentication traffic
  • Implement password complexity requirements
  • Consider password expiration policies for sensitive applications
  • Use the cryptMakePassword API for production password hashing

User Management

  • Implement user account lockout after failed login attempts
  • Log authentication events for security monitoring
  • Regularly audit user accounts and roles
  • Remove inactive user accounts
  • Use strong password requirements

APIs

The following APIs are available for user and role management:

See Also