Development/AWS

API Gateway vs. Lambda: Where Should You Validate JWT Tokens?

kozylife 2025. 8. 2. 10:27

When building serverless APIs with AWS Lambda and API Gateway, we face a critical architectural decision: "Where should we handle JWT (JSON Web Token) validation?" This choice might seem straightforward, but it directly impacts your project's security posture, performance characteristics, maintainability, and AWS costs. Making the wrong decision can lead to a complete system refactoring down the road. In this article, we'll dive deep into comparing two primary approaches: API Gateway Authorizers and Individual Lambda Validation, providing you with clear decision criteria for your specific project needs.

Approach 1: API Gateway Authorizer (The Centralized Gatekeeper)

Understanding the Concept

API Gateway Authorizer (formerly Lambda Authorizer) validates JWT tokens before API Gateway invokes your actual Lambda function. Think of it as a security guard at the building entrance who checks credentials before allowing visitors to proceed.

The workflow looks like this:

  1. Client sends API request with JWT token
  2. API Gateway invokes the Authorizer Lambda
  3. Authorizer validates JWT and returns policy
  4. Only valid requests proceed to the business logic Lambda

Pros

  • Centralized Management All authentication logic is managed in one place, ensuring consistency and easy maintenance. When new security requirements emerge or JWT validation logic needs updates, you only need to modify the Authorizer to apply changes across all APIs.
  • Simplified Lambda Logic Each Lambda function can focus solely on business logic, perfectly implementing the Separation of Concerns principle. This dramatically improves code readability and maintainability.
  • Strong Security Invalid requests are blocked before reaching Lambda functions, preventing unnecessary execution and costs. Additionally, security policies can be applied uniformly at the API Gateway level, significantly reducing the risk of security gaps.

Cons

  • Additional Costs Authorizer invocations incur separate charges, which can add up significantly for high-traffic services.
  • Limited Flexibility Implementing very dynamic and granular permission controls per API can become complex. For example, authorization based on real-time user status or external system data can be challenging with the Authorizer pattern.
  • Slight Latency Increase The additional step before Lambda invocation introduces some delay. While typically minimal, this could be a consideration for applications requiring extremely low latency.

Code Example (AWS CDK)

import { Duration } from 'aws-cdk-lib';
import { Function, Runtime, Code } from 'aws-cdk-lib/aws-lambda';
import { RestApi, RequestAuthorizer, IdentitySource } from 'aws-cdk-lib/aws-apigateway';

// Authorizer Lambda function
const authorizer = new Function(this, 'JWTAuthorizer', {
  runtime: Runtime.NODEJS_18_X,
  handler: 'authorizer.handler',
  code: Code.fromAsset('lambda'),
});

// API Gateway Authorizer configuration
const jwtAuthorizer = new RequestAuthorizer(this, 'JWTRequestAuthorizer', {
  handler: authorizer,
  identitySources: [IdentitySource.header('Authorization')],
  resultsCacheTtl: Duration.minutes(5), // Performance optimization through caching
});

// Connect Authorizer to API Gateway
// userHandler is assumed to be a pre-defined Lambda function
const api = new RestApi(this, 'MyAPI');
const resource = api.root.addResource('users');
resource.addMethod('GET', userHandler, {
  authorizer: jwtAuthorizer
});

Approach 2: Individual Lambda Validation (Autonomous Processing)

Understanding the Concept

In this approach, API Gateway passes requests through as proxies, and each Lambda function validates JWT tokens directly using JWT libraries within the function code. It's like each department handling its own security procedures.

Pros

  • Maximum Flexibility You can implement complex and granular permission control logic tailored to each API's characteristics. For example, requiring additional 2FA verification for specific APIs or implementing dynamic authorization based on specific JWT payload fields becomes straightforward.
  • Cost Efficiency No additional Authorizer costs – only Lambda execution costs apply. This is particularly advantageous for projects with low request volumes or cost-sensitive environments.
  • Simple Infrastructure API Gateway configuration becomes simpler, eliminating the need for complex Authorizer setups or permission policy management.

