Authentication
API keys, token-based auth, rate limits, and CSRF protection.
Ionhour supports two authentication methods: API keys for programmatic access and OAuth tokens for interactive sessions. Which one you need depends on the endpoint you are calling — see the table below before writing any code.
Which credential goes where
| Surface | Base path | Credential |
|---|---|---|
| Integration API | /api/v1/* | ionh_ API key as a Bearer token |
| MCP | POST /api/mcp | ionh_ API key as a Bearer token |
| Dashboard REST API | all other /api/* routes | OAuth session (Keycloak access token) |
| Public endpoints | ping, public status, badges | none |
ionh_ API keys authenticate only /api/v1/* and /api/mcp. Every other REST endpoint in this reference belongs to the dashboard API and rejects API keys with a 401. If you are a third-party service provider wiring your product into Ionhour, start with the Integrations section — it covers everything the Integration API can do.
API Keys
API keys are the recommended way to reach Ionhour from scripts, CI/CD pipelines, and third-party integrations — via the Integration API (/api/v1) and MCP. Each key is scoped to a single workspace.
Creating an API Key
- Navigate to Settings > API Keys in your workspace.
- Click Create API Key.
- Enter a name to identify the key's purpose.
- Copy the key immediately — it will not be shown again.
API keys follow the format ionh_ followed by 32 hex characters (37 characters total).
Using an API Key
Pass the key in the Authorization header on an Integration API or MCP request. GET /api/v1/whoami is the smoke test — it echoes the key's workspace, permission level, and projected role:
curl -H "Authorization: Bearer ionh_your_api_key_here" \
https://api.ionhour.com/api/v1/whoamiKeys carry a permission level (READ_ONLY keys are limited to GET requests) and optional resource restrictions. The full model — levels, scoping, rate limits, and error codes — is documented in Integration API authentication.
Key Management
| Action | Description |
|---|---|
| Create | Generate a new key. Full key shown once. |
| List | View all keys in the workspace. Only the prefix is displayed. |
| Rotate | Generate a new key for an existing record. The old key is invalidated. |
| Revoke | Permanently delete a key. |
Security
- Keys are stored as SHA-256 hashes — Ionhour never stores the plaintext key.
- Only the first 12 characters (prefix) are stored for identification.
- Each key tracks a
lastUsedAttimestamp for auditing. - Keys can be disabled without deleting them.
OAuth Tokens (Web and Mobile)
Interactive applications (like the Ionhour dashboard) use OAuth 2.0 with Keycloak as the identity provider. This is primarily for building custom UIs — most API integrations should use API keys with the Integration API instead.
The dashboard REST endpoints in this reference authenticate with the Keycloak access token — sent automatically as an HttpOnly cookie in browsers, or passed explicitly as Authorization: Bearer <access token> from non-browser clients. Examples in this section write it as $ACCESS_TOKEN.
Web Flow
GET /api/auth/login-url returns a Keycloak authorization URL.POST /api/auth/token exchanges the code for access and refresh tokens.POST /api/auth/refresh renews the access token using the refresh token.Mobile Flow
Mobile apps use PKCE (Proof Key for Code Exchange) for added security:
POST /api/auth/mobile/login-url — returns auth URL with PKCE challenge.POST /api/auth/mobile/token — exchanges code + verifier for tokens (returned in response body, not cookies).POST /api/auth/mobile/refresh — refreshes tokens (accepts refresh token in request body).POST /api/auth/mobile/logout — revokes tokens.CSRF Protection
State-changing requests (POST, PUT, PATCH, DELETE) from web clients require a CSRF token:
- A
csrf_tokencookie is set on login/refresh (JavaScript-accessible). - Include the token in the
X-CSRF-Tokenheader for all state-changing requests. - GET, HEAD, and OPTIONS requests are exempt.
Public Endpoints
These endpoints require no authentication:
| Endpoint | Purpose |
|---|---|
GET /api/signals/ping/:token | Send a heartbeat (GET) |
POST /api/signals/ping/:token | Send a heartbeat with payload (POST) |
GET /api/public/status/:slug | View a public status page |
GET /api/public/status/:slug/feed.rss | Status page RSS feed |
GET /api/public/status/:slug/badge.svg | Status badge |
GET /api/checks/:id/badge | Check status badge |
Rate Limits
Ionhour enforces rate limits to protect the API from abuse. Limits are per client IP address.
Default Limit
100 requests per 60 seconds for all authenticated endpoints.
Auth Endpoints
| Endpoint | Limit |
|---|---|
GET /api/auth/login-url | 5 per 60s |
POST /api/auth/token | 10 per 60s |
POST /api/auth/refresh | 10 per 60s |
POST /api/auth/logout | 10 per 60s |
Public Status Page Endpoints
| Endpoint | Limit |
|---|---|
| Status page data, uptime, history | 30 per 60s |
| Password verification | 5 per 5 minutes |
| Subscription | 5 per 60s |
| RSS/Atom feeds | 10 per 60s |
Rate Limit Response
When the limit is exceeded, the API returns:
HTTP/1.1 429 Too Many RequestsWait for the rate limit window to reset before retrying.
Workspace Scoping
All authenticated requests are scoped to a workspace. The workspace is determined by:
- API keys: The workspace the key was created in.
- OAuth tokens: The workspace selected by the user in the dashboard.
Data from one workspace is never accessible from another, even for the same user. This is enforced at the API level — you cannot query resources across workspaces in a single request.