Skip to main content

Key Validation

The validation endpoint is how Hokusai services verify incoming API keys. It checks that a key is active, not expired, authorized for the requested service, and optionally validates scopes and IP restrictions.

POST /api/v1/keys/validate

info

The validation endpoint is public — it does not require an admin token. This allows any Hokusai microservice to validate keys independently.

Sending API Keys

There are three ways to send an API key for validation, listed in priority order:

curl -X POST https://auth.hokus.ai/api/v1/keys/validate \
-H "Authorization: Bearer hk_live_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"service_id": "prediction"}'

Method 2: X-API-Key Header

curl -X POST https://auth.hokus.ai/api/v1/keys/validate \
-H "X-API-Key: hk_live_YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"service_id": "prediction"}'

Method 3: Request Body

curl -X POST https://auth.hokus.ai/api/v1/keys/validate \
-H "Content-Type: application/json" \
-d '{
"api_key": "hk_live_YOUR_API_KEY",
"service_id": "prediction"
}'
tip

Use the Authorization header for production integrations. It follows the OAuth 2.0 Bearer Token standard and keeps keys out of request bodies and server logs.

Request Parameters

FieldTypeRequiredDescription
service_idstringNoVerify the key is authorized for this service
required_scopestringNoVerify the key has this specific scope
client_ipstringNoCheck IP against the key's allowlist (auto-detected if omitted)
api_keystringNoAPI key (only needed if not sent via header)

Validation Flow

Response

Successful Validation

{
"is_valid": true,
"key_id": "550e8400-e29b-41d4-a716-446655440000",
"user_id": "admin",
"service_id": "prediction",
"scopes": ["predict", "read"],
"rate_limit_per_hour": 5000,
"billing_plan": "free",
"monthly_prediction_limit": null
}

Failed Validation

{
"is_valid": false,
"key_id": null,
"user_id": null,
"service_id": null,
"scopes": null,
"rate_limit_per_hour": null,
"billing_plan": null,
"monthly_prediction_limit": null,
"error": "API key is inactive or has been revoked"
}

Caching Behavior

Validation results are cached in Redis for 5 minutes (configurable via CACHE_TTL). This means:

  • First validation of a key queries the database and caches the result
  • Subsequent validations within 5 minutes are served from cache (under 5ms response time)
  • Key revocation invalidates the cache immediately
  • Key rotation invalidates the old key's cache entry
  • If Redis is unavailable, every validation falls back to a database query
warning

After revoking a key, there may be up to a 5-minute window where cached validation results still return is_valid: true from other service instances. For immediate revocation, consider reducing the CACHE_TTL or triggering a cache flush.

Integration Examples

Python Service Integration

import requests
from functools import wraps
from flask import request, jsonify

AUTH_SERVICE_URL = "https://auth.hokus.ai"

def require_api_key(service_id: str, required_scope: str = None):
"""Decorator to validate API keys on incoming requests."""
def decorator(f):
@wraps(f)
def wrapper(*args, **kwargs):
api_key = request.headers.get("Authorization", "").replace("Bearer ", "")
if not api_key:
api_key = request.headers.get("X-API-Key", "")

if not api_key:
return jsonify({"error": "API key required"}), 401

validation = requests.post(
f"{AUTH_SERVICE_URL}/api/v1/keys/validate",
headers={"Authorization": f"Bearer {api_key}"},
json={
"service_id": service_id,
"required_scope": required_scope,
"client_ip": request.remote_addr,
},
).json()

if not validation.get("is_valid"):
return jsonify({"error": validation.get("error", "Invalid API key")}), 401

request.key_info = validation
return f(*args, **kwargs)
return wrapper
return decorator

@app.route("/predict")
@require_api_key(service_id="prediction", required_scope="predict")
def predict():
# request.key_info contains validation result
rate_limit = request.key_info["rate_limit_per_hour"]
# ... handle prediction

JavaScript / Node.js Integration

const AUTH_SERVICE_URL = "https://auth.hokus.ai";

async function validateApiKey(req) {
const apiKey =
req.headers.authorization?.replace("Bearer ", "") ||
req.headers["x-api-key"];

if (!apiKey) {
throw new Error("API key required");
}

const response = await fetch(`${AUTH_SERVICE_URL}/api/v1/keys/validate`, {
method: "POST",
headers: {
Authorization: `Bearer ${apiKey}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
service_id: "prediction",
client_ip: req.ip,
}),
});

const result = await response.json();
if (!result.is_valid) {
throw new Error(result.error || "Invalid API key");
}

return result;
}

Status Codes

StatusMeaning
200Key is valid
400No API key provided in request
401Key is invalid, expired, revoked, or fails scope/IP checks
500Internal server error

Next Steps