Cons

  • Code Duplication and Maintenance Burden Authentication logic must be copied to all Lambda functions or managed through separate layers or libraries. This burden grows exponentially as teams expand and APIs multiply.
  • Security Omission Risk Accidentally omitting authentication logic when adding new Lambda functions can create critical security vulnerabilities. This risk is particularly high in projects with multiple developers.
  • Business Logic Contamination Authentication code mixed with business logic increases code complexity, leading to more difficult code reviews and higher bug probability.

Code Example (Node.js Lambda)

const jwt = require('jsonwebtoken');
const jwksClient = require('jwks-rsa');

// JWKS client setup (initialize once)
const client = jwksClient({
  jwksUri: 'https://your-auth0-domain/.well-known/jwks.json'
});

const getKey = (header, callback) => {
  client.getSigningKey(header.kid, (err, key) => {
    if (err) {
      return callback(err);
    }
    const signingKey = key.publicKey || key.rsaPublicKey;
    callback(null, signingKey);
  });
};

exports.handler = async (event) => {
  try {
    // [Important] API Gateway converts header keys to lowercase
    const token = event.headers.authorization?.replace('Bearer ', '');
    
    if (!token) {
      return {
        statusCode: 401,
        body: JSON.stringify({ error: 'No token provided' })
      };
    }

    // JWT validation
    const decoded = await new Promise((resolve, reject) => {
      jwt.verify(token, getKey, {
        audience: 'your-api-identifier',
        issuer: 'https://your-auth0-domain/',
        algorithms: ['RS256']
      }, (err, decoded) => {
        if (err) return reject(err);
        resolve(decoded);
      });
    });

    // Execute business logic
    const result = await processBusinessLogic(decoded);
    
    return {
      statusCode: 200,
      body: JSON.stringify(result)
    };
    
  } catch (error) {
    console.error('Token validation error:', error);
    return {
      statusCode: 401,
      body: JSON.stringify({ error: 'Invalid token' })
    };
  }
};

Side-by-Side Comparison: Decision-Making Analysis

Security Policy

  • API Gateway Authorizer: Centralized, high consistency
  • Individual Lambda Validation: Distributed, high flexibility

Maintainability

  • API Gateway Authorizer: Easy (managed in one place)
  • Individual Lambda Validation: Complex (possible code duplication)

Flexibility

  • API Gateway Authorizer: Limited
  • Individual Lambda Validation: Very high

Cost

  • API Gateway Authorizer: Additional Authorizer invocation costs
  • Individual Lambda Validation: Only Lambda execution costs

Performance (Latency)

  • API Gateway Authorizer: Slight additional delay
  • Individual Lambda Validation: Potentially faster

Lambda Code

  • API Gateway Authorizer: Simple (business logic focused)
  • Individual Lambda Validation: Complex (authentication + business logic)

Security Error Risk

  • API Gateway Authorizer: Low
  • Individual Lambda Validation: High

Development Speed

  • API Gateway Authorizer: Fast after initial setup
  • Individual Lambda Validation: Requires authentication code for each function

Conclusion: When to Use What?

Recommend "API Gateway Authorizer" when:

Multiple Microservices Environment When operating 10+ API endpoints or when multiple teams are developing their own services, the centralized management of Authorizers truly shines. Security-First Policy For services requiring high security levels like finance, healthcare, or personal data processing, Authorizers that enable consistent security policy application are strongly recommended. Development Team Efficiency Focus When you want to create an environment where developers can focus solely on core business logic without spending time on authentication logic, Authorizers are the optimal choice.

Recommend "Individual Lambda Validation" when:

High Customization Requirements When different APIs need distinct dynamic authorization logic or when complex business logic is closely tied to authentication using JWT payloads. Small Projects & Cost Sensitivity For projects operating fewer than 5 APIs with low monthly request volumes, you can save on Authorizer costs. Legacy System Integration When migrating existing systems with individual authentication logic per service to serverless, this approach enables gradual transition. Key Message: There's no one-size-fits-all solution. There's only the choice that better fits your specific situation.

Conclusion

Choosing where to validate JWT tokens isn't just a technical decision. It's a comprehensive architectural judgment that considers team size, security requirements, cost constraints, and future scalability.

API Gateway Authorizer represents 'stability and consistency', while individual Lambda validation represents 'flexibility and cost efficiency'. Once you clarify which values your project prioritizes more, the answer will naturally emerge.