From 24bb26b81a14e3dcda811ff4c9334c228ae06e1b Mon Sep 17 00:00:00 2001 From: Philip Korsholm <88927411+pKorsholm@users.noreply.github.com> Date: Tue, 23 Jan 2024 16:04:22 +0700 Subject: [PATCH] Feat(authentication): username password provider (#6052) --- .../__fixtures__/auth-user/index.ts | 3 + .../services/auth-user/index.spec.ts | 1 + .../services/module/auth-user.spec.ts | 1 + ...{provider-loaders.ts => providers.spec.ts} | 25 +++- .../providers/username-password.spec.ts | 140 ++++++++++++++++++ packages/authentication/package.json | 3 +- .../authentication/src/initialize/index.ts | 5 +- .../authentication/src/loaders/providers.ts | 46 +++--- .../.snapshot-medusa-authentication.json | 19 +++ .../src/migrations/Migration20240115092929.ts | 15 ++ .../authentication/src/models/auth-user.ts | 9 +- .../src/providers/username-password.ts | 52 ++++++- .../authentication/src/services/auth-user.ts | 42 +++++- .../src/services/authentication-module.ts | 77 +++++++++- .../src/types/repositories/auth-user.ts | 1 + .../src/types/services/auth-user.ts | 2 + .../src/authentication/common/auth-user.ts | 2 + packages/types/src/authentication/provider.ts | 18 ++- packages/types/src/authentication/service.ts | 6 + yarn.lock | 1 + 20 files changed, 424 insertions(+), 44 deletions(-) rename packages/authentication/integration-tests/__tests__/services/module/{provider-loaders.ts => providers.spec.ts} (60%) create mode 100644 packages/authentication/integration-tests/__tests__/services/providers/username-password.spec.ts create mode 100644 packages/authentication/src/migrations/Migration20240115092929.ts diff --git a/packages/authentication/integration-tests/__fixtures__/auth-user/index.ts b/packages/authentication/integration-tests/__fixtures__/auth-user/index.ts index 7921cbdf90..46e745ffdc 100644 --- a/packages/authentication/integration-tests/__fixtures__/auth-user/index.ts +++ b/packages/authentication/integration-tests/__fixtures__/auth-user/index.ts @@ -6,13 +6,16 @@ export async function createAuthUsers( userData: any[] = [ { id: "test-id", + entity_id: "test-id", provider: "manual", }, { id: "test-id-1", + entity_id: "test-id-1", provider: "manual", }, { + entity_id: "test-id-2", provider: "store", }, ] diff --git a/packages/authentication/integration-tests/__tests__/services/auth-user/index.spec.ts b/packages/authentication/integration-tests/__tests__/services/auth-user/index.spec.ts index eaaf4324ef..07f7aa2426 100644 --- a/packages/authentication/integration-tests/__tests__/services/auth-user/index.spec.ts +++ b/packages/authentication/integration-tests/__tests__/services/auth-user/index.spec.ts @@ -229,6 +229,7 @@ describe("AuthUser Service", () => { { id: "test", provider_id: "manual", + entity_id: "test" }, ]) diff --git a/packages/authentication/integration-tests/__tests__/services/module/auth-user.spec.ts b/packages/authentication/integration-tests/__tests__/services/module/auth-user.spec.ts index 14dc31ef66..677fd8e35f 100644 --- a/packages/authentication/integration-tests/__tests__/services/module/auth-user.spec.ts +++ b/packages/authentication/integration-tests/__tests__/services/module/auth-user.spec.ts @@ -237,6 +237,7 @@ describe("AuthenticationModuleService - AuthUser", () => { { id: "test", provider_id: "manual", + entity_id: "test" }, ]) diff --git a/packages/authentication/integration-tests/__tests__/services/module/provider-loaders.ts b/packages/authentication/integration-tests/__tests__/services/module/providers.spec.ts similarity index 60% rename from packages/authentication/integration-tests/__tests__/services/module/provider-loaders.ts rename to packages/authentication/integration-tests/__tests__/services/module/providers.spec.ts index 36e513f95f..3a49d6c3b0 100644 --- a/packages/authentication/integration-tests/__tests__/services/module/provider-loaders.ts +++ b/packages/authentication/integration-tests/__tests__/services/module/providers.spec.ts @@ -5,6 +5,7 @@ import { initialize } from "../../../../src" import { DB_URL } from "@medusajs/pricing/integration-tests/utils" import { MedusaModule } from "@medusajs/modules-sdk" import { IAuthenticationModuleService } from "@medusajs/types" +import { createAuthProviders } from "../../../__fixtures__/auth-provider" jest.setTimeout(30000) @@ -22,6 +23,10 @@ describe("AuthenticationModuleService - AuthProvider", () => { schema: process.env.MEDUSA_PRICING_DB_SCHEMA, }, }) + + if(service.__hooks?.onApplicationStart) { + await service.__hooks.onApplicationStart() + } }) afterEach(async () => { @@ -30,7 +35,7 @@ describe("AuthenticationModuleService - AuthProvider", () => { }) describe("listAuthProviders", () => { - it("should list default AuthProviders", async () => { + it("should list default AuthProviders registered by loaders", async () => { const authProviders = await service.listAuthProviders() const serialized = JSON.parse(JSON.stringify(authProviders)) @@ -42,4 +47,22 @@ describe("AuthenticationModuleService - AuthProvider", () => { ]) }) }) + + describe("authenticate", () => { + it("authenticate validates that a provider is registered in container", async () => { + await createAuthProviders(testManager, [ + { + provider: "notRegistered", + name: "test", + }, + ]) + + const { success, error } = await service.authenticate("notRegistered", {}) + + expect(success).toBe(false) + expect(error).toEqual( + "AuthenticationProvider with for provider: notRegistered wasn't registered in the module. Have you configured your options correctly?" + ) + }) + }) }) diff --git a/packages/authentication/integration-tests/__tests__/services/providers/username-password.spec.ts b/packages/authentication/integration-tests/__tests__/services/providers/username-password.spec.ts new file mode 100644 index 0000000000..7902c1591c --- /dev/null +++ b/packages/authentication/integration-tests/__tests__/services/providers/username-password.spec.ts @@ -0,0 +1,140 @@ +import { SqlEntityManager } from "@mikro-orm/postgresql" +import Scrypt from "scrypt-kdf" + +import { MikroOrmWrapper } from "../../../utils" +import { initialize } from "../../../../src" +import { DB_URL } from "@medusajs/pricing/integration-tests/utils" +import { MedusaModule } from "@medusajs/modules-sdk" +import { IAuthenticationModuleService } from "@medusajs/types" +import { createAuthUsers } from "../../../__fixtures__/auth-user" +import { createAuthProviders } from "../../../__fixtures__/auth-provider" + +jest.setTimeout(30000) +const seedDefaultData = async (testManager) => { + await createAuthProviders(testManager) + await createAuthUsers(testManager) +} + +describe("AuthenticationModuleService - AuthProvider", () => { + let service: IAuthenticationModuleService + let testManager: SqlEntityManager + + beforeEach(async () => { + await MikroOrmWrapper.setupDatabase() + testManager = MikroOrmWrapper.forkManager() + + service = await initialize({ + database: { + clientUrl: DB_URL, + schema: process.env.MEDUSA_PRICING_DB_SCHEMA, + }, + }) + + if(service.__hooks?.onApplicationStart) { + await service.__hooks.onApplicationStart() + } + }) + + afterEach(async () => { + await MikroOrmWrapper.clearDatabase() + MedusaModule.clearInstances() + }) + + describe("authenticate", () => { + it("authenticate validates that a provider is registered in container", async () => { + const password = "supersecret" + const email = "test@test.com" + const passwordHash = ( + await Scrypt.kdf(password, { logN: 15, r: 8, p: 1 }) + ).toString("base64") + + await seedDefaultData(testManager) + await createAuthUsers(testManager, [ + // Add authenticated user + { + provider: "usernamePassword", + entity_id: email, + provider_metadata: { + password: passwordHash, + }, + }, + ]) + + const res = await service.authenticate("usernamePassword", { + body: { + email: "test@test.com", + password: password, + }, + }) + + expect(res).toEqual({ + success: true, + authUser: expect.objectContaining({ + entity_id: email, + provider_metadata: { + }, + }), + }) + }) + + it("fails when no password is given", async () => { + const email = "test@test.com" + + await seedDefaultData(testManager) + + const res = await service.authenticate("usernamePassword", { + body: { email: "test@test.com" }, + }) + + expect(res).toEqual({ + success: false, + error: "Password should be a string", + }) + }) + + it("fails when no email is given", async () => { + await seedDefaultData(testManager) + + const res = await service.authenticate("usernamePassword", { + body: { password: "supersecret" }, + }) + + expect(res).toEqual({ + success: false, + error: "Email should be a string", + }) + }) + + it("fails with an invalid password", async () => { + const password = "supersecret" + const email = "test@test.com" + const passwordHash = ( + await Scrypt.kdf(password, { logN: 15, r: 8, p: 1 }) + ).toString("base64") + + await seedDefaultData(testManager) + await createAuthUsers(testManager, [ + // Add authenticated user + { + provider: "usernamePassword", + entity_id: email, + provider_metadata: { + password_hash: passwordHash, + }, + }, + ]) + + const res = await service.authenticate("usernamePassword", { + body: { + email: "test@test.com", + password: "password", + }, + }) + + expect(res).toEqual({ + success: false, + error: "Invalid email or password", + }) + }) + }) +}) diff --git a/packages/authentication/package.json b/packages/authentication/package.json index 05fb16fbbf..8fbf500cb8 100644 --- a/packages/authentication/package.json +++ b/packages/authentication/package.json @@ -56,6 +56,7 @@ "@mikro-orm/postgresql": "5.9.7", "awilix": "^8.0.0", "dotenv": "^16.1.4", - "knex": "2.4.2" + "knex": "2.4.2", + "scrypt-kdf": "^2.0.1" } } diff --git a/packages/authentication/src/initialize/index.ts b/packages/authentication/src/initialize/index.ts index cfd284f1e9..2328c27688 100644 --- a/packages/authentication/src/initialize/index.ts +++ b/packages/authentication/src/initialize/index.ts @@ -1,13 +1,14 @@ import { ExternalModuleDeclaration, InternalModuleDeclaration, - MedusaModule, MODULE_PACKAGE_NAMES, + MedusaModule, Modules, } from "@medusajs/modules-sdk" import { IAuthenticationModuleService, ModulesSdkTypes } from "@medusajs/types" -import { moduleDefinition } from "../module-definition" + import { InitializeModuleInjectableDependencies } from "../types" +import { moduleDefinition } from "../module-definition" export const initialize = async ( options?: diff --git a/packages/authentication/src/loaders/providers.ts b/packages/authentication/src/loaders/providers.ts index d21a31db0b..0ffa6eee8f 100644 --- a/packages/authentication/src/loaders/providers.ts +++ b/packages/authentication/src/loaders/providers.ts @@ -1,12 +1,11 @@ -import { LoaderOptions, ModulesSdkTypes } from "@medusajs/types" -import { asClass } from "awilix" import * as defaultProviders from "@providers" -import { AuthProviderService } from "@services" -import { ServiceTypes } from "@types" + +import { LoaderOptions, ModulesSdkTypes } from "@medusajs/types" + +import { AwilixContainer, ClassOrFunctionReturning, Resolver, asClass, asFunction, asValue } from "awilix" export default async ({ container, - options, }: LoaderOptions< | ModulesSdkTypes.ModuleServiceInitializeOptions | ModulesSdkTypes.ModuleServiceInitializeCustomDataLayerOptions @@ -17,33 +16,22 @@ export default async ({ const providersToLoad = Object.values(defaultProviders) - const authProviderService: AuthProviderService = - container.cradle["authProviderService"] - - const providers = await authProviderService.list({ - provider: providersToLoad.map((p) => p.PROVIDER), - }) - - const loadedProviders = new Map(providers.map((p) => [p.provider, p])) - - const providersToCreate: ServiceTypes.CreateAuthProviderDTO[] = [] - for (const provider of providersToLoad) { - container.registerAdd("providers", asClass(provider).singleton()) - container.register({ - [`provider_${provider.PROVIDER}`]: asClass(provider).singleton(), - }) - - if (loadedProviders.has(provider.PROVIDER)) { - continue - } - - providersToCreate.push({ - provider: provider.PROVIDER, - name: provider.DISPLAY_NAME, + [`auth_provider_${provider.PROVIDER}`]: asClass(provider).singleton(), }) } - await authProviderService.create(providersToCreate) + container.register({ + [`auth_providers`]: asArray(providersToLoad), + }) +} + +function asArray( + resolvers: (ClassOrFunctionReturning | Resolver)[] +): { resolve: (container: AwilixContainer) => unknown[] } { + return { + resolve: (container: AwilixContainer) => + resolvers.map((resolver) => container.build(resolver)), + } } diff --git a/packages/authentication/src/migrations/.snapshot-medusa-authentication.json b/packages/authentication/src/migrations/.snapshot-medusa-authentication.json index 0d3f1eaba1..f7ebcf17c1 100644 --- a/packages/authentication/src/migrations/.snapshot-medusa-authentication.json +++ b/packages/authentication/src/migrations/.snapshot-medusa-authentication.json @@ -77,6 +77,15 @@ "nullable": false, "mappedType": "text" }, + "entity_id": { + "name": "entity_id", + "type": "text", + "unsigned": false, + "autoincrement": false, + "primary": false, + "nullable": false, + "mappedType": "text" + }, "provider_id": { "name": "provider_id", "type": "text", @@ -117,6 +126,16 @@ "name": "auth_user", "schema": "public", "indexes": [ + { + "keyName": "IDX_auth_user_provider_entity_id", + "columnNames": [ + "provider_id", + "entity_id" + ], + "composite": true, + "primary": false, + "unique": true + }, { "keyName": "auth_user_pkey", "columnNames": [ diff --git a/packages/authentication/src/migrations/Migration20240115092929.ts b/packages/authentication/src/migrations/Migration20240115092929.ts new file mode 100644 index 0000000000..d063929344 --- /dev/null +++ b/packages/authentication/src/migrations/Migration20240115092929.ts @@ -0,0 +1,15 @@ +import { Migration } from '@mikro-orm/migrations'; + +export class Migration20240115092929 extends Migration { + + async up(): Promise { + this.addSql('alter table "auth_user" add column "entity_id" text not null;'); + this.addSql('alter table "auth_user" add constraint "IDX_auth_user_provider_entity_id" unique ("provider_id", "entity_id");'); + } + + async down(): Promise { + this.addSql('alter table "auth_user" drop constraint "IDX_auth_user_provider_entity_id";'); + this.addSql('alter table "auth_user" drop column "entity_id";'); + } + +} diff --git a/packages/authentication/src/models/auth-user.ts b/packages/authentication/src/models/auth-user.ts index e90cb10130..0c10053175 100644 --- a/packages/authentication/src/models/auth-user.ts +++ b/packages/authentication/src/models/auth-user.ts @@ -1,25 +1,32 @@ -import { generateEntityId } from "@medusajs/utils" import { BeforeCreate, Cascade, Entity, + Index, ManyToOne, OnInit, OptionalProps, PrimaryKey, Property, + Unique, } from "@mikro-orm/core" + import AuthProvider from "./auth-provider" +import { generateEntityId } from "@medusajs/utils" type OptionalFields = "provider_metadata" | "app_metadata" | "user_metadata" @Entity() +@Unique({ properties: ["provider","entity_id" ], name: "IDX_auth_user_provider_entity_id" }) export default class AuthUser { [OptionalProps]: OptionalFields @PrimaryKey({ columnType: "text" }) id!: string + @Property({ columnType: "text" }) + entity_id: string + @ManyToOne(() => AuthProvider, { joinColumn: "provider", fieldName: "provider_id", diff --git a/packages/authentication/src/providers/username-password.ts b/packages/authentication/src/providers/username-password.ts index 1b3ca03a17..c6428253dc 100644 --- a/packages/authentication/src/providers/username-password.ts +++ b/packages/authentication/src/providers/username-password.ts @@ -1,5 +1,11 @@ +import { + AbstractAuthenticationModuleProvider, + AuthenticationResponse, +} from "@medusajs/types" + import { AuthUserService } from "@services" -import { AbstractAuthenticationModuleProvider } from "@medusajs/types" +import Scrypt from "scrypt-kdf" +import { isString } from "@medusajs/utils" class UsernamePasswordProvider extends AbstractAuthenticationModuleProvider { public static PROVIDER = "usernamePassword" @@ -13,8 +19,48 @@ class UsernamePasswordProvider extends AbstractAuthenticationModuleProvider { this.authUserSerivce_ = AuthUserService } - async authenticate(userData: Record) { - return {} + async authenticate( + userData: Record + ): Promise { + const { email, password } = userData.body + + if (!password || !isString(password)) { + return { + success: false, + error: "Password should be a string", + } + } + + if (!email || !isString(email)) { + return { + success: false, + error: "Email should be a string", + } + } + + const authUser = await this.authUserSerivce_.retrieveByProviderAndEntityId( + email, + UsernamePasswordProvider.PROVIDER + ) + + const password_hash = authUser.provider_metadata?.password + + if (isString(password_hash)) { + const buf = Buffer.from(password_hash, "base64") + + const success = await Scrypt.verify(buf, password) + + if (success) { + delete authUser.provider_metadata!.password + + return { success, authUser: JSON.parse(JSON.stringify(authUser)) } + } + } + + return { + success: false, + error: "Invalid email or password", + } } } diff --git a/packages/authentication/src/services/auth-user.ts b/packages/authentication/src/services/auth-user.ts index 352d818a2a..8ee6285386 100644 --- a/packages/authentication/src/services/auth-user.ts +++ b/packages/authentication/src/services/auth-user.ts @@ -1,8 +1,12 @@ -import { DAL } from "@medusajs/types" -import { ModulesSdkUtils } from "@medusajs/utils" +import { AuthenticationTypes, Context, DAL, FindConfig } from "@medusajs/types" +import { + InjectManager, + MedusaContext, + MedusaError, + ModulesSdkUtils, +} from "@medusajs/utils" import { AuthUser } from "@models" - -import { ServiceTypes } from "@types" +import { ServiceTypes, RepositoryTypes } from "@types" type InjectedDependencies = { authUserRepository: DAL.RepositoryService @@ -16,8 +20,38 @@ export default class AuthUserService< create: ServiceTypes.CreateAuthUserDTO } >(AuthUser) { + protected readonly authUserRepository_: RepositoryTypes.IAuthUserRepository constructor(container: InjectedDependencies) { // @ts-ignore super(...arguments) + this.authUserRepository_ = container.authUserRepository + } + + @InjectManager("authUserRepository_") + async retrieveByProviderAndEntityId< + TEntityMethod = AuthenticationTypes.AuthUserDTO + >( + entityId: string, + provider: string, + config: FindConfig = {}, + @MedusaContext() sharedContext: Context = {} + ): Promise { + const queryConfig = ModulesSdkUtils.buildQuery( + { entity_id: entityId, provider }, + { ...config, take: 1 } + ) + const [result] = await this.authUserRepository_.find( + queryConfig, + sharedContext + ) + + if (!result) { + throw new MedusaError( + MedusaError.Types.NOT_FOUND, + `AuthUser with entity_id: "${entityId}" and provider: "${provider}" not found` + ) + } + + return result } } diff --git a/packages/authentication/src/services/authentication-module.ts b/packages/authentication/src/services/authentication-module.ts index d47c094b3e..93365943b3 100644 --- a/packages/authentication/src/services/authentication-module.ts +++ b/packages/authentication/src/services/authentication-module.ts @@ -1,9 +1,12 @@ import { + AbstractAuthenticationModuleProvider, + AuthenticationResponse, AuthenticationTypes, Context, DAL, FindConfig, InternalModuleDeclaration, + MedusaContainer, ModuleJoinerConfig, } from "@medusajs/types" @@ -11,10 +14,12 @@ import { AuthProvider, AuthUser } from "@models" import { joinerConfig } from "../joiner-config" import { AuthProviderService, AuthUserService } from "@services" + import { InjectManager, InjectTransactionManager, MedusaContext, + MedusaError, } from "@medusajs/utils" import { AuthProviderDTO, @@ -25,6 +30,7 @@ import { FilterableAuthUserProps, UpdateAuthUserDTO, } from "@medusajs/types/dist/authentication/common" +import { ServiceTypes } from "@types" type InjectedDependencies = { baseRepository: DAL.RepositoryService @@ -37,6 +43,15 @@ export default class AuthenticationModuleService< TAuthProvider extends AuthProvider = AuthProvider > implements AuthenticationTypes.IAuthenticationModuleService { + __joinerConfig(): ModuleJoinerConfig { + return joinerConfig + } + + __hooks = { + onApplicationStart: async () => await this.createProvidersOnLoad(), + } + + protected __container__: MedusaContainer protected baseRepository_: DAL.RepositoryService protected authUserService_: AuthUserService @@ -50,6 +65,7 @@ export default class AuthenticationModuleService< }: InjectedDependencies, protected readonly moduleDeclaration: InternalModuleDeclaration ) { + this.__container__ = arguments[0] this.baseRepository_ = baseRepository this.authUserService_ = authUserService this.authProviderService_ = authProviderService @@ -336,7 +352,64 @@ export default class AuthenticationModuleService< await this.authUserService_.delete(ids, sharedContext) } - __joinerConfig(): ModuleJoinerConfig { - return joinerConfig + protected getRegisteredAuthenticationProvider( + provider: string + ): AbstractAuthenticationModuleProvider { + let containerProvider: AbstractAuthenticationModuleProvider + try { + containerProvider = this.__container__[`auth_provider_${provider}`] + } catch (error) { + throw new MedusaError( + MedusaError.Types.NOT_FOUND, + `AuthenticationProvider with for provider: ${provider} wasn't registered in the module. Have you configured your options correctly?` + ) + } + + return containerProvider + } + + @InjectTransactionManager("baseRepository_") + async authenticate( + provider: string, + authenticationData: Record, + @MedusaContext() sharedContext: Context = {} + ): Promise { + let registeredProvider + + try { + await this.retrieveAuthProvider(provider, {}) + + registeredProvider = this.getRegisteredAuthenticationProvider(provider) + + return await registeredProvider.authenticate(authenticationData) + } catch (error) { + return { success: false, error: error.message } + } + } + + + private async createProvidersOnLoad() { + const providersToLoad = this.__container__["auth_providers"] + + const providers = await this.authProviderService_.list({ + provider: providersToLoad.map((p) => p.provider), + }) + + const loadedProvidersMap = new Map(providers.map((p) => [p.provider, p])) + + const providersToCreate: ServiceTypes.CreateAuthProviderDTO[] = [] + + for (const provider of providersToLoad) { + if (loadedProvidersMap.has(provider.provider)) { + continue + } + + providersToCreate.push({ + provider: provider.provider, + name: provider.displayName, + }) + } + + await this.authProviderService_.create(providersToCreate) } } diff --git a/packages/authentication/src/types/repositories/auth-user.ts b/packages/authentication/src/types/repositories/auth-user.ts index 33315b20e1..541f465838 100644 --- a/packages/authentication/src/types/repositories/auth-user.ts +++ b/packages/authentication/src/types/repositories/auth-user.ts @@ -2,6 +2,7 @@ import { AuthUser } from "@models" export type CreateAuthUserDTO = { provider_id: string + entity_id: string provider_metadata?: Record user_metadata?: Record app_metadata?: Record diff --git a/packages/authentication/src/types/services/auth-user.ts b/packages/authentication/src/types/services/auth-user.ts index 18c8899303..c059e980f8 100644 --- a/packages/authentication/src/types/services/auth-user.ts +++ b/packages/authentication/src/types/services/auth-user.ts @@ -3,6 +3,7 @@ import { AuthProviderDTO } from "./auth-provider" export type AuthUserDTO = { id: string provider_id: string + entity_id: string provider: AuthProviderDTO provider_metadata?: Record user_metadata: Record @@ -10,6 +11,7 @@ export type AuthUserDTO = { } export type CreateAuthUserDTO = { + entity_id: string provider_id: string provider_metadata?: Record user_metadata?: Record diff --git a/packages/types/src/authentication/common/auth-user.ts b/packages/types/src/authentication/common/auth-user.ts index ae5b03b0fe..11357a10eb 100644 --- a/packages/types/src/authentication/common/auth-user.ts +++ b/packages/types/src/authentication/common/auth-user.ts @@ -4,6 +4,7 @@ import { AuthProviderDTO } from "./auth-provider" export type AuthUserDTO = { id: string provider_id: string + entity_id: string provider: AuthProviderDTO provider_metadata?: Record user_metadata: Record @@ -12,6 +13,7 @@ export type AuthUserDTO = { export type CreateAuthUserDTO = { provider_id: string + entity_id: string provider_metadata?: Record user_metadata?: Record app_metadata?: Record diff --git a/packages/types/src/authentication/provider.ts b/packages/types/src/authentication/provider.ts index db950c2077..8a709a6db9 100644 --- a/packages/types/src/authentication/provider.ts +++ b/packages/types/src/authentication/provider.ts @@ -1,8 +1,24 @@ +import { AuthUserDTO } from "./common" + export abstract class AbstractAuthenticationModuleProvider { public static PROVIDER: string public static DISPLAY_NAME: string + public get provider() { + return (this.constructor as Function & { PROVIDER: string}).PROVIDER + } + + public get displayName() { + return (this.constructor as Function & { DISPLAY_NAME: string}).DISPLAY_NAME + } + abstract authenticate( data: Record - ): Promise> + ): Promise +} + +export type AuthenticationResponse = { + success: boolean + authUser?: AuthUserDTO + error?: string } diff --git a/packages/types/src/authentication/service.ts b/packages/types/src/authentication/service.ts index 78df1eabca..64d63fb25e 100644 --- a/packages/types/src/authentication/service.ts +++ b/packages/types/src/authentication/service.ts @@ -11,8 +11,14 @@ import { } from "./common" import { FindConfig } from "../common" import { Context } from "../shared-context" +import { AuthenticationResponse } from "./provider" export interface IAuthenticationModuleService extends IModuleService { + authenticate( + provider: string, + providerData: Record + ): Promise + retrieveAuthProvider( provider: string, config?: FindConfig, diff --git a/yarn.lock b/yarn.lock index ee39d59dc0..dcfec06735 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7857,6 +7857,7 @@ __metadata: knex: 2.4.2 medusa-test-utils: ^1.1.40 rimraf: ^3.0.2 + scrypt-kdf: ^2.0.1 ts-jest: ^29.1.1 ts-node: ^10.9.1 tsc-alias: ^1.8.6