Skip to content

Principals

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

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:

{
"id": "01933e8f-7c45-7123-9abc-123456789abc",
"type": "principal",
"properties": {
"name": "John Admin",
"email": "[email protected]",
"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:

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

Example - First page:

GET /resources/iam/principals?limit=50

Example - Next page:

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

Example - Previous page:

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

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

GET /resources/iam/principals?search=john

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

Filtering

Filter by roles:

# 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:

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

Sorting

Sort results using the orderBy parameter:

# 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

Combined Queries

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

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):

PUT /resources/iam/principals/{id}
If-Match: "etag-value"
{
"properties": {
"name": "John Admin",
"email": "[email protected]",
"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"]
}
}

Partial Update

Update specific properties without replacing the entire principal:

PATCH /resources/iam/principals/{id}
If-Match: "etag-value"
{
"name": "John Updated",
"email": "[email protected]",
"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:

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

Update ACL

Replace the entire ACL:

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

Get Principal Details

Retrieve a principal with all properties:

GET /resources/iam/principals/{id}

Response includes:

{
"id": "01933e8f-7c45-7123-9abc-123456789abc",
"name": "John Admin",
"email": "[email protected]",
"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:

DELETE /resources/iam/principals/{id}

Returns 204 No Content on success.

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

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

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

    Use the Sendings API to send the temporary password:

    POST /resources/sendings
    {
    "category": "password_reset",
    "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

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

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:

{
"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:

PATCH /resources/iam/principals/{id}
If-Match: "etag-value"
{
"email": "[email protected]"
}

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

    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

    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:

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

Response:

[
{
"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:

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:

{
"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)

Integration Patterns

Creating Portal Users

PUT /resources/iam/principals/{userId}
{
"properties": {
"name": "John Admin",
"email": "[email protected]"
},
"roles": ["system:portal:full"]
}

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

Role-Based Filtering

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:

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.