OAuth Clients
OAuth clients represent third-party applications that access the Snapbooks API on behalf of users. Before an application can use OAuth2 flows (authorization code, client credentials, or refresh token), it must be registered as a client.
There are two ways to register a client:
- Authenticated registration — Create a client tied to your user account via the authenticated API.
- Dynamic registration — Self-register a client via the public endpoint without prior authentication (RFC 7591).
For details on how to use OAuth clients in authentication flows, see OAuth2 Authentication.
Endpoints
| Method | Endpoint | Description |
|---|---|---|
| POST | /oauth/register | Dynamic client registration (public) |
| POST | /oauth/clients | Create an OAuth client |
| GET | /oauth/clients | List your OAuth clients |
| DELETE | /oauth/clients/{client_id} | Delete an OAuth client |
Dynamic Client Registration
POST /public/v2/oauth/register
Public endpoint for dynamic client registration per RFC 7591. No authentication is required. Rate limited to 10 requests per hour.
Dynamically registered clients are owned by the system user and cannot be listed or managed via the authenticated client endpoints.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| client_name | string | Yes | Display name for the client application |
| redirect_uris | array | Yes | Non-empty array of redirect URIs. Each must use HTTPS or be localhost |
| grant_types | array | No | Allowed grant types. Default: ["authorization_code", "refresh_token"] |
| response_types | array | No | Allowed response types. Default: ["code"]. Only code is supported |
| scope | string | No | Requested scope |
| token_endpoint_auth_method | string | No | Authentication method. Default: client_secret_post. Allowed: client_secret_post, client_secret_basic |
Allowed Grant Types
| Value | Description |
|---|---|
authorization_code |
For user-facing applications |
client_credentials |
For server-to-server access |
refresh_token |
For obtaining new access tokens |
Example Request
{
"client_name": "My Integration",
"redirect_uris": ["https://myapp.example.com/callback"],
"grant_types": ["authorization_code", "refresh_token"],
"scope": "read:accounts"
}
Response
{
"client_id": "AbCdEfGhIjKlMnOpQrStUv",
"client_secret": "AbCdEfGhIjKlMnOpQrStUvWxYz0123456789AbCdEfGhIjKl",
"client_name": "My Integration",
"redirect_uris": ["https://myapp.example.com/callback"],
"grant_types": ["authorization_code", "refresh_token"],
"response_types": ["code"],
"token_endpoint_auth_method": "client_secret_post",
"client_id_issued_at": 1712764800
}
Important: Store the
client_secretsecurely — it will not be retrievable later.
Error Responses
| Status | Description |
|---|---|
| 400 | Missing or invalid client_name |
| 400 | redirect_uris is missing, not an array, or empty |
| 400 | Redirect URI does not use HTTPS and is not localhost |
| 400 | Unsupported grant_types or response_types |
| 400 | Invalid token_endpoint_auth_method |
| 429 | Rate limit exceeded (10 per hour) |
Create an OAuth Client
POST /api/v2/oauth/clients
Creates a new OAuth client tied to the authenticated user.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
| client_name | string | Yes | Display name for the client application |
| redirect_uris | string | Conditional | Space-separated redirect URIs. Required when grant_types includes authorization_code |
| grant_types | string | No | Space-separated grant types. Default: authorization_code refresh_token |
| scope | string | No | Requested scope |
Example Request
{
"client_name": "My Accounting App",
"redirect_uris": "https://myapp.example.com/callback",
"grant_types": "authorization_code refresh_token",
"scope": "read:accounts write:transactions"
}
Response
{
"client_id": "AbCdEfGhIjKlMnOpQrStUv",
"client_secret": "AbCdEfGhIjKlMnOpQrStUvWxYz0123456789AbCdEfGhIjKl",
"client_name": "My Accounting App",
"redirect_uris": "https://myapp.example.com/callback",
"grant_types": "authorization_code refresh_token",
"scope": "read:accounts write:transactions"
}
Important: Store the
client_secretsecurely — it will not be retrievable later.
Error Responses
| Status | Description |
|---|---|
| 400 | Missing client_name |
| 400 | Missing redirect_uris when using authorization code grant |
List OAuth Clients
GET /api/v2/oauth/clients
Returns all OAuth clients owned by the authenticated user. The client_secret is not included in the response.
Response
{
"clients": [
{
"client_id": "AbCdEfGhIjKlMnOpQrStUv",
"client_name": "My Accounting App",
"redirect_uris": "https://myapp.example.com/callback",
"grant_types": "authorization_code refresh_token",
"scope": "read:accounts write:transactions",
"created_at": "2026-03-15T10:00:00.000000"
}
]
}
Delete an OAuth Client
DELETE /api/v2/oauth/clients/{client_id}
Deletes an OAuth client and revokes all associated refresh tokens. The client must be owned by the authenticated user.
Path Parameters
| Parameter | Type | Description |
|---|---|---|
| client_id | string | The OAuth client ID |
Response
{
"status": "success",
"message": "Client deleted"
}
Error Responses
| Status | Description |
|---|---|
| 400 | Client not found or not owned by the authenticated user |
Attributes
OAuth Client
| Attribute | Type | Description |
|---|---|---|
| client_id | string | Unique client identifier (read-only) |
| client_secret | string | Client secret. Only returned on creation |
| client_name | string | Display name for the client application |
| redirect_uris | string or array | Allowed redirect URIs. String (space-separated) for authenticated registration, array for dynamic registration |
| grant_types | string or array | Allowed OAuth grant types |
| scope | string | Token scope |
| created_at | datetime | Creation timestamp (read-only, only in list response) |
Notes
- The authenticated endpoints (
/api/v2/oauth/clients) use space-separated strings forredirect_urisandgrant_types. - The dynamic registration endpoint (
/public/v2/oauth/register) uses arrays forredirect_urisandgrant_types, per RFC 7591. - Deleting a client automatically revokes all associated refresh tokens. Access tokens (JWT) remain valid until they expire.
- Only
codeis supported as aresponse_type.
Related Resources
- OAuth2 Authentication — complete OAuth2 flow documentation
- Users — the user account that owns the client