Skip to content

A principal represents a human identity that authenticates with Hantera. Principals are the primary way users interact with the Hantera platform.

TIP

This page covers principals in depth. For an overview of IAM, see the IAM Overview.

What is a Principal?

Principals represent people who need to access Hantera - whether they're administrators managing the portal, customer service agents, or end customers accessing their accounts.

Key characteristics:

  • Email address (used as username, must be unique)
  • Password or OAuth authentication
  • Can be assigned multiple roles
  • Can be temporarily suspended
  • Dynamic properties for custom data
  • Active session tracking

Example principal:

json
{
  "id": "01933e8f-7c45-7123-9abc-123456789abc",
  "type": "principal",
  "properties": {
    "name": "John Admin",
    "email": "john@company.com",
    "phone": "+1234567890",
    "picture": "https://example.com/photo.jpg",
    "settings": {
      "theme": "dark",
      "language": "en"
    }
  },
  "roles": ["system:portal:full"],
  "suspendedAt": null,
  "lastActiveAt": "2025-01-07T15:30:00Z"
}

When to Use Principals

✅ Use principals for:

  • Portal users (administrators, staff)
  • Customer accounts
  • Partner or vendor users
  • Any human that needs to log in

❌ Don't use principals for:

  • Application-to-application authentication (use Clients instead)
  • Service accounts (use Clients instead)
  • Webhook consumers (use Clients instead)

List API Features

The principals list endpoint supports comprehensive filtering, search, and cursor-based pagination for efficient data retrieval.

Cursor-Based Pagination

All list operations use cursor-based pagination for optimal performance with large datasets:

Query parameters:

  • limit - Items per page (default: 50, max: 100)
  • after - Cursor for next page
  • before - Cursor for previous page

Response format:

json
{
  "principals": [...],
  "totalCount": 245,
  "lastCursor": "01933e8f-7c45-7123-9abc-123456789abc",
  "firstCursor": "01933e8f-7c45-7123-9abc-123456789def"
}

Example - First page:

http
GET /resources/iam/principals?limit=50

Example - Next page:

http
GET /resources/iam/principals?limit=50&after=01933e8f-7c45-7123-9abc-123456789abc

Example - Previous page:

http
GET /resources/iam/principals?limit=50&before=01933e8f-7c45-7123-9abc-123456789def

TIP

Use totalCount to display result counts. Use lastCursor and firstCursor for pagination navigation.

Search by name or email (case-insensitive, partial matches):

http
GET /resources/iam/principals?search=john

This will match principals with "john" in their name or email address.

Filtering

Filter by roles:

http
# Filter by multiple roles (matches principals with ANY of these roles)
GET /resources/iam/principals?roles=system:owner&roles=system:portal:full

# Filter by single role (convenience parameter)
GET /resources/iam/principals?role=support:agent

# Filter by role prefix (all roles starting with prefix)
GET /resources/iam/principals?rolePrefix=system:portal:

Include suspended principals:

http
# By default, suspended principals are excluded
GET /resources/iam/principals?includeSuspended=true

Sorting

Sort results using the orderBy parameter:

http
# Sort by name ascending (default)
GET /resources/iam/principals?orderBy=name asc

# Sort by email descending
GET /resources/iam/principals?orderBy=email desc

# Sort by last active date
GET /resources/iam/principals?orderBy=lastActiveAt desc

Available sort fields:

  • name - Principal's name
  • email - Email address
  • lastActiveAt - Last authentication timestamp
  • suspendedAt - Suspension date

INFO

The orderBy parameter combines field name and direction in a single value (e.g., name asc, email desc).

Combined Queries

You can combine search, filters, sorting, and pagination:

http
GET /resources/iam/principals?search=admin&roles=system:portal:full&orderBy=name asc&limit=20

This query:

  • Searches for "admin" in name/email
  • Filters by system:portal:full role
  • Sorts by name ascending
  • Returns 20 results per page

Principal Management

Create or Update Principal

Full replacement of a principal (use for initial creation or complete updates):

http
PUT /resources/iam/principals/{id}
If-Match: "etag-value"
{
  "properties": {
    "name": "John Admin",
    "email": "john@example.com",
    "phone": "+1234567890",
    "picture": "https://example.com/photo.jpg",
    "settings": {
      "theme": "dark",
      "language": "en"
    }
  },
  "roles": ["system:portal:full"],
  "acl": {
    "entries": [
      { "resource": "orders", "permission": "*" }
    ]
  },
  "accessAttributes": {
    "channelKey": ["STORE-NYC"]
  }
}

WARNING

The If-Match header with ETag is required for updates to prevent conflicting changes. Omit it only when creating a new principal.

Partial Update

Update specific properties without replacing the entire principal:

http
PATCH /resources/iam/principals/{id}
If-Match: "etag-value"
{
  "name": "John Updated",
  "email": "john.new@example.com",
  "settings": {
    "theme": "light"
  }
}

Partial updates:

  • Only update specified fields
  • Merge settings (don't replace them)
  • Leave other properties unchanged
  • Require ETag for safety

Update Roles

Replace the entire roles list:

http
PUT /resources/iam/principals/{id}/roles
If-Match: "etag-value"
{
  "roles": ["system:portal:full", "support:agent"]
}

Update ACL

Replace the entire ACL:

http
PUT /resources/iam/principals/{id}/acl
If-Match: "etag-value"
{
  "acl": [
    "orders:*",
    "customers:read"
  ]
}

Get Principal Details

Retrieve a principal with all properties:

http
GET /resources/iam/principals/{id}

Response includes:

json
{
  "id": "01933e8f-7c45-7123-9abc-123456789abc",
  "name": "John Admin",
  "email": "john@example.com",
  "phone": "+1234567890",
  "picture": "https://example.com/photo.jpg",
  "settings": {
    "theme": "dark",
    "language": "en"
  },
  "roles": ["system:portal:full"],
  "acl": {
    "entries": [...]
  },
  "accessAttributes": {
    "channelKey": ["STORE-NYC"]
  },
  "suspendedAt": null,
  "lastActiveAt": "2025-01-07T15:30:00Z",
  "createdAt": "2024-01-01T10:00:00Z",
  "etag": "W/\"abc123\"",
  "passwordLogin": true,
  "passwordExpiresAt": null
}

Additional fields:

  • passwordLogin - Whether password authentication is enabled
  • passwordExpiresAt - When the password expires (null for permanent passwords)
  • lastActiveAt - Last successful authentication timestamp
  • etag - Version identifier for safe updates

Delete Principal

Remove a principal permanently:

http
DELETE /resources/iam/principals/{id}

Returns 204 No Content on success.

WARNING

Deletion is permanent and cannot be undone. Consider suspension for temporary account deactivation.

Self-Service Restrictions

Principals cannot suspend or delete themselves. If you attempt to suspend or delete your own account, the API returns 403 Forbidden with the error message: "Cannot suspend your own principal" or "Cannot delete your own principal".

This prevents accidental account lockouts and ensures administrative continuity.

Password Management

Password Reset Flow

Password resets generate temporary passwords that expire on first use:

  1. Administrator initiates reset

    http
    POST /resources/iam/principals/{id}/password/reset
  2. API returns temporary password

    json
    {
      "temporaryPassword": "TempPass123"
    }
  3. Administrator sends email to user

    Use the Sendings API to send the temporary password:

    http
    POST /resources/sendings
    {
      "category": "password_reset",
      "to": "user@example.com",
      "subject": "Password Reset",
      "bodyHtml": "<p>Your temporary password is: TempPass123</p>"
    }
  4. User logs in with temporary password

    • Session is created but marked as requiring password change
  5. User must change password

    http
    POST /resources/me/password
    {
      "currentPassword": "TempPass123",
      "newPassword": "NewSecurePass456!"
    }

INFO

The IAM API generates the temporary password but does NOT send emails. Email sending is the responsibility of the calling application (e.g., Portal) using the Sendings API.

Password Requirements

Passwords must meet these criteria:

  • Minimum 8 characters
  • At least one uppercase letter
  • At least one lowercase letter
  • At least one digit
  • No common/weak passwords

Invalid passwords will be rejected with an appropriate error message.

Email and Phone Uniqueness

Email addresses and phone numbers must be unique across all principals.

Email Uniqueness

Attempting to create a principal with an existing email address returns an error:

json
{
  "error": {
    "code": "EMAIL_NOT_UNIQUE",
    "message": "Email address already in use"
  }
}

Changing Email Addresses

When you change a principal's email address:

  1. The new email must not be in use by another principal
  2. The change updates the principal's login username automatically (if password authentication is enabled)
  3. The principal must log in with the new email address going forward

Example:

http
PATCH /resources/iam/principals/{id}
If-Match: "etag-value"
{
  "email": "newemail@example.com"
}

TIP

Before creating or updating a principal with an email, you can query existing principals by email using the Graph API to check availability.

Principal Suspension

Principals can be suspended to temporarily block authentication without deleting the account.

Suspension vs Deletion

FeatureSuspensionDeletion
Reversible✅ Yes❌ No
Data retained✅ Yes❌ No
Can authenticate❌ No❌ No
Roles retained✅ Yes❌ No
Visible in API❌ No (by default)❌ No

Suspension Workflow

  1. Suspend the principal

    http
    POST /resources/iam/principals/{id}/suspend
    If-Match: "etag-value"
    • Sets suspension timestamp
    • Automatically revokes all active sessions
    • Principal cannot create new sessions
    • Requires ETag for concurrency control
  2. Principal attempts to log in

    • Authentication fails with "suspended" status
    • Error message: "Account has been suspended"
  3. Reactivate when ready

    http
    POST /resources/iam/principals/{id}/reactivate
    If-Match: "etag-value"
    • Clears suspension timestamp
    • Principal can authenticate again
    • Must log in to create new sessions
    • Requires ETag for concurrency control

When to Use Suspension

✅ Appropriate uses:

  • Security incidents (compromised account)
  • Policy violations (temporary punishment)
  • Account review periods
  • Inactive account cleanup (temporary)
  • Employee leave of absence

❌ Not appropriate:

  • Permanent account removal (use deletion instead)
  • Password changes (use password reset)
  • Role changes (update roles directly)

Session Management

Principals can have multiple active sessions from different devices or applications. The session management endpoints allow viewing and revoking these sessions.

List Sessions

Get all active sessions for a principal:

http
GET /resources/iam/principals/{id}/sessions

Response:

json
[
  {
    "id": "01933e8f-7c45-7123-9abc-sessionid123",
    "type": "interactive",
    "createdAt": "2025-01-07T15:30:00Z",
    "accessTokenExpiresAt": "2025-01-07T16:30:00Z",
    "isCurrent": true,
    "isRevoked": false,
    "revokedAt": null,
    "clientId": "01933e8f-7c45-7123-9abc-clientid456",
    "clientName": "Portal Web App",
    "description": "Chrome on Windows"
  }
]

Session fields:

  • id - Unique session identifier
  • type - Session type (e.g., interactive, api)
  • isCurrent - Whether this is the current session making the request
  • isRevoked - Whether the session has been revoked
  • clientId - OAuth client that created the session
  • clientName - Human-readable client name
  • description - Session description (e.g., browser and device info)

Revoke Session

Revoke a specific session:

http
DELETE /resources/iam/principals/{id}/sessions/{sessionId}

Returns 204 No Content on success. The session is immediately invalidated and cannot be used for further requests.

Session Management Permissions

Session management permissions:

  • Principals can view and revoke their own sessions without special permissions
  • Viewing/revoking another principal's sessions requires iam/principals:read or iam/principals:write permission

This enables self-service session management while allowing administrators to help users who may have lost access.

Access Attributes (ABAC)

Access attributes enable Attribute-Based Access Control (ABAC), allowing you to scope permissions to specific data.

Use case: A store manager should only access orders and inventory for their assigned locations.

Solution: Set channelKey attributes on the principal:

json
{
  "accessAttributes": {
    "channelKey": ["STORE-NYC", "STORE-BOS"]
  }
}

When this principal accesses resources, they can only view/modify data where the resource's channelKey matches one of their attribute values. Attempting to access other channels returns 403 Forbidden.

Example scenarios:

  • Multi-location businesses (store managers)
  • Multi-tenant applications (tenant isolation)
  • Departmental access (only HR records)
  • Regional restrictions (GDPR compliance)

TIP

Access attributes work with any resource that supports attribute-based filtering. The attribute names are customizable based on your domain model.

Integration Patterns

Creating Portal Users

http
PUT /resources/iam/principals/{userId}
{
  "properties": {
    "name": "John Admin",
    "email": "john@company.com"
  },
  "roles": ["system:portal:full"]
}

Then generate a temporary password and send via email using the Sendings API.

Role-Based Filtering

http
GET /resources/iam/principals?rolePrefix=system:portal:

Returns only principals with portal access, useful for building user management UIs.

Bulk Role Assignment

Update multiple principals' roles using the Graph API and batch operations:

http
POST /resources/graph/query
{
  "resource": "identity",
  "filters": [
    { "field": "email", "op": "endsWith", "value": "@company.com" }
  ]
}

Then update each principal's roles individually.

API Endpoints

Principal management endpoints:

  • GET /resources/iam/principals - List principals
  • GET /resources/iam/principals/{id} - Get principal
  • PUT /resources/iam/principals/{id} - Create or update (full)
  • PATCH /resources/iam/principals/{id} - Update properties (partial)
  • DELETE /resources/iam/principals/{id} - Delete principal
  • POST /resources/iam/principals/{id}/suspend - Suspend principal
  • POST /resources/iam/principals/{id}/reactivate - Reactivate principal
  • POST /resources/iam/principals/{id}/password/reset - Reset password
  • PUT /resources/iam/principals/{id}/roles - Update roles
  • PUT /resources/iam/principals/{id}/acl - Update ACL
  • GET /resources/iam/principals/{id}/sessions - List sessions
  • DELETE /resources/iam/principals/{id}/sessions/{sessionId} - Revoke session

For complete endpoint documentation, request/response formats, and error codes, see the HTTP API Reference.

© 2024 Hantera AB. All rights reserved.