wso2 / wso2/api-platform

[Bug]: API key id exceeding 40 characters passes application validation but fails with an opaque 500 error due to VARCHAR(40) DB column limit

Open
#3,237 0 comments 0 reactions 1 assignee View on GitHub

@Isuranga-2001 is already working on this.

Since Aug 17, 2026.

Aspect/API Severity/Major Type/Bug
Dominant language
Go
Stars
71
Forks
111
Avg merge
1d 14h
Merged PRs (30d)
110

Description

Please select the area the issue is related to

Platform API

Please select the aspect the issue is related to

Aspect/API (API backends, definitions, contracts, interfaces, OpenAPI)

Description

The API key id field has no length validation in the application layer — apiKeyNameMaxLength = 63 (internal/service/apikey.go:41) is only applied to server-generated names, never to a caller-supplied id. But the actual persisted column, api_keys.handle, is declared VARCHAR(40) in schema.postgres.sql/schema.sql/schema.sqlserver.sql. Any id longer than 40 characters therefore fails at the database layer on Postgres/SQL Server with value too long for type character varying(40), which the handler wraps into an opaque 500 INTERNAL_ERROR — the caller gets no indication the problem is field length.

This is invisible on SQLite (the default dev/CI database), since SQLite doesn't enforce declared VARCHAR(N) length at all — the identical request returns 201 Created there regardless of id length, which is why existing unit tests never catch it.

Steps to Reproduce
  1. Start platform-api against a real Postgres backend:
    docker compose -p platform-api-it -f it/docker-compose.postgres.yaml up -d --wait
    docker exec -i platform-api-it-postgres-1 psql -U postgres -d platform_api_it < internal/database/schema.postgres.sql

  2. Create a config pointing [platform_api.database] at Postgres (driver = "postgres", host = "localhost", port = 55432, user = "postgres", password = "postgres", name = "platform_api_it", sslmode = "disable") and run:
    export $(grep -v '^#' local-dev.env | xargs)
    export APIP_CP_ENCRYPTION_KEY=$(cat resources/keys/encryption.key)
    go run ./cmd/main.go -config <that-config>

  3. Log in and create a project + REST API:

    • TOKEN=$(curl -sk -X POST https://localhost:9243/api/portal/v0.9/auth/login \ --data-urlencode "username=admin" --data-urlencode "password=<admin-password>" \ | python3 -c "import json,sys;print(json.load(sys.stdin)['token'])")
    • curl -sk -X POST https://localhost:9243/api/v0.9/projects -H "Authorization: Bearer $TOKEN" \ -d '{"handle":"repro-proj","displayName":"Repro Project"}'
    • curl -sk -X POST https://localhost:9243/api/v0.9/rest-apis -H "Authorization: Bearer $TOKEN" \ -d '{"displayName":"Repro API","context":"/repro-api","version":"1.0.0","projectId":"repro-project","upstream":{"main":{"url":"https://example.com"}}}'
  4. Create an API key with an id longer than 40 characters (e.g. 63): LONGID=$(python3 -c "print('a'*63)")
    curl -sk -i -X POST https://localhost:9243/api/v0.9/rest-apis/repro-api/api-keys \ -H "Authorization: Bearer $TOKEN" \ -d "{\"id\":\"$LONGID\",\"displayName\":\"Long name key\",\"apiKey\":\"sk_example_1234567890abcdef\"}"

Actual result:

HTTP/2 500
{"status":"error","code":"INTERNAL_ERROR","message":"An unexpected error occurred.","trackingId":"39c2695d-b274-4c66-a150-df890d8fa020"}
with the real cause (value too long for type character varying(40)) only visible in the server log.

Expected result:

Either a clear 400 VALIDATION_FAILED response naming the actual length constraint, or the request should succeed if 63 characters is meant to be a valid id.
Control case (same request, SQLite instead of Postgres): returns 201 Created and silently persists the oversized value — proving the length is enforced inconsistently depending on which database backend is deployed.

Severity Level of the Issue

Severity/Major (Important functionality is broken. Should be prioritized. Doesn't need immediate attention)

Environment Details (with versions)
  • PostgreSQL (repro): 16.15 (Debian, via postgres:16 Docker image)
  • OS: macOS 26.6.1 (build 25G76), arm64
  • Not reproducible on SQLite (schema.sqlite.sql), the default local/CI database

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.