Workflow Automation

Secure Internal APIs with Windmill: OAuth2 and JWT Guide

Building internal APIs that handle sensitive data requires robust authentication mechanisms. While external-facing services often rely on standard API keys, internal workflows need more granular control and dynamic credential management. Windmill provides a powerful environment for executing these scripts, but securing them effectively requires a deep understanding of how to integrate modern authentication protocols like OAuth2 and JSON Web Tokens (JWT) directly into your workflow logic.

Why Standard API Keys Fall Short

Traditional static API keys present significant security risks in microservices architectures. They are difficult to rotate without downtime, lack user-specific context, and offer limited scope control. In contrast, OAuth2 and JWT provide stateless, time-bound, and scope-specific access tokens. By embedding these protocols into Windmill scripts, you ensure that every workflow execution operates under least-privilege access controls, reducing the attack surface of your internal infrastructure.

Implementing OAuth2 Client Credentials Flow

The Client Credentials flow is ideal for server-to-server communication in Windmill. This method allows your workflow script to act as the client, requesting an access token from the authorization server without user interaction. Below is a practical example using Python within a Windmill script to handle this flow securely.

import requests
import json

def get_access_token(client_id, client_secret, token_url):
    """
    Retrieves an OAuth2 access token using the Client Credentials grant.
    """
    response = requests.post(
        token_url,
        data={
            'grant_type': 'client_credentials',
            'client_id': client_id,
            'client_secret': client_secret
        },
        headers={'Content-Type': 'application/x-www-form-urlencoded'}
    )
    response.raise_for_status()
    return response.json().get('access_token')

# Example usage in a Windmill script
def main(client_id: str, client_secret: str, token_url: str, target_api_url: str):
    access_token = get_access_token(client_id, client_secret, token_url)
    
    # Use the token in a subsequent API call
    result = requests.get(
        target_api_url,
        headers={'Authorization': f'Bearer {access_token}'}
    )
    
    return json.loads(result.text)

Validating JWTs in Workflow Inputs

When your Windmill workflows are triggered by webhooks or other services, you should validate the JWT provided in the request headers before executing any logic. This ensures that only trusted sources can trigger your workflows. Python's PyJWT library is excellent for this task.

import jwt
import os

def validate_jwt(token: str, secret_key: str):
    """
    Validates a JWT token using a shared secret.
    """
    try:
        payload = jwt.decode(
            token,
            secret_key,
            algorithms=["HS256"]
        )
        return payload
    except jwt.ExpiredSignatureError:
        raise ValueError("Token has expired")
    except jwt.InvalidTokenError:
        raise ValueError("Invalid token")

def main(token: str):
    secret = os.environ.get('JWT_SECRET', 'your-secret-key')
    payload = validate_jwt(token, secret)
    
    # Extract user ID or role from payload
    user_id = payload.get('sub')
    return {'status': 'ok', 'user_id': user_id}

Best Practices for Secret Management

Never hardcode secrets like client IDs, secrets, or JWT keys in your Windmill scripts. Instead, utilize Windmill's built-in secrets management or environment variables. This ensures that sensitive data remains encrypted at rest and is injected securely at runtime. Additionally, implement short-lived tokens wherever possible to minimize the impact of a potential token leak.

Conclusion

Securing internal APIs within Windmill requires a shift from static keys to dynamic, protocol-driven authentication. By integrating OAuth2 for service-to-service communication and JWT for request validation, you create a resilient and secure workflow automation infrastructure. These practices not only protect your data but also simplify the management of access controls across complex microservice landscapes.

Share: