A client represents an application or service identity for OAuth and API access. Clients are how applications authenticate with Hantera without requiring human interaction.
TIP
This page covers clients in depth. For an overview of IAM, see the IAM Overview.
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 flowrefresh_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
INFO
System clients are read-only. They cannot be created, modified, or deleted via the API.
OAuth Configuration
Grant Types
Clients support different OAuth 2.0 grant types:
authorization_code
Standard OAuth authorization flow for user-facing applications.
Flow:
- User redirects to authorization endpoint
- User grants permission
- Client receives authorization code
- 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:
- Client uses refresh token
- 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:
- Client authenticates with client ID and secret
- 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 informationprofile- User profile dataemail- 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_hereclient_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=ABC123Client 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
}WARNING
The client secret is only shown once during creation. Store it securely - it cannot be retrieved later.
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
lastUsedAtfor unused secrets
Listing Secrets
View all active secrets for a client:
GET /resources/iam/clients/{id}/secretsResponse:
[
{
"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"
}
]INFO
The actual secret value is never returned after creation. Only metadata is shown.
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 pagebefore- 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_hereSearch
Search by client name (case-insensitive, partial matches):
GET /resources/iam/clients?search=mobileFiltering
Filter by type:
GET /resources/iam/clients?type=service_accountInclude suspended clients:
# By default, suspended clients are excluded
GET /resources/iam/clients?includeSuspended=trueSorting
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 descClient 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"]
}WARNING
The If-Match header with ETag is required for updates to prevent conflicting changes. Omit it only when creating a new client.
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.
WARNING
Deletion is permanent and cannot be undone. All associated secrets are also deleted.
Integration Patterns
OAuth Authorization Code Flow
Create OAuth client
httpPUT /resources/iam/clients/mobile-app-v1 { "properties": { "name": "Mobile App", "redirectUris": ["myapp://callback"], "grantTypes": ["authorization_code", "refresh_token"] } }Generate client secret
httpPOST /resources/iam/clients/mobile-app-v1/secrets { "description": "Production secret" }Redirect user to authorization endpoint
GET /oauth/authorize? response_type=code& client_id=mobile-app-v1& redirect_uri=myapp://callback& scope=openid%20profile%20orders:readExchange authorization code for tokens
httpPOST /oauth/token { "grant_type": "authorization_code", "code": "auth_code_here", "client_id": "mobile-app-v1", "client_secret": "secret_here", "redirect_uri": "myapp://callback" }Use access token for API calls
httpGET /resources/orders/123 Authorization: Bearer access_token_here
Service Account Pattern
Create service account client
httpPUT /resources/iam/clients/sync-service { "properties": { "name": "Data Sync Service", "grantTypes": ["client_credentials"] }, "roles": ["integration:sync:full"] }Generate long-lived secret
httpPOST /resources/iam/clients/sync-service/secrets { "description": "Production sync service", "expiresAt": "2026-12-31T23:59:59Z" }Obtain access token
httpPOST /oauth/token { "grant_type": "client_credentials", "client_id": "sync-service", "client_secret": "secret_here" }Make API calls
httpGET /resources/orders Authorization: Bearer access_token_here
Secret Rotation
Create new secret (before old expires)
httpPOST /resources/iam/clients/{id}/secrets { "description": "Rotated secret 2025-01", "expiresAt": "2026-01-31T00:00:00Z" }Deploy new secret to application Update environment variables or secret manager
Verify new secret works Test authentication with new secret
Revoke old secret
httpDELETE /resources/iam/clients/{id}/secrets/{old-secret-id}
API Endpoints
Client management endpoints:
GET /resources/iam/clients- List clientsGET /resources/iam/clients/{id}- Get clientPUT /resources/iam/clients/{id}- Create or update (full)PATCH /resources/iam/clients/{id}- Update properties (partial)DELETE /resources/iam/clients/{id}- Delete clientPUT /resources/iam/clients/{id}/roles- Update rolesGET /resources/iam/clients/{id}/secrets- List secretsPOST /resources/iam/clients/{id}/secrets- Create secretDELETE /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
grantTypesconfiguration - Update client to include required grant type
Related Resources
- IAM Overview - Introduction to IAM concepts
- Principals - User identity management
- Authentication Guide - OAuth flows and patterns
- Access Control - Permission patterns
- HTTP API Reference - Complete endpoint documentation