Revamp the authentication setup (#7419)
* feat: Add email pass authentication provider package * feat: Revamp auth module and remove concept of scope * feat: Revamp the auth module to be more standardized in how providers are loaded * feat: Switch from scope to actor type for authentication * feat: Add support for per-actor auth methods * feat: Add emailpass auth provider by default * fix: Add back app_metadata in auth module
This commit is contained in:
1 parent
7b0cfe3b77
commit
8a070d5d85
100 files changed
+991
-1005
No files matched your search
@@ -16,7 +16,7 @@ import { createLinkBody } from "../../utils/validators"
|
||||
export const adminApiKeyRoutesMiddlewares: MiddlewareRoute[] = [
|
||||
{
|
||||
matcher: "/admin/api-keys*",
|
||||
middlewares: [authenticate("admin", ["bearer", "session"])],
|
||||
middlewares: [authenticate("user", ["bearer", "session"])],
|
||||
},
|
||||
{
|
||||
method: ["GET"],
|
||||
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
export const adminCampaignRoutesMiddlewares: MiddlewareRoute[] = [
|
||||
{
|
||||
matcher: "/admin/campaigns*",
|
||||
middlewares: [authenticate("admin", ["bearer", "session", "api-key"])],
|
||||
middlewares: [authenticate("user", ["bearer", "session", "api-key"])],
|
||||
},
|
||||
{
|
||||
method: ["GET"],
|
||||
|
||||
@@ -15,7 +15,7 @@ export const adminCollectionRoutesMiddlewares: MiddlewareRoute[] = [
|
||||
{
|
||||
method: ["ALL"],
|
||||
matcher: "/admin/collections*",
|
||||
middlewares: [authenticate("admin", ["bearer", "session", "api-key"])],
|
||||
middlewares: [authenticate("user", ["bearer", "session", "api-key"])],
|
||||
},
|
||||
|
||||
{
|
||||
|
||||
@@ -8,7 +8,7 @@ export const adminCurrencyRoutesMiddlewares: MiddlewareRoute[] = [
|
||||
{
|
||||
method: ["ALL"],
|
||||
matcher: "/admin/currencies*",
|
||||
middlewares: [authenticate("admin", ["bearer", "session", "api-key"])],
|
||||
middlewares: [authenticate("user", ["bearer", "session", "api-key"])],
|
||||
},
|
||||
{
|
||||
method: ["GET"],
|
||||
|
||||
@@ -15,7 +15,7 @@ export const adminCustomerGroupRoutesMiddlewares: MiddlewareRoute[] = [
|
||||
{
|
||||
method: ["ALL"],
|
||||
matcher: "/admin/customer-groups*",
|
||||
middlewares: [authenticate("admin", ["bearer", "session", "api-key"])],
|
||||
middlewares: [authenticate("user", ["bearer", "session", "api-key"])],
|
||||
},
|
||||
{
|
||||
method: ["GET"],
|
||||
|
||||
@@ -19,7 +19,7 @@ export const adminCustomerRoutesMiddlewares: MiddlewareRoute[] = [
|
||||
{
|
||||
method: ["ALL"],
|
||||
matcher: "/admin/customers*",
|
||||
middlewares: [authenticate("admin", ["bearer", "session", "api-key"])],
|
||||
middlewares: [authenticate("user", ["bearer", "session", "api-key"])],
|
||||
},
|
||||
{
|
||||
method: ["GET"],
|
||||
|
||||
@@ -13,7 +13,7 @@ export const adminDraftOrderRoutesMiddlewares: MiddlewareRoute[] = [
|
||||
{
|
||||
method: ["ALL"],
|
||||
matcher: "/admin/draft-orders*",
|
||||
middlewares: [authenticate("admin", ["bearer", "session", "api-key"])],
|
||||
middlewares: [authenticate("user", ["bearer", "session", "api-key"])],
|
||||
},
|
||||
{
|
||||
method: ["GET"],
|
||||
|
||||
@@ -8,7 +8,7 @@ export const adminFulfillmentProvidersRoutesMiddlewares: MiddlewareRoute[] = [
|
||||
{
|
||||
method: "ALL",
|
||||
matcher: "/admin/fulfillment-providers*",
|
||||
middlewares: [authenticate("admin", ["session", "bearer", "api-key"])],
|
||||
middlewares: [authenticate("user", ["session", "bearer", "api-key"])],
|
||||
},
|
||||
{
|
||||
method: ["GET"],
|
||||
|
||||
@@ -14,7 +14,7 @@ export const adminFulfillmentSetsRoutesMiddlewares: MiddlewareRoute[] = [
|
||||
{
|
||||
method: "ALL",
|
||||
matcher: "/admin/fulfillment-sets*",
|
||||
middlewares: [authenticate("admin", ["session", "bearer", "api-key"])],
|
||||
middlewares: [authenticate("user", ["session", "bearer", "api-key"])],
|
||||
},
|
||||
{
|
||||
method: ["POST"],
|
||||
|
||||
@@ -14,7 +14,7 @@ export const adminFulfillmentsRoutesMiddlewares: MiddlewareRoute[] = [
|
||||
{
|
||||
method: "ALL",
|
||||
matcher: "/admin/fulfillments*",
|
||||
middlewares: [authenticate("admin", ["session", "bearer", "api-key"])],
|
||||
middlewares: [authenticate("user", ["session", "bearer", "api-key"])],
|
||||
},
|
||||
{
|
||||
method: ["POST"],
|
||||
|
||||
@@ -20,7 +20,7 @@ export const adminInventoryRoutesMiddlewares: MiddlewareRoute[] = [
|
||||
{
|
||||
method: "ALL",
|
||||
matcher: "/admin/inventory-items*",
|
||||
middlewares: [authenticate("admin", ["session", "bearer", "api-key"])],
|
||||
middlewares: [authenticate("user", ["session", "bearer", "api-key"])],
|
||||
},
|
||||
{
|
||||
method: ["GET"],
|
||||
|
||||
@@ -18,7 +18,7 @@ export const adminInviteRoutesMiddlewares: MiddlewareRoute[] = [
|
||||
method: ["GET"],
|
||||
matcher: "/admin/invites",
|
||||
middlewares: [
|
||||
authenticate("admin", ["session", "bearer", "api-key"]),
|
||||
authenticate("user", ["session", "bearer", "api-key"]),
|
||||
validateAndTransformQuery(
|
||||
AdminGetInvitesParams,
|
||||
QueryConfig.listTransformQueryConfig
|
||||
@@ -29,7 +29,7 @@ export const adminInviteRoutesMiddlewares: MiddlewareRoute[] = [
|
||||
method: ["POST"],
|
||||
matcher: "/admin/invites",
|
||||
middlewares: [
|
||||
authenticate("admin", ["session", "bearer", "api-key"]),
|
||||
authenticate("user", ["session", "bearer", "api-key"]),
|
||||
validateAndTransformBody(AdminCreateInvite),
|
||||
validateAndTransformQuery(
|
||||
AdminGetInviteParams,
|
||||
@@ -41,7 +41,7 @@ export const adminInviteRoutesMiddlewares: MiddlewareRoute[] = [
|
||||
method: "POST",
|
||||
matcher: "/admin/invites/accept",
|
||||
middlewares: [
|
||||
authenticate("admin", ["session", "bearer"], {
|
||||
authenticate("user", ["session", "bearer"], {
|
||||
allowUnregistered: true,
|
||||
}),
|
||||
validateAndTransformBody(AdminInviteAccept),
|
||||
@@ -55,7 +55,7 @@ export const adminInviteRoutesMiddlewares: MiddlewareRoute[] = [
|
||||
method: ["GET"],
|
||||
matcher: "/admin/invites/:id",
|
||||
middlewares: [
|
||||
authenticate("admin", ["session", "bearer", "api-key"]),
|
||||
authenticate("user", ["session", "bearer", "api-key"]),
|
||||
validateAndTransformQuery(
|
||||
AdminGetInviteParams,
|
||||
QueryConfig.retrieveTransformQueryConfig
|
||||
@@ -65,13 +65,13 @@ export const adminInviteRoutesMiddlewares: MiddlewareRoute[] = [
|
||||
{
|
||||
method: ["DELETE"],
|
||||
matcher: "/admin/invites/:id",
|
||||
middlewares: [authenticate("admin", ["session", "bearer", "api-key"])],
|
||||
middlewares: [authenticate("user", ["session", "bearer", "api-key"])],
|
||||
},
|
||||
{
|
||||
method: "POST",
|
||||
matcher: "/admin/invites/:id/resend",
|
||||
middlewares: [
|
||||
authenticate("admin", ["session", "bearer", "api-key"]),
|
||||
authenticate("user", ["session", "bearer", "api-key"]),
|
||||
validateAndTransformQuery(
|
||||
AdminGetInviteParams,
|
||||
QueryConfig.retrieveTransformQueryConfig
|
||||
|
||||
@@ -14,7 +14,7 @@ export const adminOrderRoutesMiddlewares: MiddlewareRoute[] = [
|
||||
{
|
||||
method: ["ALL"],
|
||||
matcher: "/admin/orders*",
|
||||
middlewares: [authenticate("admin", ["bearer", "session", "api-key"])],
|
||||
middlewares: [authenticate("user", ["bearer", "session", "api-key"])],
|
||||
},
|
||||
{
|
||||
method: ["GET"],
|
||||
|
||||
@@ -16,7 +16,7 @@ export const adminPaymentRoutesMiddlewares: MiddlewareRoute[] = [
|
||||
{
|
||||
method: "ALL",
|
||||
matcher: "/admin/payments",
|
||||
middlewares: [authenticate("admin", ["session", "bearer", "api-key"])],
|
||||
middlewares: [authenticate("user", ["session", "bearer", "api-key"])],
|
||||
},
|
||||
{
|
||||
method: ["GET"],
|
||||
|
||||
@@ -18,7 +18,7 @@ export const adminPriceListsRoutesMiddlewares: MiddlewareRoute[] = [
|
||||
{
|
||||
method: ["ALL"],
|
||||
matcher: "/admin/price-lists*",
|
||||
middlewares: [authenticate("admin", ["bearer", "session", "api-key"])],
|
||||
middlewares: [authenticate("user", ["bearer", "session", "api-key"])],
|
||||
},
|
||||
{
|
||||
method: ["GET"],
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
export const adminPricingRoutesMiddlewares: MiddlewareRoute[] = [
|
||||
{
|
||||
matcher: "/admin/pricing*",
|
||||
middlewares: [authenticate("admin", ["bearer", "session", "api-key"])],
|
||||
middlewares: [authenticate("user", ["bearer", "session", "api-key"])],
|
||||
},
|
||||
{
|
||||
method: ["GET"],
|
||||
|
||||
@@ -15,7 +15,7 @@ export const adminProductCategoryRoutesMiddlewares: MiddlewareRoute[] = [
|
||||
{
|
||||
method: ["ALL"],
|
||||
matcher: "/admin/product-categories*",
|
||||
middlewares: [authenticate("admin", ["bearer", "session", "api-key"])],
|
||||
middlewares: [authenticate("user", ["bearer", "session", "api-key"])],
|
||||
},
|
||||
{
|
||||
method: ["GET"],
|
||||
|
||||
@@ -14,7 +14,7 @@ export const adminProductTypeRoutesMiddlewares: MiddlewareRoute[] = [
|
||||
{
|
||||
method: ["ALL"],
|
||||
matcher: "/admin/product-types/*",
|
||||
middlewares: [authenticate("admin", ["bearer", "session", "api-key"])],
|
||||
middlewares: [authenticate("user", ["bearer", "session", "api-key"])],
|
||||
},
|
||||
|
||||
{
|
||||
|
||||
@@ -28,7 +28,7 @@ export const adminProductRoutesMiddlewares: MiddlewareRoute[] = [
|
||||
{
|
||||
method: ["ALL"],
|
||||
matcher: "/admin/products*",
|
||||
middlewares: [authenticate("admin", ["bearer", "session", "api-key"])],
|
||||
middlewares: [authenticate("user", ["bearer", "session", "api-key"])],
|
||||
},
|
||||
{
|
||||
method: ["GET"],
|
||||
|
||||
@@ -19,7 +19,7 @@ import {
|
||||
export const adminPromotionRoutesMiddlewares: MiddlewareRoute[] = [
|
||||
{
|
||||
matcher: "/admin/promotions*",
|
||||
middlewares: [authenticate("admin", ["bearer", "session", "api-key"])],
|
||||
middlewares: [authenticate("user", ["bearer", "session", "api-key"])],
|
||||
},
|
||||
{
|
||||
method: ["GET"],
|
||||
|
||||
@@ -14,7 +14,7 @@ export const adminRegionRoutesMiddlewares: MiddlewareRoute[] = [
|
||||
{
|
||||
method: ["ALL"],
|
||||
matcher: "/admin/regions*",
|
||||
middlewares: [authenticate("admin", ["bearer", "session", "api-key"])],
|
||||
middlewares: [authenticate("user", ["bearer", "session", "api-key"])],
|
||||
},
|
||||
{
|
||||
method: ["GET"],
|
||||
|
||||
@@ -15,7 +15,7 @@ export const adminReservationRoutesMiddlewares: MiddlewareRoute[] = [
|
||||
{
|
||||
method: ["ALL"],
|
||||
matcher: "/admin/reservations*",
|
||||
middlewares: [authenticate("admin", ["bearer", "session", "api-key"])],
|
||||
middlewares: [authenticate("user", ["bearer", "session", "api-key"])],
|
||||
},
|
||||
{
|
||||
method: ["GET"],
|
||||
|
||||
@@ -13,7 +13,7 @@ export const adminReturnReasonRoutesMiddlewares: MiddlewareRoute[] = [
|
||||
{
|
||||
method: ["ALL"],
|
||||
matcher: "/admin/return-reasons*",
|
||||
middlewares: [authenticate("admin", ["bearer", "session", "api-key"])],
|
||||
middlewares: [authenticate("user", ["bearer", "session", "api-key"])],
|
||||
},
|
||||
{
|
||||
method: ["GET"],
|
||||
|
||||
@@ -13,7 +13,7 @@ export const adminOrderRoutesMiddlewares: MiddlewareRoute[] = [
|
||||
{
|
||||
method: ["ALL"],
|
||||
matcher: "/admin/returns*",
|
||||
middlewares: [authenticate("admin", ["bearer", "session", "api-key"])],
|
||||
middlewares: [authenticate("user", ["bearer", "session", "api-key"])],
|
||||
},
|
||||
{
|
||||
method: ["GET"],
|
||||
|
||||
@@ -16,7 +16,7 @@ export const adminSalesChannelRoutesMiddlewares: MiddlewareRoute[] = [
|
||||
{
|
||||
method: ["ALL"],
|
||||
matcher: "/admin/sales-channels*",
|
||||
middlewares: [authenticate("admin", ["bearer", "session", "api-key"])],
|
||||
middlewares: [authenticate("user", ["bearer", "session", "api-key"])],
|
||||
},
|
||||
{
|
||||
method: ["GET"],
|
||||
|
||||
@@ -21,7 +21,7 @@ import { createBatchBody } from "../../utils/validators"
|
||||
export const adminShippingOptionRoutesMiddlewares: MiddlewareRoute[] = [
|
||||
{
|
||||
matcher: "/admin/shipping-options*",
|
||||
middlewares: [authenticate("admin", ["bearer", "session"])],
|
||||
middlewares: [authenticate("user", ["bearer", "session"])],
|
||||
},
|
||||
{
|
||||
method: ["GET"],
|
||||
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
export const adminShippingProfilesMiddlewares: MiddlewareRoute[] = [
|
||||
{
|
||||
matcher: "/admin/shipping-profiles*",
|
||||
middlewares: [authenticate("admin", ["bearer", "session", "api-key"])],
|
||||
middlewares: [authenticate("user", ["bearer", "session", "api-key"])],
|
||||
},
|
||||
{
|
||||
method: ["POST"],
|
||||
|
||||
@@ -17,7 +17,7 @@ export const adminStockLocationRoutesMiddlewares: MiddlewareRoute[] = [
|
||||
{
|
||||
method: "ALL",
|
||||
matcher: "/admin/stock-locations*",
|
||||
middlewares: [authenticate("admin", ["session", "bearer", "api-key"])],
|
||||
middlewares: [authenticate("user", ["session", "bearer", "api-key"])],
|
||||
},
|
||||
{
|
||||
method: ["POST"],
|
||||
|
||||
@@ -13,7 +13,7 @@ export const adminStoreRoutesMiddlewares: MiddlewareRoute[] = [
|
||||
{
|
||||
method: ["ALL"],
|
||||
matcher: "/admin/stores*",
|
||||
middlewares: [authenticate("admin", ["bearer", "session", "api-key"])],
|
||||
middlewares: [authenticate("user", ["bearer", "session", "api-key"])],
|
||||
},
|
||||
{
|
||||
method: ["GET"],
|
||||
|
||||
@@ -17,7 +17,7 @@ export const adminTaxRateRoutesMiddlewares: MiddlewareRoute[] = [
|
||||
{
|
||||
method: "ALL",
|
||||
matcher: "/admin/tax-rates*",
|
||||
middlewares: [authenticate("admin", ["bearer", "session", "api-key"])],
|
||||
middlewares: [authenticate("user", ["bearer", "session", "api-key"])],
|
||||
},
|
||||
{
|
||||
method: "POST",
|
||||
|
||||
@@ -15,7 +15,7 @@ export const adminTaxRegionRoutesMiddlewares: MiddlewareRoute[] = [
|
||||
{
|
||||
method: ["ALL"],
|
||||
matcher: "/admin/tax-regions*",
|
||||
middlewares: [authenticate("admin", ["bearer", "session", "api-key"])],
|
||||
middlewares: [authenticate("user", ["bearer", "session", "api-key"])],
|
||||
},
|
||||
{
|
||||
method: "POST",
|
||||
|
||||
@@ -14,7 +14,7 @@ export const adminUploadRoutesMiddlewares: MiddlewareRoute[] = [
|
||||
{
|
||||
method: ["ALL"],
|
||||
matcher: "/admin/uploads*",
|
||||
middlewares: [authenticate("admin", ["bearer", "session", "api-key"])],
|
||||
middlewares: [authenticate("user", ["bearer", "session", "api-key"])],
|
||||
},
|
||||
// TODO: There is a `/protected` route in v1 that might need a bit more thought when implementing
|
||||
{
|
||||
|
||||
@@ -17,7 +17,7 @@ export const adminUserRoutesMiddlewares: MiddlewareRoute[] = [
|
||||
method: ["GET"],
|
||||
matcher: "/admin/users",
|
||||
middlewares: [
|
||||
authenticate("admin", ["bearer", "session"]),
|
||||
authenticate("user", ["bearer", "session"]),
|
||||
validateAndTransformQuery(
|
||||
AdminGetUsersParams,
|
||||
QueryConfig.listTransformQueryConfig
|
||||
@@ -28,7 +28,7 @@ export const adminUserRoutesMiddlewares: MiddlewareRoute[] = [
|
||||
method: ["POST"],
|
||||
matcher: "/admin/users",
|
||||
middlewares: [
|
||||
authenticate("admin", ["bearer", "session"], { allowUnregistered: true }),
|
||||
authenticate("user", ["bearer", "session"], { allowUnregistered: true }),
|
||||
validateAndTransformBody(AdminCreateUser),
|
||||
validateAndTransformQuery(
|
||||
AdminGetUserParams,
|
||||
@@ -40,7 +40,7 @@ export const adminUserRoutesMiddlewares: MiddlewareRoute[] = [
|
||||
method: ["GET"],
|
||||
matcher: "/admin/users/:id",
|
||||
middlewares: [
|
||||
authenticate("admin", ["bearer", "session"]),
|
||||
authenticate("user", ["bearer", "session"]),
|
||||
validateAndTransformQuery(
|
||||
AdminGetUserParams,
|
||||
QueryConfig.retrieveTransformQueryConfig
|
||||
@@ -51,7 +51,7 @@ export const adminUserRoutesMiddlewares: MiddlewareRoute[] = [
|
||||
method: ["GET"],
|
||||
matcher: "/admin/users/me",
|
||||
middlewares: [
|
||||
authenticate("admin", ["bearer", "session"]),
|
||||
authenticate("user", ["bearer", "session"]),
|
||||
validateAndTransformQuery(
|
||||
AdminGetUserParams,
|
||||
QueryConfig.retrieveTransformQueryConfig
|
||||
@@ -62,7 +62,7 @@ export const adminUserRoutesMiddlewares: MiddlewareRoute[] = [
|
||||
method: ["POST"],
|
||||
matcher: "/admin/users/:id",
|
||||
middlewares: [
|
||||
authenticate("admin", ["bearer", "session"]),
|
||||
authenticate("user", ["bearer", "session"]),
|
||||
validateAndTransformBody(AdminUpdateUser),
|
||||
validateAndTransformQuery(
|
||||
AdminGetUserParams,
|
||||
@@ -73,6 +73,6 @@ export const adminUserRoutesMiddlewares: MiddlewareRoute[] = [
|
||||
{
|
||||
method: ["DELETE"],
|
||||
matcher: "/admin/users/:id",
|
||||
middlewares: [authenticate("admin", ["bearer", "session"])],
|
||||
middlewares: [authenticate("user", ["bearer", "session"])],
|
||||
},
|
||||
]
|
||||
@@ -73,8 +73,6 @@ export const POST = async (
|
||||
actor_id: result.id,
|
||||
actor_type: "user",
|
||||
auth_identity_id: req.auth_context.auth_identity_id,
|
||||
app_metadata: {},
|
||||
scope: "admin",
|
||||
},
|
||||
{
|
||||
secret: jwtSecret,
|
||||
|
||||
@@ -16,7 +16,7 @@ export const adminWorkflowsExecutionsMiddlewares: MiddlewareRoute[] = [
|
||||
{
|
||||
method: ["ALL"],
|
||||
matcher: "/admin/workflows-executions*",
|
||||
middlewares: [authenticate("admin", ["bearer", "session", "api-key"])],
|
||||
middlewares: [authenticate("user", ["bearer", "session", "api-key"])],
|
||||
},
|
||||
{
|
||||
method: ["GET"],
|
||||
|
||||
+24
-11
@@ -1,5 +1,9 @@
|
||||
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
||||
import { AuthenticationInput, IAuthModuleService } from "@medusajs/types"
|
||||
import {
|
||||
AuthenticationInput,
|
||||
IAuthModuleService,
|
||||
ConfigModule,
|
||||
} from "@medusajs/types"
|
||||
import {
|
||||
ContainerRegistrationKeys,
|
||||
MedusaError,
|
||||
@@ -9,10 +13,23 @@ import { MedusaRequest, MedusaResponse } from "../../../../../types/routing"
|
||||
import { generateJwtToken } from "../../../../utils/auth/token"
|
||||
|
||||
export const GET = async (req: MedusaRequest, res: MedusaResponse) => {
|
||||
const { scope, auth_provider } = req.params
|
||||
const actorType = scope === "admin" ? "user" : "customer"
|
||||
|
||||
const { actor_type, auth_provider } = req.params
|
||||
const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
|
||||
const config: ConfigModule = req.scope.resolve(
|
||||
ContainerRegistrationKeys.CONFIG_MODULE
|
||||
)
|
||||
|
||||
const authMethods = (config.projectConfig?.http as any)?.authMethods ?? {}
|
||||
// Not having the config defined would allow for all auth providers for the particular actor.
|
||||
if (authMethods[actor_type]) {
|
||||
if (!authMethods[actor_type].includes(auth_provider)) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.NOT_ALLOWED,
|
||||
`The actor type ${actor_type} is not allowed to use the auth provider ${auth_provider}`
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const service: IAuthModuleService = req.scope.resolve(
|
||||
ModuleRegistrationName.AUTH
|
||||
)
|
||||
@@ -22,7 +39,6 @@ export const GET = async (req: MedusaRequest, res: MedusaResponse) => {
|
||||
headers: req.headers,
|
||||
query: req.query,
|
||||
body: req.body,
|
||||
authScope: scope,
|
||||
protocol: req.protocol,
|
||||
} as AuthenticationInput
|
||||
|
||||
@@ -31,11 +47,11 @@ export const GET = async (req: MedusaRequest, res: MedusaResponse) => {
|
||||
|
||||
const queryObject = remoteQueryObjectFromString({
|
||||
entryPoint: "auth_identity",
|
||||
fields: [`${actorType}.id`],
|
||||
fields: [`${actor_type}.id`],
|
||||
variables: { id: authIdentity.id },
|
||||
})
|
||||
const [actorData] = await remoteQuery(queryObject)
|
||||
const entityId = actorData?.[actorType]?.id
|
||||
const entityId = actorData?.[actor_type]?.id
|
||||
|
||||
if (success) {
|
||||
const { http } = req.scope.resolve(
|
||||
@@ -43,14 +59,11 @@ export const GET = async (req: MedusaRequest, res: MedusaResponse) => {
|
||||
).projectConfig
|
||||
|
||||
const { jwtSecret, jwtExpiresIn } = http
|
||||
// TODO: Clean up mapping between scope and actor type
|
||||
const token = generateJwtToken(
|
||||
{
|
||||
actor_id: entityId,
|
||||
actor_type: actorType,
|
||||
actor_type,
|
||||
auth_identity_id: authIdentity.id,
|
||||
app_metadata: {},
|
||||
scope,
|
||||
},
|
||||
{
|
||||
secret: jwtSecret,
|
||||
+23
-10
@@ -1,5 +1,9 @@
|
||||
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
|
||||
import { AuthenticationInput, IAuthModuleService } from "@medusajs/types"
|
||||
import {
|
||||
AuthenticationInput,
|
||||
IAuthModuleService,
|
||||
ConfigModule,
|
||||
} from "@medusajs/types"
|
||||
import {
|
||||
ContainerRegistrationKeys,
|
||||
MedusaError,
|
||||
@@ -9,9 +13,22 @@ import { MedusaRequest, MedusaResponse } from "../../../../types/routing"
|
||||
import { generateJwtToken } from "../../../utils/auth/token"
|
||||
|
||||
export const GET = async (req: MedusaRequest, res: MedusaResponse) => {
|
||||
const { scope, auth_provider } = req.params
|
||||
const actorType = scope === "admin" ? "user" : "customer"
|
||||
const { actor_type, auth_provider } = req.params
|
||||
const remoteQuery = req.scope.resolve(ContainerRegistrationKeys.REMOTE_QUERY)
|
||||
const config: ConfigModule = req.scope.resolve(
|
||||
ContainerRegistrationKeys.CONFIG_MODULE
|
||||
)
|
||||
|
||||
const authMethods = (config.projectConfig?.http as any)?.authMethods ?? {}
|
||||
// Not having the config defined would allow for all auth providers for the particular actor.
|
||||
if (authMethods[actor_type]) {
|
||||
if (!authMethods[actor_type].includes(auth_provider)) {
|
||||
throw new MedusaError(
|
||||
MedusaError.Types.NOT_ALLOWED,
|
||||
`The actor type ${actor_type} is not allowed to use the auth provider ${auth_provider}`
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const service: IAuthModuleService = req.scope.resolve(
|
||||
ModuleRegistrationName.AUTH
|
||||
@@ -22,7 +39,6 @@ export const GET = async (req: MedusaRequest, res: MedusaResponse) => {
|
||||
headers: req.headers,
|
||||
query: req.query,
|
||||
body: req.body,
|
||||
authScope: scope,
|
||||
protocol: req.protocol,
|
||||
} as AuthenticationInput
|
||||
|
||||
@@ -43,21 +59,18 @@ export const GET = async (req: MedusaRequest, res: MedusaResponse) => {
|
||||
|
||||
const queryObject = remoteQueryObjectFromString({
|
||||
entryPoint: "auth_identity",
|
||||
fields: [`${actorType}.id`],
|
||||
fields: [`${actor_type}.id`],
|
||||
variables: { id: authIdentity.id },
|
||||
})
|
||||
const [actorData] = await remoteQuery(queryObject)
|
||||
const entityId = actorData?.[actorType]?.id
|
||||
const entityId = actorData?.[actor_type]?.id
|
||||
|
||||
const { jwtSecret, jwtExpiresIn } = http
|
||||
// TODO: Clean up mapping between scope and actor type
|
||||
const token = generateJwtToken(
|
||||
{
|
||||
actor_id: entityId,
|
||||
actor_type: actorType,
|
||||
actor_type,
|
||||
auth_identity_id: authIdentity.id,
|
||||
app_metadata: {},
|
||||
scope,
|
||||
},
|
||||
{
|
||||
secret: jwtSecret,
|
||||
@@ -14,12 +14,12 @@ export const authRoutesMiddlewares: MiddlewareRoute[] = [
|
||||
},
|
||||
{
|
||||
method: ["POST"],
|
||||
matcher: "/auth/:scope/:auth_provider/callback",
|
||||
matcher: "/auth/:actor_type/:auth_provider/callback",
|
||||
middlewares: [],
|
||||
},
|
||||
{
|
||||
method: ["POST"],
|
||||
matcher: "/auth/:scope/:auth_provider",
|
||||
matcher: "/auth/:actor_type/:auth_provider",
|
||||
middlewares: [],
|
||||
},
|
||||
]
|
||||
@@ -25,7 +25,7 @@ export const storeCartRoutesMiddlewares: MiddlewareRoute[] = [
|
||||
method: "ALL",
|
||||
matcher: "/store/carts*",
|
||||
middlewares: [
|
||||
authenticate("store", ["session", "bearer"], {
|
||||
authenticate("customer", ["session", "bearer"], {
|
||||
allowUnauthenticated: true,
|
||||
}),
|
||||
],
|
||||
|
||||
@@ -20,7 +20,9 @@ export const storeCustomerRoutesMiddlewares: MiddlewareRoute[] = [
|
||||
method: ["POST"],
|
||||
matcher: "/store/customers",
|
||||
middlewares: [
|
||||
authenticate("store", ["session", "bearer"], { allowUnregistered: true }),
|
||||
authenticate("customer", ["session", "bearer"], {
|
||||
allowUnregistered: true,
|
||||
}),
|
||||
validateAndTransformBody(StoreCreateCustomer),
|
||||
validateAndTransformQuery(
|
||||
StoreGetCustomerParams,
|
||||
@@ -31,7 +33,7 @@ export const storeCustomerRoutesMiddlewares: MiddlewareRoute[] = [
|
||||
{
|
||||
method: "ALL",
|
||||
matcher: "/store/customers/me*",
|
||||
middlewares: [authenticate("store", ["session", "bearer"])],
|
||||
middlewares: [authenticate("customer", ["session", "bearer"])],
|
||||
},
|
||||
{
|
||||
method: ["GET"],
|
||||
|
||||
@@ -41,8 +41,6 @@ export const POST = async (
|
||||
actor_id: result.id,
|
||||
actor_type: "customer",
|
||||
auth_identity_id: req.auth_context.auth_identity_id,
|
||||
app_metadata: {},
|
||||
scope: "store",
|
||||
},
|
||||
{
|
||||
secret: jwtSecret,
|
||||
|
||||
@@ -9,7 +9,7 @@ export const storeOrderRoutesMiddlewares: MiddlewareRoute[] = [
|
||||
method: ["GET"],
|
||||
matcher: "/store/orders",
|
||||
middlewares: [
|
||||
authenticate("store", ["session", "bearer"]),
|
||||
authenticate("customer", ["session", "bearer"]),
|
||||
validateAndTransformQuery(
|
||||
StoreGetOrdersParams,
|
||||
QueryConfig.listTransformQueryConfig
|
||||
@@ -20,7 +20,7 @@ export const storeOrderRoutesMiddlewares: MiddlewareRoute[] = [
|
||||
method: ["GET"],
|
||||
matcher: "/store/orders/:id",
|
||||
middlewares: [
|
||||
authenticate("store", ["session", "bearer"], {
|
||||
authenticate("customer", ["session", "bearer"], {
|
||||
allowUnauthenticated: true,
|
||||
}),
|
||||
validateAndTransformQuery(
|
||||
|
||||
@@ -14,7 +14,7 @@ export const storePaymentCollectionsMiddlewares: MiddlewareRoute[] = [
|
||||
method: "ALL",
|
||||
matcher: "/store/payment-collections*",
|
||||
middlewares: [
|
||||
authenticate("store", ["session", "bearer"], {
|
||||
authenticate("customer", ["session", "bearer"], {
|
||||
allowUnauthenticated: true,
|
||||
}),
|
||||
],
|
||||
|
||||
@@ -19,7 +19,7 @@ export const storeProductRoutesMiddlewares: MiddlewareRoute[] = [
|
||||
method: "ALL",
|
||||
matcher: "/store/products*",
|
||||
middlewares: [
|
||||
authenticate("store", ["session", "bearer"], {
|
||||
authenticate("customer", ["session", "bearer"], {
|
||||
allowUnauthenticated: true,
|
||||
}),
|
||||
],
|
||||
|
||||
@@ -46,14 +46,18 @@ export default async function ({
|
||||
} else {
|
||||
const user = await userService.create({ email })
|
||||
|
||||
const { authIdentity } = await authService.authenticate(provider, {
|
||||
const { authIdentity, error } = await authService.authenticate(provider, {
|
||||
body: {
|
||||
email,
|
||||
password,
|
||||
},
|
||||
authScope: "admin",
|
||||
})
|
||||
|
||||
if (error) {
|
||||
Logger.error(error)
|
||||
throw new Error(error)
|
||||
}
|
||||
|
||||
await remoteLink.create([
|
||||
{
|
||||
[Modules.USER]: {
|
||||
|
||||
@@ -61,11 +61,8 @@ export interface MedusaRequest<Body = unknown>
|
||||
|
||||
export interface AuthContext {
|
||||
actor_id: string
|
||||
// TODO: We possibly want to make this more open-ended so it's easy to extend.
|
||||
actor_type: "api-key" | "user" | "customer" | "unknown"
|
||||
actor_type: string
|
||||
auth_identity_id: string
|
||||
scope: string
|
||||
app_metadata: Record<string, any>
|
||||
}
|
||||
|
||||
export interface AuthenticatedMedusaRequest<Body = never>
|
||||
|
||||
@@ -8,25 +8,23 @@ import {
|
||||
MedusaRequest,
|
||||
MedusaResponse,
|
||||
} from "../../types/routing"
|
||||
import { ContainerRegistrationKeys } from "@medusajs/utils"
|
||||
|
||||
const SESSION_AUTH = "session"
|
||||
const BEARER_AUTH = "bearer"
|
||||
const API_KEY_AUTH = "api-key"
|
||||
|
||||
// This is the only hard-coded actor type, as API keys have special handling for now. We could also generalize API keys to carry the actor type with them.
|
||||
const ADMIN_ACTOR_TYPE = "user"
|
||||
|
||||
type AuthType = typeof SESSION_AUTH | typeof BEARER_AUTH | typeof API_KEY_AUTH
|
||||
|
||||
const ADMIN_SCOPE = "admin"
|
||||
const STORE_SCOPE = "store"
|
||||
const ALL_SCOPE = "*"
|
||||
|
||||
type Scope = typeof ADMIN_SCOPE | typeof STORE_SCOPE | typeof ALL_SCOPE
|
||||
|
||||
type MedusaSession = {
|
||||
auth_context: AuthContext
|
||||
}
|
||||
|
||||
export const authenticate = (
|
||||
authScope: Scope | Scope[],
|
||||
actorType: string,
|
||||
authType: AuthType | AuthType[],
|
||||
options: { allowUnauthenticated?: boolean; allowUnregistered?: boolean } = {}
|
||||
): RequestHandler => {
|
||||
@@ -36,21 +34,20 @@ export const authenticate = (
|
||||
next: NextFunction
|
||||
): Promise<void> => {
|
||||
const authTypes = Array.isArray(authType) ? authType : [authType]
|
||||
const scopes = Array.isArray(authScope) ? authScope : [authScope]
|
||||
const actorTypes = Array.isArray(actorType) ? actorType : [actorType]
|
||||
const req_ = req as AuthenticatedMedusaRequest
|
||||
|
||||
// We only allow authenticating using a secret API key on the admin
|
||||
const isExclusivelyAdmin =
|
||||
scopes.length === 1 && scopes.includes(ADMIN_SCOPE)
|
||||
if (authTypes.includes(API_KEY_AUTH) && isExclusivelyAdmin) {
|
||||
const isExclusivelyUser =
|
||||
actorTypes.length === 1 && actorTypes[0] === ADMIN_ACTOR_TYPE
|
||||
|
||||
if (authTypes.includes(API_KEY_AUTH) && isExclusivelyUser) {
|
||||
const apiKey = await getApiKeyInfo(req)
|
||||
if (apiKey) {
|
||||
req_.auth_context = {
|
||||
actor_id: apiKey.id,
|
||||
actor_type: "api-key",
|
||||
auth_identity_id: "",
|
||||
app_metadata: {},
|
||||
scope: ADMIN_SCOPE,
|
||||
}
|
||||
|
||||
return next()
|
||||
@@ -61,27 +58,29 @@ export const authenticate = (
|
||||
let authContext: AuthContext | null = getAuthContextFromSession(
|
||||
req.session,
|
||||
authTypes,
|
||||
scopes
|
||||
actorTypes
|
||||
)
|
||||
|
||||
if (!authContext) {
|
||||
const { http } =
|
||||
req.scope.resolve<ConfigModule>("configModule").projectConfig
|
||||
const { http } = req.scope.resolve<ConfigModule>(
|
||||
ContainerRegistrationKeys.CONFIG_MODULE
|
||||
).projectConfig
|
||||
|
||||
authContext = getAuthContextFromJwtToken(
|
||||
req.headers.authorization,
|
||||
http.jwtSecret!,
|
||||
authTypes,
|
||||
scopes
|
||||
actorTypes
|
||||
)
|
||||
}
|
||||
|
||||
// If the entity is authenticated, and it is a registered user/customer we can continue
|
||||
if (!!authContext?.actor_id && authContext.actor_type !== "unknown") {
|
||||
// If the entity is authenticated, and it is a registered actor we can continue
|
||||
if (authContext?.actor_id) {
|
||||
req_.auth_context = authContext
|
||||
return next()
|
||||
}
|
||||
|
||||
// If the entity is authenticated, but there is no user/customer yet, we can continue (eg. in the case of a user invite) if allow unregistered is set
|
||||
// If the entity is authenticated, but there is no registered actor yet, we can continue (eg. in the case of a user invite) if allow unregistered is set
|
||||
if (authContext?.auth_identity_id && options.allowUnregistered) {
|
||||
req_.auth_context = authContext
|
||||
return next()
|
||||
@@ -142,7 +141,7 @@ const getApiKeyInfo = async (req: MedusaRequest): Promise<ApiKeyDTO | null> => {
|
||||
const getAuthContextFromSession = (
|
||||
session: Partial<MedusaSession> = {},
|
||||
authTypes: AuthType[],
|
||||
scopes: Scope[]
|
||||
actorTypes: string[]
|
||||
): AuthContext | null => {
|
||||
if (!authTypes.includes(SESSION_AUTH)) {
|
||||
return null
|
||||
@@ -150,8 +149,8 @@ const getAuthContextFromSession = (
|
||||
|
||||
if (
|
||||
session.auth_context &&
|
||||
(scopes.includes("*") ||
|
||||
scopes.includes(session.auth_context.scope as Scope))
|
||||
(actorTypes.includes("*") ||
|
||||
actorTypes.includes(session.auth_context.actor_type))
|
||||
) {
|
||||
return session.auth_context
|
||||
}
|
||||
@@ -163,7 +162,7 @@ const getAuthContextFromJwtToken = (
|
||||
authHeader: string | undefined,
|
||||
jwtSecret: string,
|
||||
authTypes: AuthType[],
|
||||
scopes: Scope[]
|
||||
actorTypes: string[]
|
||||
): AuthContext | null => {
|
||||
if (!authTypes.includes(BEARER_AUTH)) {
|
||||
return null
|
||||
@@ -185,7 +184,10 @@ const getAuthContextFromJwtToken = (
|
||||
// verify token and set authUser
|
||||
try {
|
||||
const verified = jwt.verify(token, jwtSecret) as JwtPayload
|
||||
if (scopes.includes("*") || scopes.includes(verified.scope)) {
|
||||
if (
|
||||
actorTypes.includes("*") ||
|
||||
actorTypes.includes(verified.actor_type)
|
||||
) {
|
||||
return verified as AuthContext
|
||||
}
|
||||
} catch (err) {
|
||||
|
||||
Reference in new issue
Block a user