WARNING: THIS SITE IS A MIRROR OF GITHUB.COM / IT CANNOT LOGIN OR REGISTER ACCOUNTS / THE CONTENTS ARE PROVIDED AS-IS / THIS SITE ASSUMES NO RESPONSIBILITY FOR ANY DISPLAYED CONTENT OR LINKS / IF YOU FOUND SOMETHING MAY NOT GOOD FOR EVERYONE, CONTACT ADMIN AT ilovescratch@foxmail.com
Skip to content

Feature Request: Secure-by-Default API Endpoints with Opt-Out for Public Routes #899

@chamishkadinuwan

Description

@chamishkadinuwan

Problem

Request for Motia to support secure-by-default API endpoints where authentication middleware is automatically applied to all routes unless explicitly marked as public. This would improve security and reduce the risk of accidentally exposing protected endpoints.

Currently, in Motia, every API step requires explicit middleware configuration:

export const config: ApiRouteConfig = {
  type: 'api',
  name: 'GetTaskData',
  path: '/tasks/query',
  method: 'POST',
  middleware: [authMiddleware], // ⚠️ Must remember to add this manually
  // ... rest of config
}

The Problem:
Easy to forget: Developers must remember to add authentication to every protected endpoint
Security risk: A missed middleware means an unprotected endpoint goes to production
Boilerplate: Repetitive code across multiple steps
Maintenance burden: Hard to ensure consistency across a growing codebase
Current Workaround.

I've created a custom solution using a wrapper function, but it requires manual opt-in for every step:

// middlewares/auto-global.middleware.ts
const PUBLIC_ROUTES = [
  "/auth/sign-in",
  "/auth/sign-up",
  "/auth/verify-email",
  // ... etc
];

export function withGlobalMiddleware<T extends ApiRouteConfig>(config: T) {
  if (config.middleware?.length > 0) {
    return config; // Respect custom middleware
  }

  const middleware = [
    errorMiddleware,
    corsMiddleware,
    requestIdMiddleware,
    loggingMiddleware
  ];

  // Apply auth unless it's a public route
  if (!isPublicRoute(config.path)) {
    middleware.push(authMiddleware);
  }

  return { ...config, middleware };
}

Usage:

import { withGlobalMiddleware } from "../../middlewares/auto-global.middleware";

export const config = withGlobalMiddleware({
  type: "api",
  name: "GetTaskData",
  path: "/tasks/query",
  method: "POST",
  // No middleware property needed!
});

Limitations of this approach:
Still requires wrapping every config manually
Easy to forget the wrapper function
No IDE/type-level enforcement
Workaround feels hacky for what should be a framework feature

Questions for the Team
Is there already a recommended pattern for this that I'm missing?
Would this feature align with Motia's design philosophy?

Tech Stack Context:
Motia backend with TypeScript
BetterAuth for session management
Mixed public (auth endpoints) and protected (task management) routes
Need for consistent CORS, error handling, and authentication across all routes

Proposed Solution

Proposed Solution
Add native framework support for secure-by-default endpoints with explicit opt-out:
Option 1: Config-based approach

// motia.config.ts
export default {
  api: {
    secureByDefault: true,
    globalMiddleware: [errorMiddleware, corsMiddleware, authMiddleware],
    publicRoutes: [
      "/auth/sign-in",
      "/auth/sign-up",
      "/health"
    ]
  }
}

Option 2: Step-level opt-out

export const config: ApiRouteConfig = {
  type: 'api',
  name: 'SignIn',
  path: '/auth/sign-in',
  method: 'POST',
  public: true, // ✅ Explicit opt-out
}

Option 3: Hybrid approach

// Global config sets defaults
export default {
  api: {
    defaultMiddleware: [errorMiddleware, corsMiddleware, authMiddleware]
  }
}

// Steps can override with `public: true` or custom middleware
export const config: ApiRouteConfig = {
  public: true, // Skips defaultMiddleware
  // OR
  middleware: [customMiddleware] // Replaces defaultMiddleware
}

Alternatives Considered

No response

Additional Context

No response

Willing to Help Implement?

  • I would like to work/help with this

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions