LIGHT

  • News
  • Docs
  • Community
  • Reddit
  • GitHub
Star

Token Limit Handler

For most OAuth 2.0 cloud service providers, customers are charged based on the number of tokens issued. When a JWT (JSON Web Token) is used, it typically expires within 10 to 20 minutes. Therefore, it’s practical for the client to cache the token within the expiration period to avoid requesting a new token for each API call. This approach also allows the API server to cache the token instead of verifying the signature for every request, as the cryptographic calculation is time-consuming.

OAuth Token Management Strategy for Large Organizations

In large organizations with thousands of applications and APIs, detecting inefficient token usage (such as requesting a new token per API call) is challenging. Several factors contribute to this difficulty:

  • IP Address Detection: Accurately identifying source IP addresses is problematic due to numerous network components between clients and servers.
  • Token Analysis: Each token must be parsed to extract claims, allowing detection of multiple token uses within the expiration period for the same client_id (in the case of client credentials grant type).
  • Performance Impact: Implementing this detection before the token security verification handler would slow down all APIs within the organization.

Given these challenges, applying limits at the OAuth 2.0 provider’s token endpoint seems ideal. However, most cloud OAuth 2.0 providers lack this feature, and standardization is difficult.

Proposed Solution

To create a generic, standardized solution, we propose:

  • Set up a light-gateway instance for all external and internal OAuth 2.0 providers.
  • Route each token request through this light-gateway.
  • Implement a light-4j handler to record all token requests.
  • Use this data to identify applications that are inefficiently requesting new tokens for each API call.

This approach allows for centralized monitoring and management of token usage across the organization, regardless of the specific OAuth 2.0 provider in use.

Deployment Options

There are two options for the light-gateway setup:

  • Dedicated Light-Gateway: A light-gateway specifically for OAuth 2.0 providers only.

  • Pros:

Focused on token management Potentially simpler configuration

  • Cons:

Additional infrastructure to maintain

  • Shared Outbound Light-Gateway: A single light-gateway for all external services, including OAuth 2.0 providers.

  • Pros:

Consolidated infrastructure Potential for broader traffic analysis

  • Cons:

More complex configuration May require more resources to handle diverse traffic

The choice between these options depends on factors such as organizational structure, existing infrastructure, and specific security requirements.

Design

Detailed Design

The light-gateway handler for managing token requests is designed with the following specifications:

Handler Configuration
  • The handler will be part of the default chain.
  • It will match the request path with a list of configured templates for the token request paths, accommodating different paths used by various OAuth 2.0 providers.
Data Management
  • Stateful data is cached in the CacheManager named “token-limit”.
  • Configuration for the CacheManager should be specified in the cache.yml section of the values.yml file.
Handler Positioning
  • The handler must be positioned after the requestInterceptor in the chain, as it depends on the REQUEST_BODY_STRING attachment.
Request Differentiation

The handler differentiates between client_credentials and authorization_code grant types:

  • For client_credentials: The key is composed of client_id and source IP.
  • For authorization_code: The key is composed of client_id, code and source IP.
  • Refresh token is one-time token and it is not handled in this handler.
Duplicate Request Handling

The maximum number of duplicated keys is configurable as duplicateLimit in the config file. When duplicated request counts exceed this number, an action is recommended based on the environment:

  • For lower environments (dev/sit/stg): It is recommended to return an error message to the consumer.
  • For production environment: It is recommended to log the same error in the logs, but not return it to the consumer.

These recommendations allow for flexibility in implementation while providing guidance on best practices for different environments.

Implementation Considerations
  • Flexibility: The design allows for easy adaptation to different OAuth 2.0 providers and organizational needs.
  • Scalability: Using a CacheManager enables efficient handling of large volumes of requests.
  • Security: Differentiating between grant types and using composite keys helps in precise tracking and limiting of token requests.
  • Environment-specific behavior: The different handling for production vs. non-production environments allows for stricter control in lower environments while maintaining service availability in production.

This design ensures that the light-gateway can effectively monitor and manage token requests across various OAuth 2.0 providers, helping to identify and mitigate inefficient token usage patterns.

Configuration

Here is the token-limit.yml config file with default values.

# indicate if the handler is enabled or not. By default, it is enabled.
enabled: ${token-limit.enabled:true}
# return an error if limit is reached. It should be the default behavior on dev/sit/stg. For production,
# a warning message should be logged. Also, this handler can be disabled on production for performance.
errorOnLimit: ${token-limit.errorOnLimit:true}
# The max number of duplicated token requests. Once this number is passed, the limit is triggered. This
# number is set based on the number of client instances as each instance might get its token if there
# is no distributed cache. The duplicated tokens are calculated based on the local in memory cache per
# light-gateway or oauth-kafka instance. Note: cache.yml needs to be configured.
duplicateLimit: ${token-limit.duplicateLimit:2}
# Different OAuth 2.0 providers have different token request path. To make sure that this handler only
# applied to the token endpoint, we define a list of path templates here to ensure request path is matched.
# The following is an example with two different OAuth 2.0 providers in values.yml file.
# token-limit.tokenPathTemplates:
#   - /oauth2/(?<instanceId>[^/]+)/v1/token
#   - /oauth2/(?<instanceId>[^/]+)/token
tokenPathTemplates: ${token-limit.tokenPathTemplates:}

Here is the values.yml file that configures a shared light-gateway instance to router traffic to Okta token endpoint.

# request-injection.yml
request-injection.appliedBodyInjectionPathPrefixes:
  - /v1/flowers
  # This is the path prefix for the Okta token endpoint. We need to add it to inject the request body. 
  - /oauth2


# pathPrefixService.yml
pathPrefixService.mapping:
  # /gateway/Migration/1.0.0: Migration
  /v1/pets: com.networknt.petstore-1.0.0
  /v1/notifications: com.networknt.petstore-1.0.0
  /v1/flowers: com.networknt.petstore-1.0.0
  /v1/documents: com.networknt.petstore-1.0.0
  # This is the path prefix setup for router. It has a service name okta-oauth2
  /oauth2: okta-oauth2


# direct-registry.yml
direct-registry.directUrls:
  com.networknt.petstore-1.0.0: https://localhost:9443
  # Here okta-oauth2 service name is mapped to a Okta host. 
  okta-oauth2: https://networknt.oktapreview.com


# handler.yml
handler.basePath: /
handler.handlers:
.
.
.
  # register the TokenLimitHandler and give it an alias tokenLimit. 
  - com.networknt.token.limit.TokenLimitHandler@tokenLimit

handler.chains.default:
  - exception
.
.
.
  - requestInterceptor
  - responseInterceptor
  - audit
  # put the tokenLimit alias into the default chain after the requestInterceptor
  - tokenLimit

# body.yml
# Need to cache the request body so that we can get the string formated request body from the exchange.
body.cacheRequestBody: true

# security.yml
# Disable the security for /oauth2 so that you don't need a token to access the token endpoint. 
security.skipPathPrefixes: ["/v1/documents", "/v1/pets", "/adm/server/info", "/oauth2"]


# cache.yml
cache.caches:
  - cacheName: jwt
    expiryInMinutes: 15
    maxSize: 100
  - cacheName: jwk
    expiryInMinutes: 129600
    maxSize: 100
  # Add token-limit cache for TokenLimitHandler.
  - cacheName: token-limit
    expiryInMinutes: 15
    maxSize: 100

# token-limit.yml
token-limit.tokenPathTemplates:
  - /oauth2/(?<instanceId>[^/]+)/v1/token

Test

Here is the curl command that access the local gateway.

curl --location --request POST 'https://localhost:8443/oauth2/aus6wg8qoeo4eCbc71d7/v1/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=client_credentials' \
--data-urlencode 'client_id=0oa6wgbkbcF27GoqA1d7' \
--data-urlencode 'client_secret=GInDco_MGt6Fz0oHxmgk1LluEHb6qJ4RQY0MvH3Q' \
--data-urlencode 'scope=petstore.w'

Here is the error response if limit is reached.

{
    "statusCode": 400,
    "code": "ERR10091",
    "message": "TOKEN_LIMIT_ERROR",
    "description": "Too many token requests. Please cache the jwt token on the client side.",
    "severity": "ERROR"
}

