Skip to main content

Introduction to Serial’s API Authentication

In the world of modern web applications, securing API endpoints is crucial. Serial’s API implementation takes a robust approach to authentication, leveraging Zuplo to support two distinct authentication methods: JSON Web Tokens (JWT) for frontend applications and API keys for direct API access. This dual approach provides flexibility and security for different use cases.

The Foundation: Zuplo Authentication

At the heart of Serial’s authentication system lies Zuplo, a powerful API management tool. Zuplo allows us to define and implement complex authentication policies with ease. Let’s take a closer look at how it’s configured:
{
  "ApiKeyInboundPolicy": [
    {
      "allow_unauthenticated": false
    },
    {
      "allow_unauthenticated": true
    }
  ],
  "SupabaseJwtInboundPolicy": [
    {
      "allow_unauthenticated": false
    },
    {
      "allow_unauthenticated": true
    }
  ],
  "Custom Policy": {
    "export": "checkAuthenticated"
  }
}
This configuration snippet from policies.json shows how we’ve set up both API key and JWT policies, along with a custom authentication check.

JWT Authentication for Frontend Applications

For frontend applications, Serial uses JWT authentication, which is handled by Supabase. When a user logs in through the frontend, Supabase issues a JWT that contains claims about the user, including their role and company ID. The SupabaseJwtInboundPolicy in Zuplo validates these JWTs. Here’s how it works:
  1. The frontend application includes the JWT in the Authorization header of API requests.
  2. Zuplo’s SupabaseJwtInboundPolicy verifies the token’s signature and expiration.
  3. If valid, the user’s claims are extracted and made available to the API handlers.

API Key Authentication for Direct Access

For clients that need to access the API directly, such as third-party integrations or scripts, Serial provides API key authentication. This method is managed by the ApiKeyInboundPolicy in Zuplo. Here’s a glimpse of how API keys are handled in the codebase:
class KeyRequestHandler extends SerialRequestHandler {
  protected async validatePrivileges(
    request: ZuploRequest,
    context: ZuploContext
  ): Promise<any> {
    // Validation logic for API key privileges
  }

  protected async performAction(
    request: ZuploRequest,
    context: ZuploContext
  ): Promise<any> {
    // Logic for creating, retrieving, or deleting API keys
  }
}
This KeyRequestHandler class extends SerialRequestHandler, which is responsible for processing authenticated requests, whether they’re authenticated via JWT or API key.

Role-Based Access Control

Both authentication methods support role-based access control. The SerialRequestHandler class includes methods to validate user privileges based on their role:
abstract class SerialRequestHandler {
  protected abstract validatePrivileges(
    request: ZuploRequest,
    context: ZuploContext
  ): Promise<any>;
}
This abstraction allows for fine-grained control over what actions different user roles can perform, regardless of the authentication method used.

Conclusion

Serial’s approach to API authentication showcases a well-thought-out system that caters to different use cases while maintaining strong security practices. By leveraging Zuplo for policy enforcement, Supabase for user management and JWT handling, and implementing role-based access control along with database-level security, Serial ensures that its API remains both flexible and secure. This dual authentication strategy, supporting both JWTs and API keys, allows Serial to serve a wide range of clients while maintaining tight control over data access and user permissions. It’s a testament to the thoughtful architecture behind Serial’s API design.