feat(auth): Make token auth default (#6305)

**What**
- make token auth the default being returned from authentication endpoints in api-v2
- Add `auth/session` to convert token to session based auth
- add regex-scopes to authenticate middleware 

Co-authored-by: Sebastian Rindom <7554214+srindom@users.noreply.github.com>
This commit is contained in:
Philip KorsholmandSebastian Rindom authored and GitHub committed 2024-02-05 08:17:08 +00:00
1 parent 96ba49329b
commit e2738ab91d
21 files changed
+147 -138

No files matched your search

@@ -1,11 +1,12 @@
import { ModuleRegistrationName } from "@medusajs/modules-sdk" import { initDb, useDb } from "../../../../environment-helpers/use-db"
import { ICustomerModuleService } from "@medusajs/types" import { ICustomerModuleService } from "@medusajs/types"
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import { createAuthenticatedCustomer } from "../../../helpers/create-authenticated-customer"
import { getContainer } from "../../../../environment-helpers/use-container"
import path from "path" import path from "path"
import { startBootstrapApp } from "../../../../environment-helpers/bootstrap-app" import { startBootstrapApp } from "../../../../environment-helpers/bootstrap-app"
import { useApi } from "../../../../environment-helpers/use-api" import { useApi } from "../../../../environment-helpers/use-api"
import { getContainer } from "../../../../environment-helpers/use-container"
import { initDb, useDb } from "../../../../environment-helpers/use-db"
import { createAuthenticatedCustomer } from "../../../helpers/create-authenticated-customer"
jest.setTimeout(50000) jest.setTimeout(50000)
@@ -39,9 +40,11 @@ describe("POST /store/customers/me/addresses", () => {
}) })
it("should create a customer address", async () => { it("should create a customer address", async () => {
const { jwt_secret } = appContainer.resolve("configModule").projectConfig
const { customer, jwt } = await createAuthenticatedCustomer( const { customer, jwt } = await createAuthenticatedCustomer(
customerModuleService, customerModuleService,
appContainer.resolve(ModuleRegistrationName.AUTH) appContainer.resolve(ModuleRegistrationName.AUTH),
jwt_secret
) )
const api = useApi() as any const api = useApi() as any
@@ -4,6 +4,7 @@ import { initDb, useDb } from "../../../../environment-helpers/use-db"
import { ModuleRegistrationName } from "@medusajs/modules-sdk" import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import adminSeeder from "../../../../helpers/admin-seeder" import adminSeeder from "../../../../helpers/admin-seeder"
import { getContainer } from "../../../../environment-helpers/use-container" import { getContainer } from "../../../../environment-helpers/use-container"
import jwt from "jsonwebtoken"
import path from "path" import path from "path"
import { startBootstrapApp } from "../../../../environment-helpers/bootstrap-app" import { startBootstrapApp } from "../../../../environment-helpers/bootstrap-app"
import { useApi } from "../../../../environment-helpers/use-api" import { useApi } from "../../../../environment-helpers/use-api"
@@ -47,12 +48,14 @@ describe("POST /store/customers", () => {
const authService: IAuthModuleService = appContainer.resolve( const authService: IAuthModuleService = appContainer.resolve(
ModuleRegistrationName.AUTH ModuleRegistrationName.AUTH
) )
const { jwt_secret } = appContainer.resolve("configModule").projectConfig
const authUser = await authService.createAuthUser({ const authUser = await authService.createAuthUser({
entity_id: "store_user", entity_id: "store_user",
provider_id: "test", provider: "emailpass",
scope: "store", scope: "store",
}) })
const jwt = await authService.generateJwtToken(authUser.id, "store")
const token = jwt.sign(authUser, jwt_secret)
const api = useApi() as any const api = useApi() as any
const response = await api.post( const response = await api.post(
@@ -62,7 +65,7 @@ describe("POST /store/customers", () => {
last_name: "Doe", last_name: "Doe",
email: "john@me.com", email: "john@me.com",
}, },
{ headers: { authorization: `Bearer ${jwt}` } } { headers: { authorization: `Bearer ${token}` } }
) )
expect(response.status).toEqual(200) expect(response.status).toEqual(200)
@@ -1,11 +1,12 @@
import { ModuleRegistrationName } from "@medusajs/modules-sdk" import { initDb, useDb } from "../../../../environment-helpers/use-db"
import { ICustomerModuleService } from "@medusajs/types" import { ICustomerModuleService } from "@medusajs/types"
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import { createAuthenticatedCustomer } from "../../../helpers/create-authenticated-customer"
import { getContainer } from "../../../../environment-helpers/use-container"
import path from "path" import path from "path"
import { startBootstrapApp } from "../../../../environment-helpers/bootstrap-app" import { startBootstrapApp } from "../../../../environment-helpers/bootstrap-app"
import { useApi } from "../../../../environment-helpers/use-api" import { useApi } from "../../../../environment-helpers/use-api"
import { getContainer } from "../../../../environment-helpers/use-container"
import { initDb, useDb } from "../../../../environment-helpers/use-db"
import { createAuthenticatedCustomer } from "../../../helpers/create-authenticated-customer"
const env = { MEDUSA_FF_MEDUSA_V2: true } const env = { MEDUSA_FF_MEDUSA_V2: true }
@@ -25,6 +26,14 @@ describe("DELETE /store/customers/me/addresses/:address_id", () => {
) )
}) })
// TODO: delete with removal of authProvider
beforeEach(async () => {
const onStart =
appContainer.resolve(ModuleRegistrationName.AUTH).__hooks
.onApplicationStart ?? (() => Promise.resolve())
await onStart()
})
afterAll(async () => { afterAll(async () => {
const db = useDb() const db = useDb()
await db.shutdown() await db.shutdown()
@@ -37,9 +46,11 @@ describe("DELETE /store/customers/me/addresses/:address_id", () => {
}) })
it("should delete a customer address", async () => { it("should delete a customer address", async () => {
const { jwt_secret } = appContainer.resolve("configModule").projectConfig
const { customer, jwt } = await createAuthenticatedCustomer( const { customer, jwt } = await createAuthenticatedCustomer(
customerModuleService, customerModuleService,
appContainer.resolve(ModuleRegistrationName.AUTH) appContainer.resolve(ModuleRegistrationName.AUTH),
jwt_secret
) )
const address = await customerModuleService.addAddresses({ const address = await customerModuleService.addAddresses({
@@ -65,9 +76,11 @@ describe("DELETE /store/customers/me/addresses/:address_id", () => {
}) })
it("should fail to delete another customer's address", async () => { it("should fail to delete another customer's address", async () => {
const { jwt_secret } = appContainer.resolve("configModule").projectConfig
const { jwt } = await createAuthenticatedCustomer( const { jwt } = await createAuthenticatedCustomer(
customerModuleService, customerModuleService,
appContainer.resolve(ModuleRegistrationName.AUTH) appContainer.resolve(ModuleRegistrationName.AUTH),
jwt_secret
) )
const otherCustomer = await customerModuleService.create({ const otherCustomer = await customerModuleService.create({
@@ -1,12 +1,13 @@
import { ModuleRegistrationName } from "@medusajs/modules-sdk" import { initDb, useDb } from "../../../../environment-helpers/use-db"
import { ICustomerModuleService } from "@medusajs/types" import { ICustomerModuleService } from "@medusajs/types"
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import { createAuthenticatedCustomer } from "../../../helpers/create-authenticated-customer"
import customer from "../../../../development/database/customer"
import { getContainer } from "../../../../environment-helpers/use-container"
import path from "path" import path from "path"
import { startBootstrapApp } from "../../../../environment-helpers/bootstrap-app" import { startBootstrapApp } from "../../../../environment-helpers/bootstrap-app"
import { useApi } from "../../../../environment-helpers/use-api" import { useApi } from "../../../../environment-helpers/use-api"
import { getContainer } from "../../../../environment-helpers/use-container"
import { initDb, useDb } from "../../../../environment-helpers/use-db"
import adminSeeder from "../../../../helpers/admin-seeder"
import { createAuthenticatedCustomer } from "../../../helpers/create-authenticated-customer"
jest.setTimeout(50000) jest.setTimeout(50000)
@@ -34,19 +35,17 @@ describe("GET /store/customers", () => {
await shutdownServer() await shutdownServer()
}) })
beforeEach(async () => {
await adminSeeder(dbConnection)
})
afterEach(async () => { afterEach(async () => {
const db = useDb() const db = useDb()
await db.teardown() await db.teardown()
}) })
it("should retrieve auth user's customer", async () => { it("should retrieve auth user's customer", async () => {
const { jwt_secret } = appContainer.resolve("configModule").projectConfig
const { customer, jwt } = await createAuthenticatedCustomer( const { customer, jwt } = await createAuthenticatedCustomer(
customerModuleService, customerModuleService,
appContainer.resolve(ModuleRegistrationName.AUTH) appContainer.resolve(ModuleRegistrationName.AUTH),
jwt_secret
) )
const api = useApi() as any const api = useApi() as any
@@ -1,11 +1,12 @@
import { ModuleRegistrationName } from "@medusajs/modules-sdk" import { initDb, useDb } from "../../../../environment-helpers/use-db"
import { ICustomerModuleService } from "@medusajs/types" import { ICustomerModuleService } from "@medusajs/types"
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import { createAuthenticatedCustomer } from "../../../helpers/create-authenticated-customer"
import { getContainer } from "../../../../environment-helpers/use-container"
import path from "path" import path from "path"
import { startBootstrapApp } from "../../../../environment-helpers/bootstrap-app" import { startBootstrapApp } from "../../../../environment-helpers/bootstrap-app"
import { useApi } from "../../../../environment-helpers/use-api" import { useApi } from "../../../../environment-helpers/use-api"
import { getContainer } from "../../../../environment-helpers/use-container"
import { initDb, useDb } from "../../../../environment-helpers/use-db"
import { createAuthenticatedCustomer } from "../../../helpers/create-authenticated-customer"
const env = { MEDUSA_FF_MEDUSA_V2: true } const env = { MEDUSA_FF_MEDUSA_V2: true }
@@ -43,9 +44,11 @@ describe("GET /store/customers/me/addresses", () => {
}) })
it("should get all customer addresses and its count", async () => { it("should get all customer addresses and its count", async () => {
const { jwt_secret } = appContainer.resolve("configModule").projectConfig
const { customer, jwt } = await createAuthenticatedCustomer( const { customer, jwt } = await createAuthenticatedCustomer(
customerModuleService, customerModuleService,
appContainer.resolve(ModuleRegistrationName.AUTH) appContainer.resolve(ModuleRegistrationName.AUTH),
jwt_secret
) )
await customerModuleService.addAddresses([ await customerModuleService.addAddresses([
@@ -1,11 +1,12 @@
import { ModuleRegistrationName } from "@medusajs/modules-sdk" import { initDb, useDb } from "../../../../environment-helpers/use-db"
import { ICustomerModuleService } from "@medusajs/types" import { ICustomerModuleService } from "@medusajs/types"
import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import { createAuthenticatedCustomer } from "../../../helpers/create-authenticated-customer"
import { getContainer } from "../../../../environment-helpers/use-container"
import path from "path" import path from "path"
import { startBootstrapApp } from "../../../../environment-helpers/bootstrap-app" import { startBootstrapApp } from "../../../../environment-helpers/bootstrap-app"
import { useApi } from "../../../../environment-helpers/use-api" import { useApi } from "../../../../environment-helpers/use-api"
import { getContainer } from "../../../../environment-helpers/use-container"
import { initDb, useDb } from "../../../../environment-helpers/use-db"
import { createAuthenticatedCustomer } from "../../../helpers/create-authenticated-customer"
const env = { MEDUSA_FF_MEDUSA_V2: true } const env = { MEDUSA_FF_MEDUSA_V2: true }
@@ -25,6 +26,14 @@ describe("POST /store/customers/:id/addresses/:address_id", () => {
) )
}) })
// TODO: delete with removal of authProvider
beforeEach(async () => {
const onStart =
appContainer.resolve(ModuleRegistrationName.AUTH).__hooks
.onApplicationStart ?? (() => Promise.resolve())
await onStart()
})
afterAll(async () => { afterAll(async () => {
const db = useDb() const db = useDb()
await db.shutdown() await db.shutdown()
@@ -37,9 +46,12 @@ describe("POST /store/customers/:id/addresses/:address_id", () => {
}) })
it("should update a customer address", async () => { it("should update a customer address", async () => {
const { jwt_secret } = appContainer.resolve("configModule").projectConfig
const { customer, jwt } = await createAuthenticatedCustomer( const { customer, jwt } = await createAuthenticatedCustomer(
customerModuleService, customerModuleService,
appContainer.resolve(ModuleRegistrationName.AUTH) appContainer.resolve(ModuleRegistrationName.AUTH),
jwt_secret
) )
const address = await customerModuleService.addAddresses({ const address = await customerModuleService.addAddresses({
@@ -69,15 +81,19 @@ describe("POST /store/customers/:id/addresses/:address_id", () => {
}) })
it("should fail to update another customer's address", async () => { it("should fail to update another customer's address", async () => {
const { jwt_secret } = appContainer.resolve("configModule").projectConfig
const { jwt } = await createAuthenticatedCustomer( const { jwt } = await createAuthenticatedCustomer(
customerModuleService, customerModuleService,
appContainer.resolve(ModuleRegistrationName.AUTH) appContainer.resolve(ModuleRegistrationName.AUTH),
jwt_secret
) )
const otherCustomer = await customerModuleService.create({ const otherCustomer = await customerModuleService.create({
first_name: "Jane", first_name: "Jane",
last_name: "Doe", last_name: "Doe",
}) })
const address = await customerModuleService.addAddresses({ const address = await customerModuleService.addAddresses({
customer_id: otherCustomer.id, customer_id: otherCustomer.id,
first_name: "John", first_name: "John",
@@ -1,8 +1,11 @@
import { ICustomerModuleService, IAuthModuleService } from "@medusajs/types" import { IAuthModuleService, ICustomerModuleService } from "@medusajs/types"
import jwt from "jsonwebtoken"
export const createAuthenticatedCustomer = async ( export const createAuthenticatedCustomer = async (
customerModuleService: ICustomerModuleService, customerModuleService: ICustomerModuleService,
authService: IAuthModuleService authService: IAuthModuleService,
jwtSecret: string
) => { ) => {
const customer = await customerModuleService.create({ const customer = await customerModuleService.create({
first_name: "John", first_name: "John",
@@ -12,12 +15,12 @@ export const createAuthenticatedCustomer = async (
const authUser = await authService.createAuthUser({ const authUser = await authService.createAuthUser({
entity_id: "store_user", entity_id: "store_user",
provider_id: "test", provider: "emailpass",
scope: "store", scope: "store",
app_metadata: { customer_id: customer.id }, app_metadata: { customer_id: customer.id },
}) })
const jwt = await authService.generateJwtToken(authUser.id, "store") const token = jwt.sign(authUser, jwtSecret)
return { customer, authUser, jwt } return { customer, authUser, jwt: token }
} }
@@ -46,9 +46,6 @@ module.exports = {
scope: "internal", scope: "internal",
resources: "shared", resources: "shared",
resolve: "@medusajs/auth", resolve: "@medusajs/auth",
options: {
jwt_secret: "test",
},
}, },
[Modules.STOCK_LOCATION]: { [Modules.STOCK_LOCATION]: {
scope: "internal", scope: "internal",
+3 -3
View File
@@ -1,8 +1,8 @@
import { AbstractAuthModuleProvider, MedusaError } from "@medusajs/utils" import { AbstractAuthModuleProvider, MedusaError } from "@medusajs/utils"
import { import {
AuthProviderScope,
AuthenticationInput, AuthenticationInput,
AuthenticationResponse, AuthenticationResponse,
AuthProviderScope,
ModulesSdkTypes, ModulesSdkTypes,
} from "@medusajs/types" } from "@medusajs/types"
import { AuthUserService } from "@services" import { AuthUserService } from "@services"
@@ -82,9 +82,9 @@ class GoogleProvider extends AbstractAuthModuleProvider {
// abstractable // abstractable
async verify_(refreshToken: string, scope: string) { async verify_(refreshToken: string, scope: string) {
const jwtData = (await jwt.decode(refreshToken, { const jwtData = jwt.decode(refreshToken, {
complete: true, complete: true,
})) as JwtPayload }) as JwtPayload
const entity_id = jwtData.payload.email const entity_id = jwtData.payload.email
let authUser let authUser
-55
View File
@@ -1,5 +1,3 @@
import jwt from "jsonwebtoken"
import { import {
AuthenticationInput, AuthenticationInput,
AuthenticationResponse, AuthenticationResponse,
@@ -11,7 +9,6 @@ import {
CreateAuthUserDTO, CreateAuthUserDTO,
DAL, DAL,
InternalModuleDeclaration, InternalModuleDeclaration,
JWTGenerationOptions,
ModuleJoinerConfig, ModuleJoinerConfig,
ModulesSdkTypes, ModulesSdkTypes,
UpdateAuthUserDTO, UpdateAuthUserDTO,
@@ -31,15 +28,6 @@ import {
} from "@medusajs/utils" } from "@medusajs/utils"
import { ServiceTypes } from "@types" import { ServiceTypes } from "@types"
type AuthModuleOptions = {
jwt_secret: string
}
type AuthJWTPayload = {
id: string
scope: string
}
type InjectedDependencies = { type InjectedDependencies = {
baseRepository: DAL.RepositoryService baseRepository: DAL.RepositoryService
authUserService: ModulesSdkTypes.InternalModuleService<any> authUserService: ModulesSdkTypes.InternalModuleService<any>
@@ -68,7 +56,6 @@ export default class AuthModuleService<
protected baseRepository_: DAL.RepositoryService protected baseRepository_: DAL.RepositoryService
protected authUserService_: ModulesSdkTypes.InternalModuleService<TAuthUser> protected authUserService_: ModulesSdkTypes.InternalModuleService<TAuthUser>
protected authProviderService_: ModulesSdkTypes.InternalModuleService<TAuthProvider> protected authProviderService_: ModulesSdkTypes.InternalModuleService<TAuthProvider>
protected options_: AuthModuleOptions
constructor( constructor(
{ {
@@ -76,7 +63,6 @@ export default class AuthModuleService<
authProviderService, authProviderService,
baseRepository, baseRepository,
}: InjectedDependencies, }: InjectedDependencies,
options: AuthModuleOptions,
protected readonly moduleDeclaration: InternalModuleDeclaration protected readonly moduleDeclaration: InternalModuleDeclaration
) { ) {
// @ts-ignore // @ts-ignore
@@ -85,53 +71,12 @@ export default class AuthModuleService<
this.baseRepository_ = baseRepository this.baseRepository_ = baseRepository
this.authUserService_ = authUserService this.authUserService_ = authUserService
this.authProviderService_ = authProviderService this.authProviderService_ = authProviderService
this.options_ = options
} }
__joinerConfig(): ModuleJoinerConfig { __joinerConfig(): ModuleJoinerConfig {
return joinerConfig return joinerConfig
} }
async generateJwtToken(
authUserId: string,
scope: string,
options: JWTGenerationOptions = {}
): Promise<string> {
const authUser = await this.authUserService_.retrieve(authUserId)
return jwt.sign({ id: authUser.id, scope }, this.options_.jwt_secret, {
expiresIn: options.expiresIn || "1d",
})
}
async retrieveAuthUserFromJwtToken(
token: string,
scope: string
): Promise<AuthUserDTO> {
let decoded: AuthJWTPayload
try {
const verifiedToken = jwt.verify(token, this.options_.jwt_secret)
decoded = verifiedToken as AuthJWTPayload
} catch (err) {
throw new MedusaError(
MedusaError.Types.UNAUTHORIZED,
"The provided JWT token is invalid"
)
}
if (decoded.scope !== scope) {
throw new MedusaError(
MedusaError.Types.UNAUTHORIZED,
"The provided JWT token is invalid"
)
}
const authUser = await this.authUserService_.retrieve(decoded.id)
return await this.baseRepository_.serialize<AuthTypes.AuthUserDTO>(
authUser,
{ populate: true }
)
}
async createAuthProvider( async createAuthProvider(
data: CreateAuthProviderDTO[], data: CreateAuthProviderDTO[],
sharedContext?: Context sharedContext?: Context
@@ -1,8 +1,8 @@
import { AuthenticationInput, IAuthModuleService } from "@medusajs/types" import jwt from "jsonwebtoken"
import { MedusaRequest, MedusaResponse } from "../../../../../types/routing"
import { MedusaError } from "@medusajs/utils" import { MedusaError } from "@medusajs/utils"
import { ModuleRegistrationName } from "@medusajs/modules-sdk" import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import { AuthenticationInput, IAuthModuleService } from "@medusajs/types"
import { MedusaRequest, MedusaResponse } from "../../../../../types/routing"
export const GET = async (req: MedusaRequest, res: MedusaResponse) => { export const GET = async (req: MedusaRequest, res: MedusaResponse) => {
const { scope, authProvider } = req.params const { scope, authProvider } = req.params
@@ -29,10 +29,9 @@ export const GET = async (req: MedusaRequest, res: MedusaResponse) => {
} }
if (success) { if (success) {
req.session.auth_user = authUser const { jwt_secret } = req.scope.resolve("configModule").projectConfig
req.session.scope = authUser.scope const token = jwt.sign(authUser, jwt_secret)
return res.status(200).json({ token })
return res.status(200).json({ authUser })
} }
throw new MedusaError( throw new MedusaError(
@@ -1,8 +1,8 @@
import jwt from "jsonwebtoken"
import { AuthenticationInput, IAuthModuleService } from "@medusajs/types" import { AuthenticationInput, IAuthModuleService } from "@medusajs/types"
import { MedusaRequest, MedusaResponse } from "../../../../types/routing"
import { MedusaError } from "@medusajs/utils" import { MedusaError } from "@medusajs/utils"
import { ModuleRegistrationName } from "@medusajs/modules-sdk" import { ModuleRegistrationName } from "@medusajs/modules-sdk"
import { MedusaRequest, MedusaResponse } from "../../../../types/routing"
export const GET = async (req: MedusaRequest, res: MedusaResponse) => { export const GET = async (req: MedusaRequest, res: MedusaResponse) => {
const { scope, authProvider } = req.params const { scope, authProvider } = req.params
@@ -29,10 +29,11 @@ export const GET = async (req: MedusaRequest, res: MedusaResponse) => {
} }
if (success) { if (success) {
req.session.auth_user = authUser const { jwt_secret } = req.scope.resolve("configModule").projectConfig
req.session.scope = authUser.scope
return res.status(200).json({ authUser }) const token = jwt.sign(authUser, jwt_secret)
return res.status(200).json({ token })
} }
throw new MedusaError( throw new MedusaError(
@@ -0,0 +1,10 @@
import { MiddlewareRoute } from "../../types/middlewares"
import { authenticate } from "../../utils/authenticate-middleware"
export const authRoutesMiddlewares: MiddlewareRoute[] = [
{
method: ["POST"],
matcher: "/auth/session",
middlewares: [authenticate(/.*/, "bearer")],
},
]
@@ -0,0 +1,7 @@
import { MedusaRequest, MedusaResponse } from "../../../types/routing"
export const POST = async (req: MedusaRequest, res: MedusaResponse) => {
req.session.auth_user = req.auth_user
res.status(200).json({ user: req.auth_user })
}
@@ -5,6 +5,7 @@ import { storeCustomerRoutesMiddlewares } from "./store/customers/middlewares"
import { adminCustomerRoutesMiddlewares } from "./admin/customers/middlewares" import { adminCustomerRoutesMiddlewares } from "./admin/customers/middlewares"
import { adminPromotionRoutesMiddlewares } from "./admin/promotions/middlewares" import { adminPromotionRoutesMiddlewares } from "./admin/promotions/middlewares"
import { storeCartRoutesMiddlewares } from "./store/carts/middlewares" import { storeCartRoutesMiddlewares } from "./store/carts/middlewares"
import { authRoutesMiddlewares } from "./auth/middlewares"
export const config: MiddlewaresConfig = { export const config: MiddlewaresConfig = {
routes: [ routes: [
@@ -14,5 +15,6 @@ export const config: MiddlewaresConfig = {
...adminCampaignRoutesMiddlewares, ...adminCampaignRoutesMiddlewares,
...storeCustomerRoutesMiddlewares, ...storeCustomerRoutesMiddlewares,
...storeCartRoutesMiddlewares, ...storeCartRoutesMiddlewares,
...authRoutesMiddlewares,
], ],
} }
+2
View File
@@ -228,9 +228,11 @@ class InviteService extends TransactionBaseService {
verifyToken(token): JwtPayload | string { verifyToken(token): JwtPayload | string {
const { jwt_secret } = this.configModule_.projectConfig const { jwt_secret } = this.configModule_.projectConfig
if (jwt_secret) { if (jwt_secret) {
return jwt.verify(token, jwt_secret) return jwt.verify(token, jwt_secret)
} }
throw new MedusaError( throw new MedusaError(
MedusaError.Types.INVALID_DATA, MedusaError.Types.INVALID_DATA,
"Please configure jwt_secret" "Please configure jwt_secret"
-2
View File
@@ -1,7 +1,5 @@
import type { Customer, User } from "../models" import type { Customer, User } from "../models"
import type { NextFunction, Request, Response } from "express" import type { NextFunction, Request, Response } from "express"
import { AuthUserDTO } from "@medusajs/types"
import type { MedusaContainer } from "./global" import type { MedusaContainer } from "./global"
export interface MedusaRequest extends Request { export interface MedusaRequest extends Request {
@@ -1,8 +1,9 @@
import { AuthUserDTO, IAuthModuleService } from "@medusajs/types"
import { MedusaRequest, MedusaResponse } from "../types/routing" import { MedusaRequest, MedusaResponse } from "../types/routing"
import { NextFunction, RequestHandler } from "express" import { NextFunction, RequestHandler } from "express"
import jwt, { JwtPayload } from "jsonwebtoken"
import { ModuleRegistrationName } from "@medusajs/modules-sdk" import { AuthUserDTO } from "@medusajs/types"
import { stringEqualsOrRegexMatch } from "@medusajs/utils"
const SESSION_AUTH = "session" const SESSION_AUTH = "session"
const BEARER_AUTH = "bearer" const BEARER_AUTH = "bearer"
@@ -15,7 +16,7 @@ type MedusaSession = {
type AuthType = "session" | "bearer" type AuthType = "session" | "bearer"
export const authenticate = ( export const authenticate = (
authScope: string, authScope: string | RegExp,
authType: AuthType | AuthType[], authType: AuthType | AuthType[],
options: { allowUnauthenticated?: boolean } = {} options: { allowUnauthenticated?: boolean } = {}
): RequestHandler => { ): RequestHandler => {
@@ -25,22 +26,23 @@ export const authenticate = (
next: NextFunction next: NextFunction
): Promise<void> => { ): Promise<void> => {
const authTypes = Array.isArray(authType) ? authType : [authType] const authTypes = Array.isArray(authType) ? authType : [authType]
const authModule = req.scope.resolve<IAuthModuleService>(
ModuleRegistrationName.AUTH
)
// @ts-ignore // @ts-ignore
const session: MedusaSession = req.session || {} const session: MedusaSession = req.session || {}
let authUser: AuthUserDTO | null = null let authUser: AuthUserDTO | null = null
if (authTypes.includes(SESSION_AUTH)) { if (authTypes.includes(SESSION_AUTH)) {
if (session.auth_user && session.scope === authScope) { if (
session.auth_user &&
stringEqualsOrRegexMatch(authScope, session.auth_user.scope)
) {
authUser = session.auth_user authUser = session.auth_user
} }
} }
if (!authUser && authTypes.includes(BEARER_AUTH)) { if (!authUser && authTypes.includes(BEARER_AUTH)) {
const authHeader = req.headers.authorization const authHeader = req.headers.authorization
if (authHeader) { if (authHeader) {
const re = /(\S+)\s+(\S+)/ const re = /(\S+)\s+(\S+)/
const matches = authHeader.match(re) const matches = authHeader.match(re)
@@ -49,10 +51,17 @@ export const authenticate = (
if (matches) { if (matches) {
const tokenType = matches[1] const tokenType = matches[1]
const token = matches[2] const token = matches[2]
if (tokenType.toLowerCase() === "bearer") { if (tokenType.toLowerCase() === BEARER_AUTH) {
authUser = await authModule // get config jwt secret
.retrieveAuthUserFromJwtToken(token, authScope) // verify token and set authUser
.catch(() => null) const { jwt_secret } =
req.scope.resolve("configModule").projectConfig
const verified = jwt.verify(token, jwt_secret) as JwtPayload
if (stringEqualsOrRegexMatch(authScope, verified.scope)) {
authUser = verified as AuthUserDTO
}
} }
} }
} }
@@ -62,7 +71,7 @@ export const authenticate = (
req.auth_user = { req.auth_user = {
id: authUser.id, id: authUser.id,
app_metadata: authUser.app_metadata, app_metadata: authUser.app_metadata,
scope: authScope, scope: authUser.scope,
} }
return next() return next()
} }
-10
View File
@@ -76,16 +76,6 @@ export interface IAuthModuleService extends IModuleService {
sharedContext?: Context sharedContext?: Context
): Promise<AuthUserDTO> ): Promise<AuthUserDTO>
generateJwtToken(
authUserId: string,
scope: string,
options?: JWTGenerationOptions
): Promise<string>
retrieveAuthUserFromJwtToken(
token: string,
scope: string
): Promise<AuthUserDTO>
listAuthUsers( listAuthUsers(
filters?: FilterableAuthProviderProps, filters?: FilterableAuthProviderProps,
config?: FindConfig<AuthUserDTO>, config?: FindConfig<AuthUserDTO>,
+1 -1
View File
@@ -34,6 +34,7 @@ export * from "./remove-nullisih"
export * from "./selector-constraints-to-string" export * from "./selector-constraints-to-string"
export * from "./set-metadata" export * from "./set-metadata"
export * from "./simple-hash" export * from "./simple-hash"
export * from "./string-or-regex-equals"
export * from "./string-to-select-relation-object" export * from "./string-to-select-relation-object"
export * from "./stringify-circular" export * from "./stringify-circular"
export * from "./to-camel-case" export * from "./to-camel-case"
@@ -42,4 +43,3 @@ export * from "./to-pascal-case"
export * from "./transaction" export * from "./transaction"
export * from "./upper-case-first" export * from "./upper-case-first"
export * from "./wrap-handler" export * from "./wrap-handler"
@@ -0,0 +1,9 @@
export const stringEqualsOrRegexMatch = (
stringOrRegex: string | RegExp,
testString: string
) => {
if (stringOrRegex instanceof RegExp) {
return stringOrRegex.test(testString)
}
return stringOrRegex === testString
}