feat(auth): Revamp authentication setup (#7387)

* chore: Clean up authentication middlewares

* chore: Rename AuthUser to AuthIdentity

* feat: Define link between user, customer, and auth identity

* feat: Use links for auth, update auth context content

* fix: Adjust user create command with new auth setup

* fix: Make auth login more dynamic, review fixes

* fix: Change test assertions for created by
This commit is contained in:
Stevche Radevski
2024-05-22 10:27:32 +02:00
committed by GitHub
parent b7df447682
commit 5ede560f70
88 changed files with 887 additions and 1014 deletions
@@ -5,24 +5,26 @@ import {
isString,
} from "@medusajs/utils"
import { AuthUserService } from "@services"
import { AuthIdentityService } from "@services"
import Scrypt from "scrypt-kdf"
const EXPIRATION = "1d"
class EmailPasswordProvider extends AbstractAuthModuleProvider {
public static PROVIDER = "emailpass"
public static DISPLAY_NAME = "Email/Password Authentication"
protected readonly authUserSerivce_: AuthUserService
protected readonly authIdentitySerivce_: AuthIdentityService
constructor({ authUserService }: { authUserService: AuthUserService }) {
constructor({
authIdentityService,
}: {
authIdentityService: AuthIdentityService
}) {
super(arguments[0], {
provider: EmailPasswordProvider.PROVIDER,
displayName: EmailPasswordProvider.DISPLAY_NAME,
})
this.authUserSerivce_ = authUserService
this.authIdentitySerivce_ = authIdentityService
}
private getHashConfig() {
@@ -54,18 +56,19 @@ class EmailPasswordProvider extends AbstractAuthModuleProvider {
error: "Email should be a string",
}
}
let authUser
let authIdentity
try {
authUser = await this.authUserSerivce_.retrieveByProviderAndEntityId(
email,
EmailPasswordProvider.PROVIDER
)
authIdentity =
await this.authIdentitySerivce_.retrieveByProviderAndEntityId(
email,
EmailPasswordProvider.PROVIDER
)
} catch (error) {
if (error.type === MedusaError.Types.NOT_FOUND) {
const password_hash = await Scrypt.kdf(password, this.getHashConfig())
const [createdAuthUser] = await this.authUserSerivce_.create([
const [createdAuthIdentity] = await this.authIdentitySerivce_.create([
{
entity_id: email,
provider: EmailPasswordProvider.PROVIDER,
@@ -78,13 +81,13 @@ class EmailPasswordProvider extends AbstractAuthModuleProvider {
return {
success: true,
authUser: JSON.parse(JSON.stringify(createdAuthUser)),
authIdentity: JSON.parse(JSON.stringify(createdAuthIdentity)),
}
}
return { success: false, error: error.message }
}
const password_hash = authUser.provider_metadata?.password
const password_hash = authIdentity.provider_metadata?.password
if (isString(password_hash)) {
const buf = Buffer.from(password_hash as string, "base64")
@@ -92,9 +95,12 @@ class EmailPasswordProvider extends AbstractAuthModuleProvider {
const success = await Scrypt.verify(buf, password)
if (success) {
delete authUser.provider_metadata!.password
delete authIdentity.provider_metadata!.password
return { success, authUser: JSON.parse(JSON.stringify(authUser)) }
return {
success,
authIdentity: JSON.parse(JSON.stringify(authIdentity)),
}
}
}
+16 -15
View File
@@ -1,13 +1,13 @@
import { AuthenticationInput, AuthenticationResponse } from "@medusajs/types"
import { AbstractAuthModuleProvider, MedusaError } from "@medusajs/utils"
import { AuthUserService } from "@services"
import { AuthIdentityService } from "@services"
import jwt, { JwtPayload } from "jsonwebtoken"
import { AuthorizationCode } from "simple-oauth2"
import url from "url"
type InjectedDependencies = {
authUserService: AuthUserService
authIdentityService: AuthIdentityService
}
type ProviderConfig = {
@@ -21,15 +21,15 @@ class GoogleProvider extends AbstractAuthModuleProvider {
public static PROVIDER = "google"
public static DISPLAY_NAME = "Google Authentication"
protected readonly authUserService_: AuthUserService
protected readonly authIdentityService_: AuthIdentityService
constructor({ authUserService }: InjectedDependencies) {
constructor({ authIdentityService }: InjectedDependencies) {
super(arguments[0], {
provider: GoogleProvider.PROVIDER,
displayName: GoogleProvider.DISPLAY_NAME,
})
this.authUserService_ = authUserService
this.authIdentityService_ = authIdentityService
}
async authenticate(
@@ -83,16 +83,17 @@ class GoogleProvider extends AbstractAuthModuleProvider {
}) as JwtPayload
const entity_id = jwtData.payload.email
let authUser
let authIdentity
try {
authUser = await this.authUserService_.retrieveByProviderAndEntityId(
entity_id,
GoogleProvider.PROVIDER
)
authIdentity =
await this.authIdentityService_.retrieveByProviderAndEntityId(
entity_id,
GoogleProvider.PROVIDER
)
} catch (error) {
if (error.type === MedusaError.Types.NOT_FOUND) {
const [createdAuthUser] = await this.authUserService_.create([
const [createdAuthIdentity] = await this.authIdentityService_.create([
{
entity_id,
provider: GoogleProvider.PROVIDER,
@@ -100,7 +101,7 @@ class GoogleProvider extends AbstractAuthModuleProvider {
scope: this.scope_,
},
])
authUser = createdAuthUser
authIdentity = createdAuthIdentity
} else {
return { success: false, error: error.message }
}
@@ -108,7 +109,7 @@ class GoogleProvider extends AbstractAuthModuleProvider {
return {
success: true,
authUser,
authIdentity,
}
}
@@ -127,7 +128,7 @@ class GoogleProvider extends AbstractAuthModuleProvider {
try {
const accessToken = await client.getToken(tokenParams)
const { authUser, success } = await this.verify_(
const { authIdentity, success } = await this.verify_(
accessToken.token.id_token
)
@@ -135,7 +136,7 @@ class GoogleProvider extends AbstractAuthModuleProvider {
return {
success,
authUser,
authIdentity,
successRedirectUrl,
}
} catch (error) {