Feature Request: Secure-by-Default API Endpoints with Opt-Out for Public Routes
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
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!
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?
Can I work on his feature @chamishkadinuwan, if yes plz assign me
Thanks for the update! Really appreciate you and the team taking this seriously. Also thanks @ytallo for bringing this to the team internally
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.