[Proposal] API Key Persistence in Platform API #1284
Replies: 3 comments 2 replies
-
|
I am +1 to use Option 2, but include the hashing for SHA-256 only for the moment. When a new algorithm is needed, we can change the preferred algorithm mentioned in the api-platform config. For the existing keys, we'll have to keep using the existing algorithm and all new keys generated will use the new algorithm. When gateway retrieves the keys, we should give keys with all types of hashes. Although there are some keys with old algorithm, the gateway should not fail the API call with the old API keys. So the gateway should know generated hashes of all API keys without filtering by a specific algorithm. |
Beta Was this translation helpful? Give feedback.
-
|
Please find the Platform API DB schema introducing two new tables for storing API keys along with the hashes according to Option 2 (multi-algorithm hashing) -- Main API Keys table (metadata)
CREATE TABLE api_keys (
id VARCHAR(40) PRIMARY KEY,
resource_type VARCHAR(20) NOT NULL, -- 'rest-api' or 'llm-provider'
resource_id VARCHAR(255) NOT NULL, -- apiId or llmProviderId
name VARCHAR(63) NOT NULL, -- URL-safe identifier
display_name VARCHAR(255) NOT NULL,
masked_api_key VARCHAR(255) NOT NULL,
organization_uuid VARCHAR(40) NOT NULL,
operations TEXT NOT NULL DEFAULT '["*"]',
status VARCHAR(20) NOT NULL DEFAULT 'active',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
created_by VARCHAR(255),
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
expires_at TIMESTAMP,
expires_in_unit VARCHAR(20), -- 'seconds', 'minutes', 'hours', 'days'
expires_in_duration INTEGER,
source VARCHAR(20) NOT NULL DEFAULT 'external',
FOREIGN KEY (organization_uuid) REFERENCES organizations(uuid) ON DELETE CASCADE,
UNIQUE(resource_type, resource_id, name, organization_uuid),
CHECK (resource_type IN ('rest-api', 'llm-provider')),
CHECK (status IN ('active', 'revoked', 'expired')),
CHECK (source IN ('local', 'external'))
);
-- Hash storage table (one row per algorithm per key)
CREATE TABLE api_key_hashes (
id VARCHAR(40) PRIMARY KEY,
api_key_id VARCHAR(40) NOT NULL,
algorithm VARCHAR(20) NOT NULL, -- 'sha256', 'sha512', 'argon2', 'bcrypt'
hash_value VARCHAR(255) NOT NULL, -- Actual hash (64 chars for SHA256, 128 for SHA512, etc.)
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (api_key_id) REFERENCES api_keys(id) ON DELETE CASCADE,
UNIQUE(api_key_id, algorithm), -- One hash per algorithm per key
UNIQUE(hash_value), -- Hash values globally unique
CHECK (algorithm IN ('sha256'))
); The Gateway Controller–side database will also require changes, since the current schema supports saving only one hashed API key in a single table. It will need a two-table structure as well: one table for API key metadata and another for storing hashes. The schema will be similar to the one described above. |
Beta Was this translation helpful? Give feedback.
-
|
According to Option 2, the database schema design has two possible approaches: 1. Single-Table Approach (SHA-256 Only for Now)If we plan to support only the SHA-256 hashing algorithm at this stage, while keeping the design extensible for future algorithms, we can:
Platform API DB -- API Keys table (stores API keys for artifacts with hashes as JSONB)
CREATE TABLE IF NOT EXISTS api_keys (
id VARCHAR(40) PRIMARY KEY,
artifact_uuid VARCHAR(40) NOT NULL,
name VARCHAR(63) NOT NULL,
display_name VARCHAR(255) NOT NULL,
masked_api_key VARCHAR(255) NOT NULL,
api_key_hashes JSONB NOT NULL DEFAULT '{}'::jsonb,
operations TEXT NOT NULL DEFAULT '["*"]',
status VARCHAR(20) NOT NULL CHECK(status IN ('active', 'revoked', 'expired')) DEFAULT 'active',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
created_by VARCHAR(255),
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
expires_at TIMESTAMP,
expires_in_unit VARCHAR(20),
expires_in_duration INTEGER,
source VARCHAR(20) NOT NULL DEFAULT 'external',
FOREIGN KEY (artifact_uuid) REFERENCES artifacts(uuid) ON DELETE CASCADE,
UNIQUE(artifact_uuid, name),
);
-- Index for performance
CREATE INDEX IF NOT EXISTS idx_api_keys_artifact ON api_keys(artifact_uuid);
Gateway Controller DB -- Table for API keys (with hashes stored as JSONB)
CREATE TABLE IF NOT EXISTS api_keys (
id TEXT PRIMARY KEY,
gateway_id TEXT NOT NULL DEFAULT 'platform-gateway-id',
name TEXT NOT NULL,
masked_api_key TEXT NOT NULL,
api_key_hashes JSONB NOT NULL DEFAULT '{}'::jsonb,
apiId TEXT NOT NULL,
operations TEXT NOT NULL DEFAULT '*',
status TEXT NOT NULL CHECK(status IN ('active', 'revoked', 'expired')) DEFAULT 'active',
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
created_by TEXT NOT NULL DEFAULT 'system',
updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
expires_at TIMESTAMPTZ NULL,
expires_in_unit TEXT NULL,
expires_in_duration INTEGER NULL,
source TEXT NOT NULL DEFAULT 'local',
external_ref_id TEXT NULL,
display_name TEXT NOT NULL DEFAULT '',
FOREIGN KEY (apiId) REFERENCES deployments(id) ON DELETE CASCADE,
UNIQUE (apiId, name, gateway_id),
);
CREATE INDEX IF NOT EXISTS idx_api_key_api ON api_keys(apiId); 2. Two-Table Approach (Multi-Algorithm Ready)If we want to prioritize support for multiple hashing algorithms from the beginning, we can:
This approach is more scalable and better suited for multi-algorithm support, but introduces slightly more complexity in the schema design. Platform API DB -- Main API Keys table (metadata)
CREATE TABLE api_keys (
id VARCHAR(40) PRIMARY KEY,
artifact_uuid VARCHAR(255) NOT NULL, -- apiId or llmProviderId
name VARCHAR(63) NOT NULL, -- URL-safe identifier
display_name VARCHAR(255) NOT NULL,
masked_api_key VARCHAR(255) NOT NULL,
operations TEXT NOT NULL DEFAULT '["*"]',
status VARCHAR(20) NOT NULL CHECK(status IN ('active', 'revoked', 'expired')) DEFAULT 'active',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
created_by VARCHAR(255),
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
expires_at TIMESTAMP,
expires_in_unit VARCHAR(20), -- 'seconds', 'minutes', 'hours', 'days'
expires_in_duration INTEGER,
source VARCHAR(20) NOT NULL DEFAULT 'external',
FOREIGN KEY (artifact_uuid) REFERENCES artifacts(uuid) ON DELETE CASCADE,
UNIQUE(artifact_uuid, name)
);
-- Hash storage table (one row per algorithm per key)
CREATE TABLE api_key_hashes (
id VARCHAR(40) PRIMARY KEY,
api_key_id VARCHAR(40) NOT NULL,
algorithm VARCHAR(20) NOT NULL, -- 'sha256', 'sha512', 'argon2', 'bcrypt'
hash_value VARCHAR(255) NOT NULL, -- Actual hash (64 chars for SHA256, 128 for SHA512, etc.)
FOREIGN KEY (api_key_id) REFERENCES api_keys(id) ON DELETE CASCADE,
UNIQUE(api_key_id, algorithm), -- One hash per algorithm per key
);Gateway Controller DB -- Table for API keys
CREATE TABLE IF NOT EXISTS api_keys (
id TEXT PRIMARY KEY,
gateway_id TEXT NOT NULL DEFAULT 'platform-gateway-id',
name TEXT NOT NULL,
masked_api_key TEXT NOT NULL,
apiId TEXT NOT NULL,
operations TEXT NOT NULL DEFAULT '*',
status TEXT NOT NULL CHECK(status IN ('active', 'revoked', 'expired')) DEFAULT 'active',
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
created_by TEXT NOT NULL DEFAULT 'system',
updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
expires_at TIMESTAMPTZ NULL,
expires_in_unit TEXT NULL,
expires_in_duration INTEGER NULL,
source TEXT NOT NULL DEFAULT 'local',
external_ref_id TEXT NULL,
display_name TEXT NOT NULL DEFAULT '',
FOREIGN KEY (apiId) REFERENCES deployments(id) ON DELETE CASCADE,
UNIQUE (apiId, name, gateway_id)
);
-- Hash storage table (one row per algorithm per key)
CREATE TABLE api_key_hashes (
id TEXT PRIMARY KEY,
api_key_id TEXT NOT NULL,
algorithm TEXT NOT NULL, -- 'sha256', 'sha512', 'argon2', 'bcrypt'
hash_value TEXT NOT NULL, -- Actual hash (64 chars for SHA256, 128 for SHA512, etc.)
FOREIGN KEY (api_key_id) REFERENCES api_keys(id) ON DELETE CASCADE,
UNIQUE(api_key_id, algorithm), -- One hash per algorithm per key
); |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Summary
Motivation
Problem Statement
Detailed Design
Overview
Alternatives Considered for the API Key Storage Mechanism
Three implementation options are proposed with different trade-offs:
Option 1: Hash-Only (SHA-256)
Platform API hashes API keys using SHA-256, stores only the hash in the database, and sends the hashed value to the gateway. Gateways also use the SHA-256 algorithm. The gateway stores the hash directly without rehashing it.
Pros:
Cons:
Option 2: Multi-Algorithm Hashing
Platform API supports a predefined set of hashing algorithms (SHA-256, SHA-512, etc.) and stores multiple hashes for each API key. The gateway specifies its preferred algorithm in the sync request:
GET /gateways/{gatewayId}/sync/api-keys?algorithm=sha512. If not specified, the algorithm defaults toSHA-256. Platform API returns only the hashes for the requested algorithm, and the gateway stores and validates keys using its chosen algorithm only.Pros:
Cons:
Option 3: Encryption-Based
Platform API encrypts API keys (e.g., AES-256), stores the encrypted value, decrypts it, and sends plain text to the gateway over TLS. The gateway hashes using its configured algorithm.
Pros:
Cons:
Changes Required
api_keystable with metadata, hashed/encrypted value, masked display value, expiration, api_id, organization_id, audit fields and resource_type(rest-apis/llm-providers)GET /gateways/{gatewayId}/sync/api-keysendpoint for gateways to fetch API keysGateway-to-Key Mapping Logic
Platform API determines which keys to sync based on Gateway type(Self-Hosted/AI):
API keys for REST APIs in the Self-Hosted Gateway:
gatewayIdresource_type='rest-api' AND api_id IN (deployed_api_ids)API keys for LLM Providers in AI Gateways:
resource_type='llm-provider' AND organization_uuid=<gateway_org>API Changes
New api key sync endpoint for Platform API:
Response:
Configuration Changes
Option 1:
No configuration required (SHA-256 hardcoded)
Option 2:
Gateway controller:
Platform API:
Option 3:
Platform API:
Compatibility
Migration Steps
N/A
Open Questions
Beta Was this translation helpful? Give feedback.
All reactions