Tutorial

  • About Light
    • Overview
    • Testimonials
    • What is Light
    • Features
    • Principles
    • Benefits
    • Roadmap
    • Community
    • Articles
    • Videos
    • License
    • Why Light Platform
  • Getting Started
    • Get Started Overview
    • Environment
    • Light Codegen Tool
    • Light Rest 4j
    • Light Tram 4j
    • Light Graphql 4j
    • Light Hybrid 4j
    • Light Eventuate 4j
    • Light Oauth2
    • Light Portal Service
    • Light Proxy Server
    • Light Router Server
    • Light Config Server
    • Light Saga 4j
    • Light Session 4j
    • Webserver
    • Websocket
    • Spring Boot Servlet
  • Architecture
    • Architecture Overview
    • API Category
    • API Gateway
    • Architecture Patterns
    • CQRS
    • Eco System
    • Event Sourcing
    • Fail Fast vs Fail Slow
    • Integration Patterns
    • JavaEE declining
    • Key Distribution
    • Microservices Architecture
    • Microservices Monitoring
    • Microservices Security
    • Microservices Traceability
    • Modular Monolith
    • Platform Ecosystem
    • Plugin Architecture
    • Scalability and Performance
    • Serverless
    • Service Collaboration
    • Service Mesh
    • SOA
    • Spring is bloated
    • Stages of API Adoption
    • Transaction Management
    • Microservices Cross-cutting Concerns Options
    • Service Mesh Plus
    • Service Discovery
  • Design
    • Design Overview
    • Design First vs Code First
    • Desgin Pattern
    • Service Evolution
    • Consumer Contract and Consumer Driven Contract
    • Handling Partial Failure
    • Idempotency
    • Server Life Cycle
    • Environment Segregation
    • Database
    • Decomposition Patterns
    • Http2
    • Test Driven
    • Multi-Tenancy
    • Why check token expiration
    • WebServices to Microservices
  • Cross-Cutting Concerns
    • Concerns Overview
  • API Styles
    • Light-4j for absolute performance
    • Style Overview
    • Distributed session on IMDG
    • Hybrid Serverless Modularized Monolithic
    • Kafka - Event Sourcing and CQRS
    • REST - Representational state transfer
    • Web Server with Light
    • Websocket with Light
    • Spring Boot Integration
    • Single Page Application
    • GraphQL - A query language for your API
    • Light IBM MQ
    • Light AWS Lambda
    • Chaos Monkey
  • Infrastructure Services
    • Service Overview
    • Light Proxy
    • Light Mesh
    • Light Router
    • Light Portal
    • Messaging Infrastructure
    • Centralized Logging
    • COVID-19
    • Light OAuth2
    • Metrics and Alerts
    • Config Server
    • Tokenization
    • Light Controller
  • Tool Chain
    • Tool Chain Overview
  • Utility Library
  • Service Consumer
    • Service Consumer
  • Development
    • Development Overview
  • Deployment
    • Deployment Overview
    • Frontend Backend
    • Linux Service
    • Windows Service
    • Install Eventuate on Windows
    • Secure API
    • Client vs light-router
    • Memory Limit
    • Deploy to Kubernetes
  • Benchmark
    • Benchmark Overview
  • Tutorial
    • Tutorial Overview
  • Troubleshooting
    • Troubleshoot
  • FAQ
    • FAQ Overview
  • Milestones
  • Contribute
    • Contribute to Light
    • Development
    • Documentation
    • Example
    • Tutorial
“Token Limit Handler” was last updated: October 16, 2024: update token-limit-handler.md for a list of templates (4f4afaf)
Improve this page
  • News
  • Docs
  • Community
  • Reddit
  • GitHub
  • About Light
  • Getting Started
  • Architecture
  • Design
  • Cross-Cutting Concerns
  • API Styles
  • Infrastructure Services
  • Tool Chain
  • Utility Library
  • Service Consumer
  • Development
  • Deployment
  • Benchmark
  • Tutorial
  • Troubleshooting
  • FAQ
  • Milestones
  • Contribute