Skip to content

Authentication

Protected endpoints require an API key:

X-API-Key: <api-key>
Standard endpoints accept either AI_HUB_USER_API_KEY or AI_HUB_ADMIN_API_KEY; endpoints using get_admin_api_key() accept only AI_HUB_ADMIN_API_KEY and never accept the user key. A configured, non-empty environment key applicable to the authentication boundary is authoritative: any mismatch returns 403 and never falls back to MongoDB.

If every applicable variable is absent or empty and DATABASE_URL is not set, authentication falls back to the common MongoDB APIKeys collection. The authenticated context retains the stored key, isAdmin and clientId, while dataSource, environment and userEmail fields are ignored. Administrator endpoints require isAdmin: true on this fallback record.

If every applicable variable is absent or empty while DATABASE_URL is set, authentication returns 403; there is no PostgreSQL key lookup. The configured PostgreSQL database remains the complete runtime scope, and the obsolete aihub_api_keys table and its application model were removed by Alembic. Optional bearer JWT validation remains active in both database modes.

Every operation needing an administrator key lives in the Administration application under /admin/api/v1, documented in /admin/docs. A path outside /admin therefore never requires an administrator key.

MongoDB routes use the API key's non-empty clientId for tenant routing, with Client-ID as a fallback, and the fixed smartmobility data source. Keys validated from the environment have no stored clientId, so the same header fallback remains available. Endpoints exposing a separate legacy data_source input keep their documented contract; no data source is read from the authentication record.

The deployment environment is resolved once when FastAPI starts. It uses the trimmed APP_IDENTIFIER_SHORT value unless that variable is missing, empty or equals mutu (case-insensitive); in those cases it uses the trimmed ENV value. Startup fails when neither variable provides a value. The resolved value is shared by the Main API and every mounted application; it is never read from MongoDB or PostgreSQL API-key attributes.

Endpoints that expose an environment query parameter use this resolved value when the parameter is omitted. Swagger displays it as the parameter default. A caller may send the same value explicitly, but a different value, including an empty string, returns 400 because one running instance cannot access another deployment environment.

Documentation access

The generated Zensical site under /docs/, Swagger, ReDoc and the corresponding OpenAPI JSON schemas are public. They do not require an API key or a browser session. Use Authorize to provide X-API-Key before using Try it out on a protected API operation.

Client header

Client-ID is never compared with the value stored on the API key. Endpoints that need tenant routing prefer a non-empty MongoDB clientId, then fall back to this header. Environment-backed keys always use the header fallback because they do not contain a client identifier. If neither source provides a value, authentication still succeeds and the resolved client identifier is None; each endpoint decides whether it can continue without a client database. PostgreSQL never requires this header and never uses it to select data.

The header name is Client-ID, not X-Client-ID.

Legacy-compatible routes

HTTP paths were preserved while routers were moved into their business packages. The /admin segment in a historical URL therefore does not by itself determine the required key.

The following entity-owned routes require the standard API key even though their path still contains /admin:

  • /api/v1/admin/get_user and /api/v1/admin/get_team_members;
  • /api/v1/admin/get_job;
  • /api/v1/admin/get_opportunity.

They appear under the Users, Jobs and Opportunities Swagger categories of the Main API. Operations that genuinely need an administrator key are served by the Administration application under /admin/api/v1.

For backward compatibility, the following routes keep their historical public access and must not be treated as authenticated replacements:

  • GET /jom/admin/get_user;
  • GET /jom/admin/get_number_of_active_users;
  • GET /jom/admin/get_number_of_active_opportunities;
  • POST /jom/admin/get_one_offer_scores;
  • POST /jom/admin/get_one_user_scores;
  • POST /jom/admin/talent_match_insights_by_id;
  • POST /jpm/admin/get_one_user_scores.

New integrations should use the API-key-protected /api/v1/... contracts when an equivalent exists. The public routes remain only to avoid breaking existing clients.

Bearer JWT

Endpoints that enable JWT checking accept an optional bearer token:

Authorization: Bearer <jwt>

When present, the token is validated with the public key at JWT_PUBLIC_KEY_PATH. Only RS256 is accepted, and iat, nbf, exp and sub claims are required. The non-empty sub claim becomes the authenticated user ID. The validated raw bearer token can then be passed to LangGraph tools that need downstream authorization.

An invalid or expired token returns 401. If a bearer token is supplied but the public key is missing or unreadable, the API returns 500 because JWT validation is not configured safely. Omitting the bearer token does not fail endpoints that do not otherwise require a user identity.

Example:

curl 'http://localhost:8000/chatbot/api/v2/chat' \
  --header 'X-API-Key: <api-key>' \
  --header 'Client-ID: 725' \
  --header 'Authorization: Bearer <jwt>' \
  --header 'Content-Type: application/json' \
  --data '{
    "userApplicationId": "user-123",
    "userConversationId": "conversation-123",
    "messageApplicationId": "message-123",
    "sender": "user",
    "type": "text",
    "message": "Show me relevant opportunities",
    "locale": "en",
    "source": "Web",
    "data": {}
  }'