Feat(auth): Remove auth provider entity (#6314)

**What**
- remove auth provider entity

**Why**
- The auth provider entity was not really used anywhere

**How**
- Keeping loader behavior as is but removing the 

Co-authored-by: Sebastian Rindom <7554214+srindom@users.noreply.github.com>
This commit is contained in:
Philip Korsholm
2024-02-06 07:54:34 +00:00
committed by GitHub
co-authored by Sebastian Rindom
parent b2eaac8cb1
commit 882aa549bd
37 changed files with 179 additions and 1223 deletions
@@ -4,71 +4,6 @@
],
"name": "public",
"tables": [
{
"columns": {
"provider": {
"name": "provider",
"type": "text",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": false,
"mappedType": "text"
},
"name": {
"name": "name",
"type": "text",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": false,
"mappedType": "text"
},
"scope": {
"name": "scope",
"type": "text",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": true,
"mappedType": "text"
},
"config": {
"name": "config",
"type": "jsonb",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": true,
"mappedType": "json"
},
"is_active": {
"name": "is_active",
"type": "boolean",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": false,
"default": "false",
"mappedType": "boolean"
}
},
"name": "auth_provider",
"schema": "public",
"indexes": [
{
"keyName": "auth_provider_pkey",
"columnNames": [
"provider"
],
"composite": false,
"primary": true,
"unique": true
}
],
"checks": [],
"foreignKeys": {}
},
{
"columns": {
"id": {
@@ -89,13 +24,13 @@
"nullable": false,
"mappedType": "text"
},
"provider_id": {
"name": "provider_id",
"provider": {
"name": "provider",
"type": "text",
"unsigned": false,
"autoincrement": false,
"primary": false,
"nullable": true,
"nullable": false,
"mappedType": "text"
},
"scope": {
@@ -141,7 +76,7 @@
{
"keyName": "IDX_auth_user_provider_scope_entity_id",
"columnNames": [
"provider_id",
"provider",
"scope",
"entity_id"
],
@@ -160,20 +95,7 @@
}
],
"checks": [],
"foreignKeys": {
"auth_user_provider_id_foreign": {
"constraintName": "auth_user_provider_id_foreign",
"columnNames": [
"provider_id"
],
"localTableName": "public.auth_user",
"referencedColumnNames": [
"provider"
],
"referencedTableName": "public.auth_provider",
"deleteRule": "cascade"
}
}
"foreignKeys": {}
}
]
}
@@ -1,22 +0,0 @@
import { Migration } from '@mikro-orm/migrations';
export class Migration20240201100135 extends Migration {
async up(): Promise<void> {
this.addSql('create table "auth_provider" ("provider" text not null, "name" text not null, "scope" text null, "config" jsonb null, "is_active" boolean not null default false, constraint "auth_provider_pkey" primary key ("provider"));');
this.addSql('create table "auth_user" ("id" text not null, "entity_id" text not null, "provider_id" text null, "scope" text not null, "user_metadata" jsonb null, "app_metadata" jsonb not null, "provider_metadata" jsonb null, constraint "auth_user_pkey" primary key ("id"));');
this.addSql('alter table "auth_user" add constraint "IDX_auth_user_provider_scope_entity_id" unique ("provider_id", "scope", "entity_id");');
this.addSql('alter table "auth_user" add constraint "auth_user_provider_id_foreign" foreign key ("provider_id") references "auth_provider" ("provider") on delete cascade;');
}
async down(): Promise<void> {
this.addSql('alter table "auth_user" drop constraint "auth_user_provider_id_foreign";');
this.addSql('drop table if exists "auth_provider" cascade;');
this.addSql('drop table if exists "auth_user" cascade;');
}
}
@@ -0,0 +1,16 @@
import { Migration } from "@mikro-orm/migrations"
export class Migration20240205025924 extends Migration {
async up(): Promise<void> {
this.addSql(
'create table if not exists "auth_user" ("id" text not null, "entity_id" text not null, "provider" text not null, "scope" text not null, "user_metadata" jsonb null, "app_metadata" jsonb not null, "provider_metadata" jsonb null, constraint "auth_user_pkey" primary key ("id"));'
)
this.addSql(
'alter table "auth_user" add constraint "IDX_auth_user_provider_scope_entity_id" unique ("provider", "scope", "entity_id");'
)
}
async down(): Promise<void> {
this.addSql('drop table if exists "auth_user" cascade;')
}
}
-31
View File
@@ -1,31 +0,0 @@
import {
Entity,
Enum,
OptionalProps,
PrimaryKey,
Property,
} from "@mikro-orm/core"
import { ProviderDomain } from "../types/repositories/auth-provider"
type OptionalFields = "domain" | "is_active" | "config"
@Entity()
export default class AuthProvider {
[OptionalProps]: OptionalFields
@PrimaryKey({ columnType: "text" })
provider!: string
@Property({ columnType: "text" })
name: string
@Property({ columnType: "text", nullable: true })
scope: string
@Property({ columnType: "jsonb", nullable: true })
config: Record<string, unknown> | null = null
@Property({ columnType: "boolean", default: false })
is_active = false
}
+2 -7
View File
@@ -11,7 +11,6 @@ import {
Unique,
} from "@mikro-orm/core"
import AuthProvider from "./auth-provider"
import { generateEntityId } from "@medusajs/utils"
type OptionalFields = "provider_metadata" | "app_metadata" | "user_metadata"
@@ -30,12 +29,8 @@ export default class AuthUser {
@Property({ columnType: "text" })
entity_id: string
@ManyToOne(() => AuthProvider, {
joinColumn: "provider",
fieldName: "provider_id",
cascade: [Cascade.REMOVE],
})
provider: AuthProvider
@Property({ columnType: "text" })
provider: string
@Property({ columnType: "text" })
scope: string
-1
View File
@@ -1,2 +1 @@
export { default as AuthUser } from "./auth-user"
export { default as AuthProvider } from "./auth-provider"
@@ -15,13 +15,16 @@ class EmailPasswordProvider extends AbstractAuthModuleProvider {
protected readonly authUserSerivce_: AuthUserService
constructor({ authUserService }: { authUserService: AuthUserService }) {
super(arguments[0])
super(arguments[0], {
provider: EmailPasswordProvider.PROVIDER,
displayName: EmailPasswordProvider.DISPLAY_NAME,
})
this.authUserSerivce_ = authUserService
}
private getHashConfig(scope: string) {
const scopeConfig = this.scopes_[scope].hashConfig as
private getHashConfig() {
const scopeConfig = this.scopeConfig_.hashConfig as
| Scrypt.ScryptParams
| undefined
@@ -58,16 +61,13 @@ class EmailPasswordProvider extends AbstractAuthModuleProvider {
)
} catch (error) {
if (error.type === MedusaError.Types.NOT_FOUND) {
const password_hash = await Scrypt.kdf(
password,
this.getHashConfig(userData.authScope)
)
const password_hash = await Scrypt.kdf(password, this.getHashConfig())
const [createdAuthUser] = await this.authUserSerivce_.create([
{
entity_id: email,
provider: EmailPasswordProvider.PROVIDER,
scope: userData.authScope,
scope: this.scope_,
provider_metadata: {
password: password_hash.toString("base64"),
},
+17 -19
View File
@@ -5,9 +5,9 @@ import {
AuthenticationResponse,
ModulesSdkTypes,
} from "@medusajs/types"
import { AuthUserService } from "@services"
import jwt, { JwtPayload } from "jsonwebtoken"
import { AuthUserService } from "@services"
import { AuthorizationCode } from "simple-oauth2"
import url from "url"
@@ -30,7 +30,10 @@ class GoogleProvider extends AbstractAuthModuleProvider {
protected readonly authProviderService_: ModulesSdkTypes.InternalModuleService<any>
constructor({ authUserService, authProviderService }: InjectedDependencies) {
super(arguments[0])
super(arguments[0], {
provider: GoogleProvider.PROVIDER,
displayName: GoogleProvider.DISPLAY_NAME,
})
this.authUserService_ = authUserService
this.authProviderService_ = authProviderService
@@ -77,11 +80,11 @@ class GoogleProvider extends AbstractAuthModuleProvider {
const code = req.query?.code ?? req.body?.code
return await this.validateCallbackToken(code, req.authScope, config)
return await this.validateCallbackToken(code, config)
}
// abstractable
async verify_(refreshToken: string, scope: string) {
async verify_(refreshToken: string) {
const jwtData = jwt.decode(refreshToken, {
complete: true,
}) as JwtPayload
@@ -101,7 +104,7 @@ class GoogleProvider extends AbstractAuthModuleProvider {
entity_id,
provider: GoogleProvider.PROVIDER,
user_metadata: jwtData!.payload,
scope,
scope: this.scope_,
},
])
authUser = createdAuthUser
@@ -116,7 +119,6 @@ class GoogleProvider extends AbstractAuthModuleProvider {
// abstractable
private async validateCallbackToken(
code: string,
scope: string,
{ clientID, callbackURL, clientSecret }: ProviderConfig
) {
const client = this.getAuthorizationCodeHandler({ clientID, clientSecret })
@@ -129,30 +131,28 @@ class GoogleProvider extends AbstractAuthModuleProvider {
try {
const accessToken = await client.getToken(tokenParams)
return await this.verify_(accessToken.token.id_token, scope)
return await this.verify_(accessToken.token.id_token)
} catch (error) {
return { success: false, error: error.message }
}
}
private getConfigFromScope(
config: AuthProviderScope & Partial<ProviderConfig>
): ProviderConfig {
const providerConfig: Partial<ProviderConfig> = { ...config }
private getConfigFromScope(): ProviderConfig {
const config: Partial<ProviderConfig> = { ...this.scopeConfig_ }
if (!providerConfig.clientID) {
if (!config.clientID) {
throw new Error("Google clientID is required")
}
if (!providerConfig.clientSecret) {
if (!config.clientSecret) {
throw new Error("Google clientSecret is required")
}
if (!providerConfig.callbackURL) {
if (!config.callbackURL) {
throw new Error("Google callbackUrl is required")
}
return providerConfig as ProviderConfig
return config as ProviderConfig
}
private originalURL(req: AuthenticationInput) {
@@ -168,11 +168,9 @@ class GoogleProvider extends AbstractAuthModuleProvider {
): Promise<ProviderConfig> {
await this.authProviderService_.retrieve(GoogleProvider.PROVIDER)
const scopeConfig = this.scopes_[req.authScope]
const config = this.getConfigFromScope()
const config = this.getConfigFromScope(scopeConfig)
const { callbackURL } = config
const callbackURL = config.callbackURL
const parsedCallbackUrl = !url.parse(callbackURL).protocol
? url.resolve(this.originalURL(req), callbackURL)
+17 -162
View File
@@ -1,11 +1,9 @@
import {
AuthenticationInput,
AuthenticationResponse,
AuthProviderDTO,
AuthTypes,
AuthUserDTO,
Context,
CreateAuthProviderDTO,
CreateAuthUserDTO,
DAL,
InternalModuleDeclaration,
@@ -14,7 +12,7 @@ import {
UpdateAuthUserDTO,
} from "@medusajs/types"
import { AuthProvider, AuthUser } from "@models"
import { AuthUser } from "@models"
import { entityNameToLinkableKeysMap, joinerConfig } from "../joiner-config"
@@ -26,43 +24,29 @@ import {
MedusaError,
ModulesSdkUtils,
} from "@medusajs/utils"
import { ServiceTypes } from "@types"
type InjectedDependencies = {
baseRepository: DAL.RepositoryService
authUserService: ModulesSdkTypes.InternalModuleService<any>
authProviderService: ModulesSdkTypes.InternalModuleService<any>
}
const generateMethodForModels = [AuthProvider, AuthUser]
const generateMethodForModels = [AuthUser]
export default class AuthModuleService<
TAuthUser extends AuthUser = AuthUser,
TAuthProvider extends AuthProvider = AuthProvider
>
export default class AuthModuleService<TAuthUser extends AuthUser = AuthUser>
extends ModulesSdkUtils.abstractModuleServiceFactory<
InjectedDependencies,
AuthTypes.AuthProviderDTO,
AuthTypes.AuthUserDTO,
{
AuthUser: { dto: AuthUserDTO }
AuthProvider: { dto: AuthProviderDTO }
}
>(AuthProvider, generateMethodForModels, entityNameToLinkableKeysMap)
>(AuthUser, generateMethodForModels, entityNameToLinkableKeysMap)
implements AuthTypes.IAuthModuleService
{
__hooks = {
onApplicationStart: async () => await this.createProvidersOnLoad(),
}
protected baseRepository_: DAL.RepositoryService
protected authUserService_: ModulesSdkTypes.InternalModuleService<TAuthUser>
protected authProviderService_: ModulesSdkTypes.InternalModuleService<TAuthProvider>
constructor(
{
authUserService,
authProviderService,
baseRepository,
}: InjectedDependencies,
{ authUserService, baseRepository }: InjectedDependencies,
protected readonly moduleDeclaration: InternalModuleDeclaration
) {
// @ts-ignore
@@ -70,94 +54,25 @@ export default class AuthModuleService<
this.baseRepository_ = baseRepository
this.authUserService_ = authUserService
this.authProviderService_ = authProviderService
}
__joinerConfig(): ModuleJoinerConfig {
return joinerConfig
}
async createAuthProvider(
data: CreateAuthProviderDTO[],
sharedContext?: Context
): Promise<AuthProviderDTO[]>
async createAuthProvider(
data: CreateAuthProviderDTO,
sharedContext?: Context
): Promise<AuthProviderDTO>
@InjectManager("baseRepository_")
async createAuthProvider(
data: CreateAuthProviderDTO | CreateAuthProviderDTO[],
@MedusaContext() sharedContext: Context = {}
): Promise<AuthTypes.AuthProviderDTO | AuthTypes.AuthProviderDTO[]> {
const input = Array.isArray(data) ? data : [data]
const providers = await this.createAuthProviders_(input, sharedContext)
const serializedProviders = await this.baseRepository_.serialize<
AuthTypes.AuthProviderDTO[]
>(providers, {
populate: true,
})
return Array.isArray(data) ? serializedProviders : serializedProviders[0]
}
updateAuthProvider(
data: AuthTypes.UpdateAuthProviderDTO[],
sharedContext?: Context
): Promise<AuthProviderDTO[]>
updateAuthProvider(
data: AuthTypes.UpdateAuthProviderDTO,
sharedContext?: Context
): Promise<AuthProviderDTO>
@InjectManager("baseRepository_")
async updateAuthProvider(
data: AuthTypes.UpdateAuthProviderDTO[] | AuthTypes.UpdateAuthProviderDTO,
@MedusaContext() sharedContext: Context = {}
): Promise<AuthTypes.AuthProviderDTO | AuthTypes.AuthProviderDTO[]> {
const input = Array.isArray(data) ? data : [data]
const providers = await this.updateAuthProvider_(input, sharedContext)
const serializedProviders = await this.baseRepository_.serialize<
AuthTypes.AuthProviderDTO[]
>(providers, {
populate: true,
})
return Array.isArray(data) ? serializedProviders : serializedProviders[0]
}
async updateAuthProvider_(
data: AuthTypes.UpdateAuthProviderDTO[],
@MedusaContext() sharedContext: Context = {}
): Promise<TAuthProvider[]> {
return await this.authProviderService_.update(data, sharedContext)
}
createAuthUser(
create(
data: CreateAuthUserDTO[],
sharedContext?: Context
): Promise<AuthUserDTO[]>
createAuthUser(
data: CreateAuthUserDTO,
sharedContext?: Context
): Promise<AuthUserDTO>
create(data: CreateAuthUserDTO, sharedContext?: Context): Promise<AuthUserDTO>
@InjectManager("baseRepository_")
async createAuthUser(
async create(
data: CreateAuthUserDTO[] | CreateAuthUserDTO,
@MedusaContext() sharedContext: Context = {}
): Promise<AuthTypes.AuthUserDTO | AuthTypes.AuthUserDTO[]> {
const input = Array.isArray(data) ? data : [data]
const authUsers = await this.createAuthUsers_(input, sharedContext)
const authUsers = await this.authUserService_.create(data, sharedContext)
const serializedUsers = await this.baseRepository_.serialize<
AuthTypes.AuthUserDTO[]
@@ -165,28 +80,23 @@ export default class AuthModuleService<
populate: true,
})
return Array.isArray(data) ? serializedUsers : serializedUsers[0]
return serializedUsers
}
updateAuthUser(
update(
data: UpdateAuthUserDTO[],
sharedContext?: Context
): Promise<AuthUserDTO[]>
updateAuthUser(
data: UpdateAuthUserDTO,
sharedContext?: Context
): Promise<AuthUserDTO>
update(data: UpdateAuthUserDTO, sharedContext?: Context): Promise<AuthUserDTO>
// TODO: should be pluralized, see convention about the methods naming or the abstract module service interface definition @engineering
@InjectManager("baseRepository_")
async updateAuthUser(
async update(
data: UpdateAuthUserDTO | UpdateAuthUserDTO[],
@MedusaContext() sharedContext: Context = {}
): Promise<AuthTypes.AuthUserDTO | AuthTypes.AuthUserDTO[]> {
const input = Array.isArray(data) ? data : [data]
const updatedUsers = await this.updateAuthUsers_(input, sharedContext)
const updatedUsers = await this.authUserService_.update(data, sharedContext)
const serializedUsers = await this.baseRepository_.serialize<
AuthTypes.AuthUserDTO[]
@@ -197,14 +107,6 @@ export default class AuthModuleService<
return Array.isArray(data) ? serializedUsers : serializedUsers[0]
}
@InjectTransactionManager("baseRepository_")
protected async updateAuthUsers_(
data: UpdateAuthUserDTO[],
@MedusaContext() sharedContext: Context
): Promise<TAuthUser[]> {
return await this.authUserService_.update(data, sharedContext)
}
protected getRegisteredAuthenticationProvider(
provider: string,
{ authScope }: AuthenticationInput
@@ -215,13 +117,11 @@ export default class AuthModuleService<
} 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?`
`AuthenticationProvider: ${provider} wasn't registered in the module. Have you configured your options correctly?`
)
}
containerProvider.validateScope(authScope)
return containerProvider
return containerProvider.withScope(authScope)
}
async authenticate(
@@ -229,8 +129,6 @@ export default class AuthModuleService<
authenticationData: AuthenticationInput
): Promise<AuthenticationResponse> {
try {
await this.retrieveAuthProvider(provider, {})
const registeredProvider = this.getRegisteredAuthenticationProvider(
provider,
authenticationData
@@ -247,8 +145,6 @@ export default class AuthModuleService<
authenticationData: AuthenticationInput
): Promise<AuthenticationResponse> {
try {
await this.retrieveAuthProvider(provider, {})
const registeredProvider = this.getRegisteredAuthenticationProvider(
provider,
authenticationData
@@ -259,45 +155,4 @@ export default class AuthModuleService<
return { success: false, error: error.message }
}
}
@InjectTransactionManager("baseRepository_")
protected async createAuthProviders_(
data: any[],
@MedusaContext() sharedContext: Context
): Promise<TAuthProvider[]> {
return await this.authProviderService_.create(data, sharedContext)
}
@InjectTransactionManager("baseRepository_")
protected async createAuthUsers_(
data: CreateAuthUserDTO[],
@MedusaContext() sharedContext: Context
): Promise<TAuthUser[]> {
return await this.authUserService_.create(data, sharedContext)
}
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)
}
}
@@ -1,26 +0,0 @@
import { AuthProvider } from "@models"
export type CreateAuthProviderDTO = {
provider: string
name: string
domain?: ProviderDomain
is_active?: boolean
config?: Record<string, unknown>
}
export type UpdateAuthProviderDTO = {
update: {
provider: string
name?: string
domain?: ProviderDomain
is_active?: boolean
config?: Record<string, unknown>
}
provider: AuthProvider
}
export enum ProviderDomain {
ALL = "all",
STORE = "store",
ADMIN = "admin",
}
@@ -1,2 +1 @@
export * from "./auth-user"
export * from "./auth-provider"
@@ -1,24 +0,0 @@
export type AuthProviderDTO = {
provider: string
name: string
scope: string
is_active: boolean
config: Record<string, unknown>
}
export type CreateAuthProviderDTO = {
provider: string
name: string
scope?: string
is_active?: boolean
config?: Record<string, unknown>
}
export type UpdateAuthProviderDTO = {
provider: string
name?: string
is_active?: boolean
config?: Record<string, unknown>
}
export type FilterableAuthProviderProps = {}
@@ -1,11 +1,9 @@
import { AuthProviderDTO } from "./auth-provider"
export type AuthUserDTO = {
id: string
provider_id: string
entity_id: string
scope: string
provider: AuthProviderDTO
provider: string
provider_metadata?: Record<string, unknown>
user_metadata: Record<string, unknown>
app_metadata: Record<string, unknown>
@@ -1,2 +1 @@
export * from "./auth-user"
export * from "./auth-provider"