motia icon indicating copy to clipboard operation
motia copied to clipboard

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

Open chamishkadinuwan opened this issue 3 months ago • 5 comments

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

chamishkadinuwan avatar Nov 06 '25 11:11 chamishkadinuwan

I think this is something we really need. Secure by default, open the routes only when required. This would be really helpful when building large production grade systems using motia!

THPubs avatar Nov 10 '25 14:11 THPubs

This is a solid request. Thanks, @chamishkadinuwan - I completely agree with @THPubs. We discussed this internally, and the team is working on addressing this very quickly.

Hey @ytallo, I know I brought this up internally to the team, but can we also address the community members with the update on their contribution?

rohitg00 avatar Nov 20 '25 20:11 rohitg00

Can I work on his feature @chamishkadinuwan, if yes plz assign me

Devnil434 avatar Nov 23 '25 17:11 Devnil434

Thanks for the update! Really appreciate you and the team taking this seriously. Also thanks @ytallo for bringing this to the team internally

chamishkadinuwan avatar Nov 24 '25 04:11 chamishkadinuwan

Also, I will also suggest that instead of using routes only:

Like:

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

We can also use StepName:

Like:

// motia.config.ts
export default {
  api: {
    secureByDefault: true,
    globalMiddleware: [errorMiddleware, corsMiddleware, authMiddleware],
    protected:[
'CreatePet',
'UpdatePet',
'DeletePet',
]
  }
}

Or even a directory within the steps directory, for example:

// motia.config.ts
export default {
  api: {
    secureByDefault: true,
    globalMiddleware: [errorMiddleware, corsMiddleware, authMiddleware],
    protected:[
'products',
'users',
'customers',
]
  }
}

I can work on this and share a solution.

Kaperskyguru avatar Nov 28 '25 12:11 Kaperskyguru