Skip to content

Clients

A client represents an application or service identity for OAuth and API access. Clients are how applications authenticate with Hantera without requiring human interaction.

What is a Client?

Clients represent applications or services that need to access Hantera APIs - whether they’re mobile apps, web applications, backend services, or third-party integrations.

Key characteristics:

  • OAuth 2.0 configuration (redirect URIs, grant types, scopes)
  • Client secret authentication
  • No password-based login (cannot log in to portal)
  • Can be assigned roles for API access
  • System clients are protected from modification

Example client:

{
"id": "01933e8f-7c45-7123-9abc-123456789xyz",
"type": "client",
"properties": {
"name": "Mobile App",
"description": "iOS and Android mobile application",
"redirectUris": ["myapp://callback", "myapp://logout"],
"grantTypes": ["authorization_code", "refresh_token"],
"scopes": ["openid", "profile", "email"],
"tokenEndpointAuthMethod": "client_secret_post"
},
"roles": ["app:mobile:access"],
"suspendedAt": null
}

When to Use Clients

✅ Use clients for:

  • Third-party integrations
  • Mobile or web applications (OAuth flows)
  • Service-to-service communication
  • Webhook consumers
  • Background jobs requiring API access
  • Developer tools and scripts

❌ Don’t use clients for:

  • Human users needing portal access (use Principals instead)
  • Accounts that need password login (use Principals instead)

Client Types

Interactive Clients

Interactive clients use OAuth flows where a user grants permission to the client.

Characteristics:

  • Require redirect URIs for OAuth callbacks
  • Support authorization code flow
  • User consent required
  • Best for mobile apps, SPAs, web applications

Example use cases:

  • Mobile application that accesses user’s Hantera data
  • Third-party app integration
  • Partner portal access

Grant types:

  • authorization_code - Standard OAuth flow
  • refresh_token - Long-lived access

Example configuration:

{
"properties": {
"name": "Partner Mobile App",
"redirectUris": ["myapp://callback"],
"grantTypes": ["authorization_code", "refresh_token"],
"scopes": ["openid", "profile", "orders:read"]
}
}

Service Accounts

Service accounts are non-interactive clients for server-to-server communication.

Characteristics:

  • No redirect URIs needed
  • Use client credentials flow
  • No user interaction required
  • Best for background services, APIs, batch jobs

Example use cases:

  • Integration service syncing data
  • Scheduled batch processing
  • Webhook receiver
  • Internal microservice

Grant types:

  • client_credentials - Server-to-server flow

Example configuration:

{
"properties": {
"name": "Integration Service",
"description": "Data synchronization service",
"grantTypes": ["client_credentials"]
},
"roles": ["integration:sync:access"]
}

System Clients

System clients are built-in clients managed by Hantera.

Characteristics:

  • Cannot be modified or deleted
  • Reserved for Hantera’s internal use
  • Predefined configuration

OAuth Configuration

Grant Types

Clients support different OAuth 2.0 grant types:

authorization_code

Standard OAuth authorization flow for user-facing applications.

Flow:

  1. User redirects to authorization endpoint
  2. User grants permission
  3. Client receives authorization code
  4. Client exchanges code for access token

Use for:

  • Web applications
  • Mobile applications
  • Single-page applications (SPA)

refresh_token

Allows obtaining new access tokens without user interaction.

Flow:

  1. Client uses refresh token
  2. Receives new access token

Use for:

  • Long-lived sessions
  • Background sync
  • Always combine with authorization_code

client_credentials

Server-to-server authentication without user context.

Flow:

  1. Client authenticates with client ID and secret
  2. Receives access token

Use for:

  • Service accounts
  • Background jobs
  • API integrations
  • Webhook handlers

Redirect URIs

Redirect URIs specify where users are sent after OAuth authorization.

