Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: as a user I want to use the claim in JWT token as a key in limit-count plugin. #11918

Open
vamsipatils opened this issue Jan 16, 2025 · 3 comments
Labels
enhancement New feature or request

Comments

@vamsipatils
Copy link

vamsipatils commented Jan 16, 2025

Description

I would like to enhance the limit-count plugin to support using a jwt-claim value as a key.

Problem Statement

Currently, the limit-count plugin supports only static keys like "var", "var_combination", "constant". However, many real-world scenarios require dynamic rate limiting based on contexts like specific users, tenants, or roles. This capability is particularly relevant when using JWT tokens, as they can contain such contextual information.

Importance

Adding support for JWT claims as keys in the limit-count plugin provides more flexibility in managing API usage. This feature makes it possible to enforce rate limits dynamically based on JWT content, thereby catering to various business use cases such as:

  • Per-User Rate Limiting: Controlling API access for individual users.
  • Tenant-Specific Limits: Enforcing resource usage restrictions at the tenant level.
  • Role-Based Rate Controls: Applying limits depending on user roles.
  • Claim-Based Customization: Leveraging any claim from the JWT token to implement fine-grained rate limiting.

Solution Approach

To achieve this, I propose the following enhancements:

  1. JWT Claim-Based Key Type
    A new key type, jwt_claim, will be introduced. When this key type is selected, the plugin will dynamically extract the specified claim from the JWT token using the in-house JWT library:

    local jwt = require("resty.jwt")  

    If key_type is configured as "jwt_claim", the plugin will decode the token and use the claim value as the rate-limiting key:

    if conf.key_type == "jwt_claim" then  
        local decoded_token, err = jwt:verify(nil, token)  
        key = decoded_token.payload[conf.key]  
    end  

    Here, conf.key specifies the claim field to be used for rate limiting.

  2. Optional Enhancement: Remaining Time in Error Messages
    To improve the user experience, the plugin can dynamically include the remaining reset time in the error message. If $reset_in is present in the rejected_msg configuration, it will be replaced with the actual time remaining:

    local reset_in = string.gsub(conf.rejected_msg, "%$reset_in", resetTimeInSeconds)  
    return conf.rejected_code, { error_msg = reset_in }  

    Example Output:

    {  
        "error_msg": "Too Many Requests. Please retry after 476 seconds."  
    }  

    Although the headers already provide reset time details, including it in the error message makes the information more accessible and user-friendly.

Benefits

  • Dynamic Context-Based Limits: Supports user, tenant, and role-specific rate limiting.
  • Backward Compatibility: The default behavior remains unchanged.
  • Improved User Experience: Clearer feedback through enhanced error messages.

Do you think this change is suitable for a PR?

@dosubot dosubot bot added the enhancement New feature or request label Jan 16, 2025
@darkSheep404
Copy link
Contributor

darkSheep404 commented Jan 20, 2025

in my views, i think limit-count provide feature which key support var and var_combination is enough
in our pratices, we set user info into var in our custom auth plugins.
like

local userInfo = json.decode(res)
  local user_info_json = json.decode(userInfo)
  ctx.var['appUserName'] = user_info_json["username"]
  if user_info_json["userOrg"] ~= ngx.null and user_info_json["userOrg"] ~= nil then
    ctx.var['appUserOrgNo'] = user_info_json["appUserOrg"]["orgNo"]
  end
end

@vamsipatils
Copy link
Author

vamsipatils commented Jan 22, 2025

Thank you @darkSheep404 for your thoughtful response and for sharing your insights on incorporating jwt_claim as a key in the limit-count plugin. While I recognize the practicality of relying on custom authentication plugins, I believe this enhancement offers significant benefits for a diverse set of users and scenarios. Here's a summary of why this feature is valuable:

  1. Minimizing Dependency on Custom Plugins: Native support for jwt_claim in the limit-count plugin eliminates the need for users to develop and maintain custom plugins, making the platform more accessible, especially for those without extensive development resources.

  2. Improved Security: By leveraging JWT claims directly within the plugin, we reduce the need to expose sensitive data in context variables. This approach not only aligns with security best practices but also minimizes potential attack vectors.

  3. Ease of Implementation: JWT-based authentication is widely adopted, and many users are familiar with its configuration. Allowing rate limiting directly through JWT claims streamlines the process and ensures compatibility with common workflows.

  4. Increased Versatility: The ability to define rate limits dynamically based on claims such as user roles, tenant IDs, or custom attributes expands the use cases the plugin can address. This flexibility makes it valuable for environments with diverse and evolving needs.

  5. Seamless Integration: By maintaining backward compatibility, this enhancement ensures no disruption to existing configurations, offering an opt-in capability for those who need it.

While custom plugins undoubtedly have their merits in specific contexts, integrating this functionality into the limit-count plugin provides a more robust, out-of-the-box solution that benefits a broader audience.

@darkSheep404
Copy link
Contributor

darkSheep404 commented Jan 24, 2025

Hi @vamsipatils
You offer a lot of good things about JWT, but I insist that this should be done in a separate jwt-auth plugin.
And then pass username in header or var so that all traffice limit-count,limit-req,limit-conn can be used
Unfortunately, apisix's current jwt-auth plugin works with the apisix consumer, not a generic authentication scenario.

Seems apisix openid-connect plugin with config bearly_only:true can do this too.
It already support set user-info in header, and will be easier to add any other info you want and get them in limit-count using var

Authentication between Services: Set bearer_only to true and configure the introspection_endpoint or public_key attribute. In this scenario, APISIX will reject requests without a token or invalid token in the request header.

Image

I remember that Kong have this type plugin jwt-keycloak too, which is more specifically focused on the jwt auth

But this is just my opinion, you can try to propose a PR and see if the community will accept it

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
Status: 📋 Backlog
Development

No branches or pull requests

2 participants