feat: Apply authentication middleware globally (#7396)

* feat: Apply auth middleware globally

* feat: Remove local auth middleware where it makes sense
This commit is contained in:
Stevche Radevski authored and GitHub committed 2024-05-27 15:24:53 +02:00
1 parent 62ef82f497
commit 10ef32c5a3
52 files changed
+76 -276

No files matched your search

@@ -123,21 +123,31 @@ export const createServer = async (rootDir) => {
if (opts.adminSession) {
const token = jwt.sign(
{
user_id: opts.adminSession.userId || opts.adminSession.jwt?.userId,
domain: "admin",
actor_id: opts.adminSession.userId || opts.adminSession.jwt?.userId,
actor_type: "user",
app_metadata: {
user_id:
opts.adminSession.userId || opts.adminSession.jwt?.userId,
},
},
config.projectConfig.http.jwtSecret!
)
headers.Authorization = `Bearer ${token}`
}
if (opts.clientSession) {
const token = jwt.sign(
{
customer_id:
actor_id:
opts.clientSession.customer_id ||
opts.clientSession.jwt?.customer_id,
domain: "store",
actor_type: "customer",
app_metadata: {
customer_id:
opts.clientSession.customer_id ||
opts.clientSession.jwt?.customer_id,
},
},
config.projectConfig.http.jwtSecret!
)
@@ -154,34 +154,6 @@ describe("RoutesLoader", function () {
expect(res.text).toBe("GET /admin/unprotected")
})
it("should return 200 when customer is authenticated", async () => {
const res = await request("GET", "/store/me/protected", {
clientSession: {
jwt: {
customer_id: "lebron",
},
},
})
expect(res.status).toBe(200)
expect(res.text).toBe("GET /store/protected")
})
// The authentication middleware has changed and is not automatically attached currently
it.skip("should return 401 when customer is not authenticated", async () => {
const res = await request("GET", "/store/me/protected")
expect(res.status).toBe(401)
expect(res.text).toBe("Unauthorized")
})
it("should return 200 when customer route is opted out of authentication", async () => {
const res = await request("GET", "/store/me/unprotected")
expect(res.status).toBe(200)
expect(res.text).toBe("GET /store/unprotected")
})
it("should return the error as JSON when an error is thrown with default error handling", async () => {
const res = await request("GET", "/customers/error")
@@ -5,7 +5,7 @@ import { type Express, json, Router, text, urlencoded } from "express"
import { readdir } from "fs/promises"
import { extname, join, sep } from "path"
import { MedusaRequest, MedusaResponse } from "../../../types/routing"
import { errorHandler } from "../../../utils/middlewares"
import { authenticate, errorHandler } from "../../../utils/middlewares"
import logger from "../../logger"
import {
AsyncRouteHandler,
@@ -298,10 +298,6 @@ export class RoutesLoader {
const config: RouteConfig = {
routes: [],
shouldRequireAdminAuth: false,
shouldRequireCustomerAuth: false,
shouldAppendCustomer: false,
shouldAppendAuthCors: false,
}
/**
@@ -313,6 +309,7 @@ export class RoutesLoader {
? (import_[AUTHTHENTICATE] as boolean)
: true
config.optedOutOfAuth = !shouldRequireAuth
/**
* If the developer has not exported the
* CORS flag we default to true.
@@ -321,29 +318,24 @@ export class RoutesLoader {
import_["CORS"] !== undefined ? (import_["CORS"] as boolean) : true
if (route.startsWith("/admin")) {
config.routeType = "admin"
if (shouldAddCors) {
config.shouldAppendAdminCors = true
}
if (shouldRequireAuth) {
config.shouldRequireAdminAuth = true
}
}
if (route.startsWith("/store")) {
config.shouldAppendCustomer = true
config.routeType = "store"
if (shouldAddCors) {
config.shouldAppendStoreCors = true
}
}
if (route.startsWith("/auth") && shouldAddCors) {
config.shouldAppendAuthCors = true
}
if (shouldRequireAuth && route.startsWith("/store/me")) {
config.shouldRequireCustomerAuth = shouldRequireAuth
config.routeType = "auth"
if (shouldAddCors) {
config.shouldAppendAuthCors = true
}
}
const handlers = Object.keys(import_).filter((key) => {
@@ -587,6 +579,7 @@ export class RoutesLoader {
continue
}
const config = descriptor.config
const routes = descriptor.config.routes
/**
@@ -594,7 +587,7 @@ export class RoutesLoader {
* not opted out of.
*/
if (descriptor.config.shouldAppendAdminCors) {
if (config.shouldAppendAdminCors) {
/**
* Apply the admin cors
*/
@@ -609,7 +602,7 @@ export class RoutesLoader {
)
}
if (descriptor.config.shouldAppendAuthCors) {
if (config.shouldAppendAuthCors) {
/**
* Apply the auth cors
*/
@@ -624,7 +617,7 @@ export class RoutesLoader {
)
}
if (descriptor.config.shouldAppendStoreCors) {
if (config.shouldAppendStoreCors) {
/**
* Apply the store cors
*/
@@ -639,6 +632,24 @@ export class RoutesLoader {
)
}
// We only apply the auth middleware to store routes to populate the auth context. For actual authentication, users can just reapply the middleware.
if (!config.optedOutOfAuth && config.routeType === "store") {
this.router.use(
descriptor.route,
authenticate("customer", ["bearer", "session"], {
allowUnauthenticated: true,
})
)
}
if (!config.optedOutOfAuth && config.routeType === "admin") {
// We probably don't want to allow access to all endpoints using an api key, but it will do until we revamp our routing.
this.router.use(
descriptor.route,
authenticate("user", ["bearer", "session", "api-key"])
)
}
for (const route of routes) {
/**
* Apply the body parser middleware if the route
@@ -36,9 +36,8 @@ export type RouteImplementation = {
}
export type RouteConfig = {
shouldRequireAdminAuth?: boolean
shouldRequireCustomerAuth?: boolean
shouldAppendCustomer?: boolean
optedOutOfAuth?: boolean
routeType?: "admin" | "store" | "auth"
shouldAppendAdminCors?: boolean
shouldAppendStoreCors?: boolean
shouldAppendAuthCors?: boolean