Requirements:

  • Must be HTTPS in production (HTTP allowed for localhost)
  • Custom schemes allowed for mobile apps (e.g., myapp://callback)
  • Exact match required (no wildcards)
  • Multiple URIs supported

Example:

{
"redirectUris": [
"https://app.example.com/oauth/callback",
"https://app.example.com/oauth/logout",
"myapp://callback",
"http://localhost:3000/callback"
]
}

Scopes

Scopes define what permissions the client requests.

Standard OpenID Connect scopes:

  • openid - Basic identity information
  • profile - User profile data
  • email - User email address

Custom Hantera scopes:

  • Resource-based scopes (e.g., orders:read, orders:write)
  • Application-specific scopes

Example:

{
"scopes": [
"openid",
"profile",
"orders:read",
"customers:read"
]
}

Token Endpoint Authentication

Clients authenticate at the token endpoint using different methods:

client_secret_post

Client sends ID and secret in POST body.

POST /oauth/token
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&
code=ABC123&
client_id=client_id_here&
client_secret=secret_here

client_secret_basic

Client sends ID and secret in Authorization header.

POST /oauth/token
Authorization: Basic base64(client_id:client_secret)
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&code=ABC123

Client Secret Management

Creating Secrets

Generate a new client secret:

POST /resources/iam/clients/{id}/secrets
If-Match: "etag-value"
{
"description": "Production API access",
"expiresAt": "2026-01-01T00:00:00Z"
}

Response:

{
"id": "01933e8f-7c45-7123-secret-abc123",
"secret": "sk_live_abcdef123456...",
"description": "Production API access",
"createdAt": "2025-01-07T15:30:00Z",
"expiresAt": "2026-01-01T00:00:00Z",
"lastUsedAt": null
}

Secret Best Practices

Expiration:

  • Always set expiration dates for secrets
  • Rotate secrets before expiration
  • Use short expiration for high-security environments

Description:

  • Document secret purpose
  • Include environment (production, staging)
  • Note the system using the secret

Security:

  • Never commit secrets to version control
  • Use environment variables or secret managers
  • Rotate compromised secrets immediately
  • Monitor lastUsedAt for unused secrets

Listing Secrets

View all active secrets for a client:

GET /resources/iam/clients/{id}/secrets

Response:

[
{
"id": "01933e8f-7c45-7123-secret-abc123",
"description": "Production API access",
"createdAt": "2025-01-07T15:30:00Z",
"expiresAt": "2026-01-01T00:00:00Z",
"lastUsedAt": "2025-01-08T10:00:00Z"
}
]

Revoking Secrets

Delete a client secret:

DELETE /resources/iam/clients/{id}/secrets/{secretId}

Returns 204 No Content on success. The secret is immediately invalidated.

When to revoke:

  • Secret compromised or exposed
  • Secret no longer needed
  • Before secret expiration (graceful rotation)
  • During security incidents

List API Features

The clients list endpoint supports filtering, search, and cursor-based pagination.

Cursor-Based Pagination

All list operations use cursor-based pagination:

Query parameters:

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

Response format:

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

Example:

GET /resources/iam/clients?limit=50
GET /resources/iam/clients?limit=50&after=cursor_here

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

GET /resources/iam/clients?search=mobile

Filtering

Filter by type:

GET /resources/iam/clients?type=service_account

Include suspended clients:

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

Sorting

Sort results using the orderBy parameter:

# Sort by name ascending (default)
GET /resources/iam/clients?orderBy=name asc
# Sort by created date
GET /resources/iam/clients?orderBy=createdAt desc

Client Management

Create or Update Client

Full replacement of a client:

PUT /resources/iam/clients/{id}
If-Match: "etag-value"
{
"properties": {
"name": "Mobile App",
"description": "iOS and Android application",
"redirectUris": ["myapp://callback"],
"grantTypes": ["authorization_code", "refresh_token"],
"scopes": ["openid", "profile", "orders:read"],
"tokenEndpointAuthMethod": "client_secret_post"
},
"roles": ["app:mobile:access"]
}

Partial Update

Update specific properties:

PATCH /resources/iam/clients/{id}
If-Match: "etag-value"
{
"name": "Mobile App v2",
"description": "Updated mobile application"
}

Update Roles

Replace the entire roles list:

PUT /resources/iam/clients/{id}/roles
If-Match: "etag-value"
{
"roles": ["app:mobile:access", "integration:api:read"]
}

Get Client Details

Retrieve a client with all properties:

GET /resources/iam/clients/{id}

Response:

{
"id": "01933e8f-7c45-7123-9abc-123456789xyz",
"name": "Mobile App",
"description": "iOS and Android application",
"redirectUris": ["myapp://callback"],
"grantTypes": ["authorization_code", "refresh_token"],
"scopes": ["openid", "profile", "orders:read"],
"tokenEndpointAuthMethod": "client_secret_post",
"roles": ["app:mobile:access"],
"suspendedAt": null,
"createdAt": "2024-01-01T10:00:00Z",
"etag": "W/\"abc123\""
}

Delete Client

Remove a client permanently:

DELETE /resources/iam/clients/{id}

Returns 204 No Content on success.

Integration Patterns

OAuth Authorization Code Flow

  1. Create OAuth client

    PUT /resources/iam/clients/mobile-app-v1
    {
    "properties": {
    "name": "Mobile App",
    "redirectUris": ["myapp://callback"],
    "grantTypes": ["authorization_code", "refresh_token"]
    }
    }
  2. Generate client secret

    POST /resources/iam/clients/mobile-app-v1/secrets
    {
    "description": "Production secret"
    }
  3. Redirect user to authorization endpoint

    GET /oauth/authorize?
    response_type=code&
    client_id=mobile-app-v1&
    redirect_uri=myapp://callback&
    scope=openid%20profile%20orders:read
  4. Exchange authorization code for tokens

    POST /oauth/token
    {
    "grant_type": "authorization_code",
    "code": "auth_code_here",
    "client_id": "mobile-app-v1",
    "client_secret": "secret_here",
    "redirect_uri": "myapp://callback"
    }
  5. Use access token for API calls

    GET /resources/orders/123
    Authorization: Bearer access_token_here

Service Account Pattern

  1. Create service account client

    PUT /resources/iam/clients/sync-service
    {
    "properties": {
    "name": "Data Sync Service",
    "grantTypes": ["client_credentials"]
    },
    "roles": ["integration:sync:full"]
    }
  2. Generate long-lived secret

    POST /resources/iam/clients/sync-service/secrets
    {
    "description": "Production sync service",
    "expiresAt": "2026-12-31T23:59:59Z"
    }
  3. Obtain access token

    POST /oauth/token
    {
    "grant_type": "client_credentials",
    "client_id": "sync-service",
    "client_secret": "secret_here"
    }
  4. Make API calls

    GET /resources/orders
    Authorization: Bearer access_token_here

Secret Rotation

  1. Create new secret (before old expires)

    POST /resources/iam/clients/{id}/secrets
    {
    "description": "Rotated secret 2025-01",
    "expiresAt": "2026-01-31T00:00:00Z"
    }
  2. Deploy new secret to application Update environment variables or secret manager

  3. Verify new secret works Test authentication with new secret

  4. Revoke old secret

    DELETE /resources/iam/clients/{id}/secrets/{old-secret-id}

API Endpoints

Client management endpoints:

  • GET /resources/iam/clients - List clients
  • GET /resources/iam/clients/{id} - Get client
  • PUT /resources/iam/clients/{id} - Create or update (full)
  • PATCH /resources/iam/clients/{id} - Update properties (partial)
  • DELETE /resources/iam/clients/{id} - Delete client
  • PUT /resources/iam/clients/{id}/roles - Update roles
  • GET /resources/iam/clients/{id}/secrets - List secrets
  • POST /resources/iam/clients/{id}/secrets - Create secret
  • DELETE /resources/iam/clients/{id}/secrets/{secretId} - Revoke secret

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

Security Considerations

Secret Storage

Never:

  • ❌ Commit secrets to version control
  • ❌ Log secrets in plain text
  • ❌ Include secrets in URLs
  • ❌ Send secrets via email
  • ❌ Store secrets in client-side code

Always:

  • ✅ Use environment variables
  • ✅ Use secret management services (AWS Secrets Manager, Azure Key Vault)
  • ✅ Rotate secrets regularly
  • ✅ Set expiration dates
  • ✅ Monitor secret usage

Rate Limiting

Implement rate limiting for client authentication:

  • Prevent brute force attacks
  • Monitor failed authentication attempts
  • Suspend clients with excessive failures

Audit Logging

Track client activity:

  • Authentication attempts
  • API calls made
  • Secret creation/revocation
  • Configuration changes

Troubleshooting

Invalid Client Error

Cause: Client ID doesn’t exist or client is suspended

Solution:

  • Verify client ID is correct
  • Check if client exists: GET /resources/iam/clients/{id}
  • Check if client is suspended (look for suspendedAt)

Invalid Client Secret

Cause: Secret is incorrect, expired, or revoked

Solution:

  • Verify secret is correct
  • Check secret expiration date
  • Generate new secret if needed
  • Ensure secret hasn’t been revoked

Invalid Redirect URI

Cause: Redirect URI doesn’t match client configuration

Solution:

  • Verify exact URI match (including protocol, port, path)
  • Check client configuration: GET /resources/iam/clients/{id}
  • Update client if redirect URI changed

Unsupported Grant Type

Cause: Requested grant type not configured for client

Solution:

  • Check client’s grantTypes configuration
  • Update client to include required grant type