Skip to content
72 changes: 72 additions & 0 deletions .github/demo-assets/TEST_RESULTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
## JWT Auth Fixes — Integration Test Results

All three fixes verified end-to-end against a live LiteLLM proxy with mock JWKS/OIDC server, fake LLM backend, and RSA-signed JWTs.

### Setup

| Component | Port | Description |
|---|---|---|
| Mock JWKS + OIDC | :19900 | Serves `/.well-known/openid-configuration` → `jwks_uri` |
| Fake LLM | :19901 | Returns canned chat completions |
| LiteLLM Proxy | :19902 | JWT auth enabled, `premium_user` patched, `team_id_upsert: true` |

---

### Fix 1: OIDC Discovery URL Resolution

`JWT_PUBLIC_KEY_URL` set to `.well-known/openid-configuration` (not a direct JWKS URL).

| Test | Token | Expected | Got |
|---|---|---|---|
| 1a | Valid JWT (RSA-signed, correct key) | **200** | ✅ **200** — chat completion returned |
| 1b | Tampered JWT (last 5 chars replaced) | **401** | ✅ **401** — "Signature verification failed" |

The proxy correctly fetches the OIDC discovery doc, resolves `jwks_uri`, and validates the JWT signature.

---

### Fix 2: Roles as Array

Config: `team_id_jwt_field: "roles"` — JWT `roles` claim is a JSON array.

| Test | Token Claims | Expected | Got |
|---|---|---|---|
| 2a | `"roles": ["team-beta", "team-gamma"]` | **200** (first element used) | ✅ **200** — `team-beta` extracted, completion returned |
| 2b | `"roles": []` | **401** | ✅ **401** — "No team found in token" |

![Fix 1+2 results](https://raw.githubusercontent.com/BerriAI/litellm/68c86d22396ea4dce14e646dc9298c7b8e5f18ee/.github/demo-assets/fix1_fix2_results.webp)

---

### Fix 3: Dot-notation Error Hint

Config: `team_id_jwt_field: "roles.0"` — common Azure AD misconfiguration.

| Test | Token Claims | Expected | Got |
|---|---|---|---|
| 3 | `"roles": ["team-alpha"]` | **401** with hint | ✅ **401** — hint says: *"Use 'roles' instead — LiteLLM automatically uses the first element when the field value is a list."* |

![Fix 3 results](https://raw.githubusercontent.com/BerriAI/litellm/68c86d22396ea4dce14e646dc9298c7b8e5f18ee/.github/demo-assets/fix3_results.webp)

---

### Unit Tests

13/13 new tests pass:

```
tests/test_litellm/proxy/auth/test_handle_jwt.py::test_resolve_jwks_url_passthrough_for_direct_jwks_url PASSED
tests/test_litellm/proxy/auth/test_handle_jwt.py::test_resolve_jwks_url_resolves_oidc_discovery_document PASSED
tests/test_litellm/proxy/auth/test_handle_jwt.py::test_resolve_jwks_url_caches_resolved_jwks_uri PASSED
tests/test_litellm/proxy/auth/test_handle_jwt.py::test_resolve_jwks_url_raises_if_no_jwks_uri_in_discovery_doc PASSED
tests/test_litellm/proxy/auth/test_handle_jwt.py::test_get_team_id_returns_first_element_when_roles_is_list PASSED
tests/test_litellm/proxy/auth/test_handle_jwt.py::test_get_team_id_returns_first_element_from_multi_value_roles_list PASSED
tests/test_litellm/proxy/auth/test_handle_jwt.py::test_get_team_id_returns_default_when_roles_list_is_empty PASSED
tests/test_litellm/proxy/auth/test_handle_jwt.py::test_get_team_id_still_works_with_string_value PASSED
tests/test_litellm/proxy/auth/test_handle_jwt.py::test_get_team_id_list_result_is_hashable PASSED
tests/test_litellm/proxy/auth/test_handle_jwt.py::test_find_and_validate_specific_team_id_hints_bracket_notation PASSED
tests/test_litellm/proxy/auth/test_handle_jwt.py::test_find_and_validate_specific_team_id_hints_bracket_index_notation PASSED
tests/test_litellm/proxy/auth/test_handle_jwt.py::test_find_and_validate_specific_team_id_no_hint_for_valid_field PASSED
```

All 13 passed ✅
Binary file added .github/demo-assets/fix1_fix2_results.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added .github/demo-assets/fix3_results.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading