OAuth Client Management API
OAuth endpoints are split into two groups. Admin endpoints manage client registrations and require explicit oauth:read or oauth:write permissions. Self-service consent endpoints are available to any authenticated user and require no additional permission beyond a valid Bearer token.
Base path: https://api.ithbat.io/api/v1/
Admin: Client Management
These endpoints are for tenant administrators. All admin endpoints are scoped to the tenant identified by the X-Tenant-ID header.
Permission convention: oauth:read grants list/get access. oauth:write grants create/update/delete/regenerate access.
GET /api/v1/oauth/admin/clients
Permission: oauth:read
List all OAuth clients registered in the tenant.
curl "https://api.ithbat.io/api/v1/oauth/admin/clients" \
-H "Authorization: Bearer <access_token>" \
-H "X-Tenant-ID: <tenant_id>"
Response 200
{
"success": true,
"data": {
"clients": [
{
"id": "d4e5f6a7-b8c9-0123-defa-123456789012",
"tenantId": "3e7a9f12-4b2c-4d8e-a1f0-9c2b3d4e5f6a",
"clientId": "ithbat_client_9f3a2b1c",
"clientSecret": "sk_live_••••••••••••••••••••••••3d7f",
"name": "Mobile App",
"description": "iOS and Android customer-facing application",
"grantTypes": ["authorization_code", "refresh_token"],
"redirectURIs": ["https://app.example.com/callback", "com.example.app://callback"],
"scopes": ["openid", "profile", "email"],
"accessTokenTTL": 3600,
"refreshTokenTTL": 2592000,
"enabled": true,
"createdAt": "2026-01-20T09:00:00Z",
"updatedAt": "2026-02-14T15:30:00Z"
}
],
"total": 1
}
}
GET /api/v1/oauth/admin/clients/{id}
Permission: oauth:read
Get a single OAuth client by its internal ID.
curl "https://api.ithbat.io/api/v1/oauth/admin/clients/d4e5f6a7-b8c9-0123-defa-123456789012" \
-H "Authorization: Bearer <access_token>" \
-H "X-Tenant-ID: <tenant_id>"
Response 200
{
"success": true,
"data": {
"client": {
"id": "d4e5f6a7-b8c9-0123-defa-123456789012",
"tenantId": "3e7a9f12-4b2c-4d8e-a1f0-9c2b3d4e5f6a",
"clientId": "ithbat_client_9f3a2b1c",
"clientSecret": "sk_live_••••••••••••••••••••••••3d7f",
"name": "Mobile App",
"description": "iOS and Android customer-facing application",
"grantTypes": ["authorization_code", "refresh_token"],
"redirectURIs": ["https://app.example.com/callback", "com.example.app://callback"],
"scopes": ["openid", "profile", "email"],
"accessTokenTTL": 3600,
"refreshTokenTTL": 2592000,
"enabled": true,
"createdAt": "2026-01-20T09:00:00Z",
"updatedAt": "2026-02-14T15:30:00Z"
}
}
}
POST /api/v1/oauth/admin/clients
Permission: oauth:write
Register a new OAuth client. The clientId is generated by the server. The clientSecret is returned in full only in this response — store it securely, as subsequent reads return a masked value.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Display name for the client |
description | string | No | Human-readable description |
grantTypes | string[] | Yes | Allowed grant types: authorization_code, client_credentials, refresh_token |
redirectURIs | string[] | No | Required when authorization_code grant is used |
scopes | string[] | No | Scopes the client may request (defaults to ["openid"]) |
accessTokenTTL | integer | No | Access token lifetime in seconds (default: 3600) |
refreshTokenTTL | integer | No | Refresh token lifetime in seconds (default: 2592000) |
enabled | boolean | No | Whether the client is active (default: true) |
curl -X POST "https://api.ithbat.io/api/v1/oauth/admin/clients" \
-H "Authorization: Bearer <access_token>" \
-H "X-Tenant-ID: <tenant_id>" \
-H "Content-Type: application/json" \
-d '{
"name": "Internal Dashboard",
"description": "Internal analytics dashboard using client credentials",
"grantTypes": ["client_credentials"],
"scopes": ["analytics:read", "report:read"],
"accessTokenTTL": 1800
}'
Response 201
{
"success": true,
"data": {
"client": {
"id": "e5f6a7b8-c9d0-1234-efab-234567890123",
"tenantId": "3e7a9f12-4b2c-4d8e-a1f0-9c2b3d4e5f6a",
"clientId": "ithbat_client_7c4e1a9d",
"clientSecret": "sk_live_nR8tKpLmQv2wXzYj0sBuCdEfGhIo4aP6",
"name": "Internal Dashboard",
"description": "Internal analytics dashboard using client credentials",
"grantTypes": ["client_credentials"],
"redirectURIs": [],
"scopes": ["analytics:read", "report:read"],
"accessTokenTTL": 1800,
"refreshTokenTTL": 2592000,
"enabled": true,
"createdAt": "2026-03-19T12:00:00Z",
"updatedAt": "2026-03-19T12:00:00Z"
}
}
}
PUT /api/v1/oauth/admin/clients/{id}
Permission: oauth:write
Update an existing OAuth client. The clientId and clientSecret cannot be modified through this endpoint — use the regenerate-secret endpoint to rotate the secret.
Request Body — All fields optional:
| Field | Type | Description |
|---|---|---|
name | string | Updated display name |
description | string | Updated description |
grantTypes | string[] | Replaces the entire grant types list |
redirectURIs | string[] | Replaces the entire redirect URI list |
scopes | string[] | Replaces the entire scopes list |
accessTokenTTL | integer | Updated access token lifetime in seconds |
refreshTokenTTL | integer | Updated refresh token lifetime in seconds |
enabled | boolean | Enable or disable the client |
curl -X PUT "https://api.ithbat.io/api/v1/oauth/admin/clients/e5f6a7b8-c9d0-1234-efab-234567890123" \
-H "Authorization: Bearer <access_token>" \
-H "X-Tenant-ID: <tenant_id>" \
-H "Content-Type: application/json" \
-d '{
"scopes": ["analytics:read", "report:read", "report:export"],
"accessTokenTTL": 3600
}'
Response 200 — Returns the updated OAuthClientResponse.
DELETE /api/v1/oauth/admin/clients/{id}
Permission: oauth:write
Permanently delete an OAuth client. All active tokens issued to this client are immediately revoked. This action cannot be undone.
curl -X DELETE "https://api.ithbat.io/api/v1/oauth/admin/clients/e5f6a7b8-c9d0-1234-efab-234567890123" \
-H "Authorization: Bearer <access_token>" \
-H "X-Tenant-ID: <tenant_id>"
Response 200
{
"success": true,
"data": null
}
POST /api/v1/oauth/admin/clients/{id}/regenerate-secret
Permission: oauth:write
Generate a new client secret and immediately invalidate the previous one. All active tokens issued with the old secret continue to work until they expire. The new secret is returned in full only in this response.
curl -X POST "https://api.ithbat.io/api/v1/oauth/admin/clients/d4e5f6a7-b8c9-0123-defa-123456789012/regenerate-secret" \
-H "Authorization: Bearer <access_token>" \
-H "X-Tenant-ID: <tenant_id>"
Response 200
{
"success": true,
"data": {
"clientId": "ithbat_client_9f3a2b1c",
"clientSecret": "sk_live_aZ3bW5xQmR7yTpKsNvUeLoGhJcFi9dE2"
}
}
Self-Service: Consent
These endpoints are available to any authenticated user. They support the OAuth 2.0 consent flow and allow users to review and revoke the access they have granted to OAuth clients. No additional permissions beyond a valid Bearer token are required.
GET /api/v1/oauth/clients/{client_id}
Retrieve public information about an OAuth client. Used by the consent screen to display the client's name, description, and requested scopes before the user approves or denies authorization.
curl "https://api.ithbat.io/api/v1/oauth/clients/ithbat_client_9f3a2b1c" \
-H "Authorization: Bearer <access_token>"
Response 200
{
"success": true,
"data": {
"client": {
"clientId": "ithbat_client_9f3a2b1c",
"name": "Mobile App",
"description": "iOS and Android customer-facing application",
"scopes": ["openid", "profile", "email"]
}
}
}
POST /api/v1/oauth/consent
Submit the user's consent decision for a pending authorization request. The loginChallenge value is provided by the authorization server when redirecting to the consent screen.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
loginChallenge | string | Yes | Challenge token from the authorization redirect |
approved | boolean | Yes | true to grant, false to deny authorization |
scopes | string[] | No | Subset of requested scopes to approve (defaults to all requested scopes when approved is true) |
remember | boolean | No | Persist consent so the user is not prompted again (default: false) |
curl -X POST "https://api.ithbat.io/api/v1/oauth/consent" \
-H "Authorization: Bearer <access_token>" \
-H "Content-Type: application/json" \
-d '{
"loginChallenge": "ch_7fK2mPqRsT9vWxYzA4bCdEfG",
"approved": true,
"scopes": ["openid", "profile", "email"],
"remember": true
}'
Response 200
{
"success": true,
"data": {
"redirectTo": "https://app.example.com/callback?code=SplxlOBeZQQYbYS6WxSbIA&state=xyz"
}
}
GET /api/v1/oauth/consents
List all OAuth clients that the authenticated user has granted consent to, along with the approved scopes and grant date.
curl "https://api.ithbat.io/api/v1/oauth/consents" \
-H "Authorization: Bearer <access_token>"
Response 200
{
"success": true,
"data": {
"consents": [
{
"clientId": "ithbat_client_9f3a2b1c",
"clientName": "Mobile App",
"scopes": ["openid", "profile", "email"],
"grantedAt": "2026-03-01T14:22:00Z"
}
],
"total": 1
}
}
DELETE /api/v1/oauth/consents/{client_id}
Revoke the authenticated user's consent for the specified OAuth client. All refresh tokens issued to this client for the user are immediately invalidated. The user will be prompted to consent again on next authorization.
curl -X DELETE "https://api.ithbat.io/api/v1/oauth/consents/ithbat_client_9f3a2b1c" \
-H "Authorization: Bearer <access_token>"
Response 200
{
"success": true,
"data": null
}
OAuth Client Object
| Field | Type | Description |
|---|---|---|
id | string | Internal UUID of the client record |
tenantId | string | UUID of the owning tenant |
clientId | string | Public OAuth 2.0 client identifier |
clientSecret | string | Secret credential — masked in all responses except create and regenerate |
name | string | Display name shown on consent screens |
description | string | Optional human-readable description |
grantTypes | string[] | Allowed OAuth 2.0 grant types |
redirectURIs | string[] | Permitted redirect URIs for authorization_code flow |
scopes | string[] | Scopes this client is permitted to request |
accessTokenTTL | integer | Access token lifetime in seconds |
refreshTokenTTL | integer | Refresh token lifetime in seconds |
enabled | boolean | Whether the client can currently obtain tokens |
createdAt | string | ISO 8601 creation timestamp |
updatedAt | string | ISO 8601 last-updated timestamp |