Skip to content

API Keys & Products

API keys and products are managed by the identity service and enforced by the gateway.

API Keys

API keys provide machine-to-machine authentication and a way for users and external systems to call the gateway without an OAuth session.

Key Format

mk_live_<64 hex characters>

The mk_live_ prefix makes keys easy to identify in logs and scrubbing tools. The raw key value is returned once at creation and is never stored — only its SHA-256 hash is kept.

Creating an API Key

POST /api-keys
Authorization: Bearer <user-jwt>
Content-Type: application/json

{
  "name": "My CI pipeline key",
  "scopes": ["workflows:invoke", "workflows:read"],
  "expires_at": "2026-12-31T23:59:59Z"
}

Response (raw key shown once):

{
  "id": "ak_abc123",
  "name": "My CI pipeline key",
  "key": "mk_live_a1b2c3d4...",
  "key_prefix": "mk_live_a",
  "scopes": ["workflows:invoke", "workflows:read"],
  "expires_at": "2026-12-31T23:59:59Z",
  "created_at": "2025-01-15T10:00:00Z"
}

Scope Inheritance

  • If scopes is empty ([]), the key inherits all of the owner's current scopes at request time
  • If scopes is set, the effective scopes are the intersection of the key's declared scopes and the owner's permissions

This means reducing a user's permissions also automatically reduces the key's effective scope — even without regenerating the key.

Key Endpoints

Method Path Auth Description
POST /api-keys User JWT Create new key
GET /api-keys User JWT List own keys (no raw values)
DELETE /api-keys/{id} User JWT Revoke key
POST /api-keys/validate Internal Validate raw key (gateway use only)
GET /admin/api-keys Admin List all keys
DELETE /admin/api-keys/{id} Admin Revoke any key

Revoking Keys

A revoked key is immediately rejected by the identity service. The gateway's 60-second validation cache means a revoked key may still work for up to 60 seconds after revocation.


Products

A product bundles API access rights with a rate-limit quota. Users and groups are assigned products to control how much and what they can call.

Product Model

{
  "id": "pro-tier",
  "name": "Pro Tier",
  "description": "10,000 requests per hour",
  "rate_limit_max_requests": 10000,
  "rate_limit_window_seconds": 3600,
  "allowed_route_ids": "*"
}

allowed_route_ids is either "*" (all routes) or a comma-separated list of route IDs.

Product Endpoints

Method Path Auth Description
GET /products User JWT Own assigned products
POST /products Admin Create product
PUT /products/{id} Admin Update product
DELETE /products/{id} Admin Delete product
PUT /products/{id}/users/{username} Admin Assign to user
DELETE /products/{id}/users/{username} Admin Remove from user
PUT /products/{id}/groups/{group} Admin Assign to group
DELETE /products/{id}/groups/{group} Admin Remove from group

Assignment Priority

When a caller has multiple products (via user + group assignments), the first matching product is used (user direct assignments before group assignments). Configure a fallback_product in the rate_limit_product policy to handle callers with no product assigned.


Product-Based Rate Limiting in Policies

The rate_limit_product policy type applies per-caller quotas using the product system:

type: rate_limit_product
apply_to: ["*"]
apply_to_triggers: ["http"]
strategy: sliding_window
fallback_product: free-tier
on_violation: reject

See Policies Reference for the full policy YAML reference (Forgejo mirror: Policies Reference).