diff --git a/docs/my-website/docs/proxy/enterprise.md b/docs/my-website/docs/proxy/enterprise.md
index cfd6ab31015..3c6d77cc7a2 100644
--- a/docs/my-website/docs/proxy/enterprise.md
+++ b/docs/my-website/docs/proxy/enterprise.md
@@ -15,8 +15,7 @@ Features:
- ✅ [SSO for Admin UI](./ui.md#✨-enterprise-features)
- ✅ [Audit Logs with retention policy](#audit-logs)
- ✅ [JWT-Auth](./token_auth.md)
- - ✅ [Control available public, private routes (Restrict certain endpoints on proxy)](#control-available-public-private-routes)
- - ✅ [Control available public, private routes](#control-available-public-private-routes)
+ - ✅ [Control available public, private routes](./public_routes.md)
- ✅ [Secret Managers - AWS Key Manager, Google Secret Manager, Azure Key, Hashicorp Vault](../secret)
- ✅ [[BETA] AWS Key Manager v2 - Key Decryption](#beta-aws-key-manager---key-decryption)
- ✅ IP address‑based access control lists
@@ -181,148 +180,7 @@ Expected Response
### Control available public, private routes
-**Restrict certain endpoints of proxy**
-
-:::info
-
-❓ Use this when you want to:
-- make an existing private route -> public
-- set certain routes as admin_only routes
-
-:::
-
-#### Usage - Define public, admin only routes
-
-**Step 1** - Set on config.yaml
-
-
-| Route Type | Optional | Requires Virtual Key Auth | Admin Can Access | All Roles Can Access | Description |
-|------------|----------|---------------------------|-------------------|----------------------|-------------|
-| `public_routes` | ✅ | ❌ | ✅ | ✅ | Routes that can be accessed without any authentication |
-| `admin_only_routes` | ✅ | ✅ | ✅ | ❌ | Routes that can only be accessed by [Proxy Admin](./self_serve#available-roles) |
-| `allowed_routes` | ✅ | ✅ | ✅ | ✅ | Routes are exposed on the proxy. If not set then all routes exposed. |
-
-`LiteLLMRoutes.public_routes` is an ENUM corresponding to the default public routes on LiteLLM. [You can see this here](https://github.com/BerriAI/litellm/blob/main/litellm/proxy/_types.py)
-
-```yaml
-general_settings:
- master_key: sk-1234
- public_routes: ["LiteLLMRoutes.public_routes", "/spend/calculate"] # routes that can be accessed without any auth
- admin_only_routes: ["/key/generate"] # Optional - routes that can only be accessed by Proxy Admin
- allowed_routes: ["/chat/completions", "/spend/calculate", "LiteLLMRoutes.public_routes"] # Optional - routes that can be accessed by anyone after Authentication
-```
-
-**Step 2** - start proxy
-
-```shell
-litellm --config config.yaml
-```
-
-**Step 3** - Test it
-
-
-
-
-
-```shell
-curl --request POST \
- --url 'http://localhost:4000/spend/calculate' \
- --header 'Content-Type: application/json' \
- --data '{
- "model": "gpt-4",
- "messages": [{"role": "user", "content": "Hey, how'\''s it going?"}]
- }'
-```
-
-🎉 Expect this endpoint to work without an `Authorization / Bearer Token`
-
-
-
-
-
-
-**Successful Request**
-
-```shell
-curl --location 'http://0.0.0.0:4000/key/generate' \
---header 'Authorization: Bearer ' \
---header 'Content-Type: application/json' \
---data '{}'
-```
-
-
-**Un-successfull Request**
-
-```shell
- curl --location 'http://0.0.0.0:4000/key/generate' \
---header 'Authorization: Bearer ' \
---header 'Content-Type: application/json' \
---data '{"user_role": "internal_user"}'
-```
-
-**Expected Response**
-
-```json
-{
- "error": {
- "message": "user not allowed to access this route. Route=/key/generate is an admin only route",
- "type": "auth_error",
- "param": "None",
- "code": "403"
- }
-}
-```
-
-
-
-
-
-
-
-**Successful Request**
-
-```shell
-curl http://localhost:4000/chat/completions \
--H "Content-Type: application/json" \
--H "Authorization: Bearer sk-1234" \
--d '{
-"model": "fake-openai-endpoint",
-"messages": [
- {"role": "user", "content": "Hello, Claude"}
-]
-}'
-```
-
-
-**Un-successfull Request**
-
-```shell
-curl --location 'http://0.0.0.0:4000/embeddings' \
---header 'Content-Type: application/json' \
--H "Authorization: Bearer sk-1234" \
---data ' {
-"model": "text-embedding-ada-002",
-"input": ["write a litellm poem"]
-}'
-```
-
-**Expected Response**
-
-```json
-{
- "error": {
- "message": "Route /embeddings not allowed",
- "type": "auth_error",
- "param": "None",
- "code": "403"
- }
-}
-```
-
-
-
-
-
+See [Control Public & Private Routes](./public_routes.md) for detailed documentation on configuring public routes, admin-only routes, allowed routes, and wildcard patterns.
## Spend Tracking
diff --git a/docs/my-website/docs/proxy/public_routes.md b/docs/my-website/docs/proxy/public_routes.md
new file mode 100644
index 00000000000..21a92a00be5
--- /dev/null
+++ b/docs/my-website/docs/proxy/public_routes.md
@@ -0,0 +1,223 @@
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+
+# Control Public & Private Routes
+
+:::info
+
+Requires a LiteLLM Enterprise License. [Get a free trial](https://calendly.com/d/4mp-gd3-k5k/litellm-1-1-onboarding-chat).
+
+:::
+
+Control which routes require authentication and which routes are publicly accessible.
+
+## Route Types
+
+| Route Type | Requires Auth | Description |
+|------------|---------------|-------------|
+| `public_routes` | No | Routes accessible without any authentication |
+| `admin_only_routes` | Yes (Admin only) | Routes only accessible by [Proxy Admin](./self_serve#available-roles) |
+| `allowed_routes` | Yes | Routes exposed on the proxy. If not set, all routes are exposed |
+
+## Quick Start
+
+### Make Routes Public
+
+Allow specific routes to be accessed without authentication:
+
+```yaml
+general_settings:
+ master_key: sk-1234
+ public_routes: ["LiteLLMRoutes.public_routes", "/spend/calculate"]
+```
+
+### Restrict Routes to Admin Only
+
+Restrict certain routes to only be accessible by Proxy Admin:
+
+```yaml
+general_settings:
+ master_key: sk-1234
+ admin_only_routes: ["/key/generate", "/key/delete"]
+```
+
+### Limit Available Routes
+
+Only expose specific routes on the proxy:
+
+```yaml
+general_settings:
+ master_key: sk-1234
+ allowed_routes: ["/chat/completions", "/embeddings", "LiteLLMRoutes.public_routes"]
+```
+
+## Usage Examples
+
+### Define Public, Admin Only, and Allowed Routes
+
+```yaml
+general_settings:
+ master_key: sk-1234
+ public_routes: ["LiteLLMRoutes.public_routes", "/spend/calculate"]
+ admin_only_routes: ["/key/generate"]
+ allowed_routes: ["/chat/completions", "/spend/calculate", "LiteLLMRoutes.public_routes"]
+```
+
+`LiteLLMRoutes.public_routes` is an ENUM corresponding to the default public routes on LiteLLM. [View the source](https://github.com/BerriAI/litellm/blob/main/litellm/proxy/_types.py).
+
+### Testing
+
+
+
+
+
+```shell
+curl --request POST \
+ --url 'http://localhost:4000/spend/calculate' \
+ --header 'Content-Type: application/json' \
+ --data '{
+ "model": "gpt-4",
+ "messages": [{"role": "user", "content": "Hey, how'\''s it going?"}]
+ }'
+```
+
+This endpoint works without an `Authorization` header.
+
+
+
+
+
+**Successful Request (Admin)**
+
+```shell
+curl --location 'http://0.0.0.0:4000/key/generate' \
+--header 'Authorization: Bearer ' \
+--header 'Content-Type: application/json' \
+--data '{}'
+```
+
+**Unsuccessful Request (Non-Admin)**
+
+```shell
+curl --location 'http://0.0.0.0:4000/key/generate' \
+--header 'Authorization: Bearer ' \
+--header 'Content-Type: application/json' \
+--data '{"user_role": "internal_user"}'
+```
+
+**Expected Response**
+
+```json
+{
+ "error": {
+ "message": "user not allowed to access this route. Route=/key/generate is an admin only route",
+ "type": "auth_error",
+ "param": "None",
+ "code": "403"
+ }
+}
+```
+
+
+
+
+
+**Successful Request**
+
+```shell
+curl http://localhost:4000/chat/completions \
+-H "Content-Type: application/json" \
+-H "Authorization: Bearer sk-1234" \
+-d '{
+"model": "fake-openai-endpoint",
+"messages": [
+ {"role": "user", "content": "Hello, Claude"}
+]
+}'
+```
+
+**Unsuccessful Request (Route Not Allowed)**
+
+```shell
+curl --location 'http://0.0.0.0:4000/embeddings' \
+--header 'Content-Type: application/json' \
+-H "Authorization: Bearer sk-1234" \
+--data '{
+"model": "text-embedding-ada-002",
+"input": ["write a litellm poem"]
+}'
+```
+
+**Expected Response**
+
+```json
+{
+ "error": {
+ "message": "Route /embeddings not allowed",
+ "type": "auth_error",
+ "param": "None",
+ "code": "403"
+ }
+}
+```
+
+
+
+
+
+## Advanced: Wildcard Patterns
+
+Use wildcard patterns to match multiple routes at once.
+
+### Syntax
+
+| Pattern | Description | Example |
+|---------|-------------|---------|
+| `/path/*` | Matches any route starting with `/path/` | `/api/*` matches `/api/users`, `/api/users/123` |
+
+
+### Examples
+
+#### Make All Routes Under a Path Public
+
+```yaml
+general_settings:
+ master_key: sk-1234
+ public_routes:
+ - "LiteLLMRoutes.public_routes"
+ - "/api/v1/*" # All routes under /api/v1/
+ - "/health/*" # All health check routes
+```
+
+#### Restrict Admin Routes with Wildcards
+
+```yaml
+general_settings:
+ master_key: sk-1234
+ admin_only_routes:
+ - "/admin/*" # All admin routes
+ - "/internal/*" # All internal routes
+```
+
+### Testing Wildcard Routes
+
+**Config:**
+```yaml
+general_settings:
+ master_key: sk-1234
+ public_routes:
+ - "/public/*"
+```
+
+**Test:**
+```shell
+# This works without auth (matches /public/*)
+curl http://localhost:4000/public/status
+
+# This also works without auth (matches /public/*)
+curl http://localhost:4000/public/health/detailed
+
+# This requires auth (doesn't match /public/*)
+curl http://localhost:4000/private/data
+```
+
diff --git a/docs/my-website/sidebars.js b/docs/my-website/sidebars.js
index 1a0aa352390..21fda61c3f6 100644
--- a/docs/my-website/sidebars.js
+++ b/docs/my-website/sidebars.js
@@ -298,6 +298,7 @@ const sidebars = {
"proxy/custom_auth",
"proxy/ip_address",
"proxy/multiple_admins",
+ "proxy/public_routes",
],
},
{
diff --git a/litellm/proxy/auth/auth_utils.py b/litellm/proxy/auth/auth_utils.py
index e6de65da2bd..c4d0d2f8f1c 100644
--- a/litellm/proxy/auth/auth_utils.py
+++ b/litellm/proxy/auth/auth_utils.py
@@ -251,30 +251,38 @@ def route_in_additonal_public_routes(current_route: str):
- bool - True if the route is defined in public_routes
- bool - False if the route is not defined in public_routes
+ Supports wildcard patterns (e.g., "/api/*" matches "/api/users", "/api/users/123")
In order to use this the litellm config.yaml should have the following in general_settings:
```yaml
general_settings:
master_key: sk-1234
- public_routes: ["LiteLLMRoutes.public_routes", "/spend/calculate"]
+ public_routes: ["LiteLLMRoutes.public_routes", "/spend/calculate", "/api/*"]
```
"""
-
- # check if user is premium_user - if not do nothing
+ from litellm.proxy.auth.route_checks import RouteChecks
from litellm.proxy.proxy_server import general_settings, premium_user
try:
if premium_user is not True:
return False
- # check if this is defined on the config
if general_settings is None:
return False
routes_defined = general_settings.get("public_routes", [])
+
+ # Check exact match first
if current_route in routes_defined:
return True
+ # Check wildcard patterns
+ for route_pattern in routes_defined:
+ if RouteChecks._route_matches_wildcard_pattern(
+ route=current_route, pattern=route_pattern
+ ):
+ return True
+
return False
except Exception as e:
verbose_proxy_logger.error(f"route_in_additonal_public_routes: {str(e)}")
diff --git a/tests/test_litellm/proxy/auth/test_route_checks.py b/tests/test_litellm/proxy/auth/test_route_checks.py
index f9276645a58..4402c09e278 100644
--- a/tests/test_litellm/proxy/auth/test_route_checks.py
+++ b/tests/test_litellm/proxy/auth/test_route_checks.py
@@ -804,4 +804,34 @@ def test_proxy_admin_viewer_can_access_global_spend_tags():
pytest.fail(
f"proxy_admin_viewer should be able to access /global/spend/tags route. Got error: {str(e)}"
)
+
+
+def test_route_in_additional_public_routes_wildcard_match():
+ """
+ Test that route_in_additonal_public_routes supports wildcard patterns.
+ """
+ from litellm.proxy.auth.auth_utils import route_in_additonal_public_routes
+
+ with patch("litellm.proxy.proxy_server.general_settings", {"public_routes": ["/api/*"]}), \
+ patch("litellm.proxy.proxy_server.premium_user", True):
+ # Wildcard should match subpaths
+ assert route_in_additonal_public_routes("/api/users") is True
+ assert route_in_additonal_public_routes("/api/users/123") is True
+ # Should not match different prefix
+ assert route_in_additonal_public_routes("/other/path") is False
+
+
+def test_route_in_additional_public_routes_exact_match():
+ """
+ Test that route_in_additonal_public_routes supports exact matches.
+ """
+ from litellm.proxy.auth.auth_utils import route_in_additonal_public_routes
+
+ with patch("litellm.proxy.proxy_server.general_settings", {"public_routes": ["/health", "/status"]}), \
+ patch("litellm.proxy.proxy_server.premium_user", True):
+ # Exact matches should work
+ assert route_in_additonal_public_routes("/health") is True
+ assert route_in_additonal_public_routes("/status") is True
+ # Non-matching routes should fail
+ assert route_in_additonal_public_routes("/other") is False