Bug description:
I was able to request a token from Microsoft and make a successful request against the litellm proxy even though I should not have been authorized to do so, since the requestor did not have the admin_jwt_scope.
Expected response: 401 Unauthorized
Actual response: 200 OK
We can see here in the logs that an OAuth token was checked with Microsoft for validity on the /discovery/v2.0/keys endpoint - so far so good (it probably even checked the audience (aud) - also good). But there does not seem to follow any check of the scopes (scp) or appRoles (roles) fields on the token after token integrity is confirmed. It just authorizes the request to succeed with 200.
Therefore any application within the same Microsoft tenant (without need for scopes or appRoles) can just make a request and get a 200 response from the litellm proxy instance.
Create app registration for litellm proxy in Azure for the service (see manifest):
{
"name": "LiteLLM_Proxy",
"identifierUris": [
"api://LiteLLM_Proxy-dev"
],
"api": {
"oauth2PermissionScopes": [ # JWT scopes
{
"adminConsentDescription": "Access LiteLLM Proxy Endpoints",
"adminConsentDisplayName": "Access LiteLLM Proxy Endpoints",
"id": "211c4fae-4a66-430a-acbf-3c6cc7cec121", # a uuidv4 identifier I created for the JWT scope
"isEnabled": true,
"type": "User",
"userConsentDescription": "Access LiteLLM Proxy Endpoints",
"userConsentDisplayName": "Access LiteLLM Proxy Endpoints",
"value": "litellm_proxy_endpoints_access" # this is the scope name we used in the litellm config
}
]
}
}
Create another app registration with app id ($MICROSOFT_CLIENT_ID) for the consumer service that calls litellm proxy - we will call it My_Service for that matter.
Create a client secret ($MICROSOFT_CLIENT_SECRET) for My_Service in the azure portal. Note that we do not configure any scopes or appRoles for My_Service.
How to fix this and feedback on how we would like this to work:
This is a diagram of the authorization flow we want to use for our consumers, which are services using OAuth:
Now based on my research and experience from setting our own Python APIs up with Microsoft OAuth, there is a false assumption here:
scopes are used, which are a delegated type of permission and not returned as fields on the JWT, when requesting an access token from Microsoft using the client_credentials flow (see CURL above in steps to reproduce). Hence there cannot be any checks done based on scopes in the code.
As far as I understand, scopes have another use case (for delegated frontend access), and appRoles would be the correct choice for this use case. There's also the distinction between application and user. There are probably other articles out there, but I found this one quickly:
https://medium.com/azurehelp/roles-and-scopes-in-azure-identity-f201d11e253c
Now it could be that we are using your JWT auth feature wrongly for services and it was intended for users via the UI. But in any case this is a bug - and, if you will, in addition to that, a feature request to make this work properly for services.
My suggestion:
use appRoles, since appRoles are meant to be used for service to service authorization and will be included as a field (roles) in the token, when performing the client_credentials flow.
Here's an example app registration defining app roles and a consumer app that has been assigned roles (see manifests).
LiteLLM_Proxy:
{
"name": "LiteLLM_Proxy",
"identifierUris": [
"api://LiteLLM_Proxy-dev"
],
"appRoles": [
{
"allowedMemberTypes": [
"Application"
],
"description": "Grants access to make request against the LiteLLM endpoints.",
"displayName": "Access to LiteLLM Endpoints",
"isEnabled": true,
"value": "LiteLLM.Admin"
}
]
}
Finally, it would be great to make the JWT auth roles more generic by allowing to provide a list of roles that can be mapped to allowed_routes. Currently everything is prefixed with admin_ which assumes one uses Oauth scopes for users and assumes one uses it for admins. We do neither, we would like to use it for services.
What happened?
Bug description: I was able to request a token from Microsoft and make a successful request against the litellm proxy even though I should not have been authorized to do so, since the requestor did not have the
admin_jwt_scope
.Expected response: 401 Unauthorized Actual response: 200 OK
Logs:
We can see here in the logs that an OAuth token was checked with Microsoft for validity on the
/discovery/v2.0/keys
endpoint - so far so good (it probably even checked theaudience (aud)
- also good). But there does not seem to follow any check of thescopes (scp)
orappRoles (roles)
fields on the token after token integrity is confirmed. It just authorizes the request to succeed with 200.Therefore any application within the same Microsoft tenant (without need for
scopes
orappRoles
) can just make a request and get a 200 response from the litellm proxy instance.How to reproduce: I have setup our litellm proxy instance following this guide for JWT auth: https://docs.litellm.ai/docs/proxy/token_auth
We are using Microsoft as an OAuth provider.
These are the steps to reproduce:
$MICROSOFT_CLIENT_ID
) for the consumer service that calls litellm proxy - we will call it My_Service for that matter.$MICROSOFT_CLIENT_SECRET
) for My_Service in the azure portal. Note that we do not configure anyscopes
orappRoles
for My_Service.How to fix this and feedback on how we would like this to work:
This is a diagram of the authorization flow we want to use for our consumers, which are services using OAuth:
Now based on my research and experience from setting our own Python APIs up with Microsoft OAuth, there is a false assumption here:
scopes
are used, which are a delegated type of permission and not returned as fields on the JWT, when requesting an access token from Microsoft using theclient_credentials
flow (see CURL above in steps to reproduce). Hence there cannot be any checks done based on scopes in the code.As far as I understand, scopes have another use case (for delegated frontend access), and
appRoles
would be the correct choice for this use case. There's also the distinction betweenapplication
anduser
. There are probably other articles out there, but I found this one quickly: https://medium.com/azurehelp/roles-and-scopes-in-azure-identity-f201d11e253cNow it could be that we are using your JWT auth feature wrongly for services and it was intended for users via the UI. But in any case this is a bug - and, if you will, in addition to that, a feature request to make this work properly for services.
My suggestion:
appRoles
, since appRoles are meant to be used for service to service authorization and will be included as a field (roles
) in the token, when performing theclient_credentials
flow.Here's an example app registration defining app roles and a consumer app that has been assigned roles (see manifests). LiteLLM_Proxy:
My_Service:
Finally, it would be great to make the JWT auth roles more generic by allowing to provide a list of roles that can be mapped to
allowed_routes
. Currently everything is prefixed withadmin_
which assumes one uses Oauth scopes for users and assumes one uses it for admins. We do neither, we would like to use it for services.Relevant log output
No response
Twitter / LinkedIn details
No response