janhq/jan · error

Access forbidden: Check your API key permissions for

Error message

Access forbidden: Check your API key permissions for ${provider.provider}

What it means

Thrown when the provider's /models endpoint responds with HTTP 403. The request was authenticated (or at least not rejected as unauthenticated) but the key or origin lacks permission for this resource, or the server is blocking access (e.g. CORS/origin policy, region block, plan restrictions).

Solutions

  1. Check the API key's permissions/scopes on the provider dashboard and grant model listing access.
  2. Verify the base URL points to the correct provider API and that your plan/region allows it.
  3. For self-hosted servers, allow the tauri://localhost origin or configure CORS/ACL rules.
  4. Try a different (unrestricted) API key via curl to isolate key vs. network blocking.

Example fix

// before: restricted key without read scope
headers['Authorization'] = 'Bearer sk-restricted-no-scope'
// after: use a key with models:list permission
headers['Authorization'] = 'Bearer sk-<key-with-models-read>'
Defensive patterns

Strategy: try-catch

Validate before calling

// Verify key permissions out-of-band before calling:
const res = await fetch(`${provider.base_url}/models`, { headers: { Authorization: `Bearer ${key}` } })
if (res.status === 403) console.warn('Key lacks models:list permission')

Try / catch

try {
  await fetchModelsFromProvider(provider)
} catch (e) {
  if (e instanceof Error && e.message.startsWith('Access forbidden')) {
    showPermissionHelp(provider.provider) // guide user to key scopes/CORS
  }
}

Prevention

When it happens

Trigger: GET `${provider.base_url}/models` returned 403 after all key attempts; typical when the key is valid but scoped without models:list permission, or the remote endpoint rejects the tauri://localhost origin.

Common situations: Restricted/scoped API key without model-list permission; provider blocks requests from browser/webview origins (CORS); organization policy or paid-plan gating; proxy/firewall returning 403; wrong base_url pointing at a service with different ACLs.

Understand the failure class

Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.

Related errors


AI-assisted analysis of janhq/jan@7205d770c1 (2026-09-17). Data as JSON: /api/errors/b4a1c0178f7bf245. Report an issue: GitHub.

Appendix: source

Thrown at web-app/src/services/providers/tauri.ts:208

        lastStatus = response.status
        lastStatusText = response.statusText

        if (
          [401, 403, 429].includes(response.status) &&
          ki < keyAttempts.length - 1
        ) {
          continue
        }

        if (!response.ok) {
          if (response.status === 401) {
            throw new Error(
              `Authentication failed: API key is required or invalid for ${provider.provider}`
            )
          }
          if (response.status === 403) {
            throw new Error(
              `Access forbidden: Check your API key permissions for ${provider.provider}`
            )
          }
          if (response.status === 404) {
            throw new Error(
              `Models endpoint not found for ${provider.provider}. Check the base URL configuration.`
            )
          }
          throw new Error(
            `Failed to fetch models from ${provider.provider}: ${response.status} ${response.statusText}`
          )
        }

        const data = await response.json()

        if (data.data && Array.isArray(data.data)) {
          return data.data
            .map((model: { id: string }) => model.id)

View on GitHub (pinned to 7205d770c1)