feat(authentication, types, utils): Add Authentication provider scopes (#6228)
* initial implementation * add test for invalid scope * get config from scope not db * assign config from scope * fix package.json * optional providers * make providers options * update type
This commit is contained in:
1 parent
d1c18a3090
commit
a41aad4bea
10 files changed
+148
-47
No files matched your search
@@ -78,5 +78,19 @@ describe("AuthenticationModuleService - AuthProvider", () => {
|
|||||||
"AuthenticationProvider with for provider: notRegistered wasn't registered in the module. Have you configured your options correctly?"
|
"AuthenticationProvider with for provider: notRegistered wasn't registered in the module. Have you configured your options correctly?"
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it("fails to authenticate using a valid provider with an invalid scope", async () => {
|
||||||
|
const { success, error } = await service.authenticate(
|
||||||
|
"usernamePassword",
|
||||||
|
{
|
||||||
|
scope: "non-existing",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(success).toBe(false)
|
||||||
|
expect(error).toEqual(
|
||||||
|
`Scope "non-existing" is not valid for provider usernamePassword`
|
||||||
|
)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
+4
@@ -73,6 +73,7 @@ describe("AuthenticationModuleService - AuthProvider", () => {
|
|||||||
email: "test@test.com",
|
email: "test@test.com",
|
||||||
password: password,
|
password: password,
|
||||||
},
|
},
|
||||||
|
scope: "store",
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(res).toEqual({
|
expect(res).toEqual({
|
||||||
@@ -91,6 +92,7 @@ describe("AuthenticationModuleService - AuthProvider", () => {
|
|||||||
|
|
||||||
const res = await service.authenticate("usernamePassword", {
|
const res = await service.authenticate("usernamePassword", {
|
||||||
body: { email: "test@test.com" },
|
body: { email: "test@test.com" },
|
||||||
|
scope: "store",
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(res).toEqual({
|
expect(res).toEqual({
|
||||||
@@ -104,6 +106,7 @@ describe("AuthenticationModuleService - AuthProvider", () => {
|
|||||||
|
|
||||||
const res = await service.authenticate("usernamePassword", {
|
const res = await service.authenticate("usernamePassword", {
|
||||||
body: { password: "supersecret" },
|
body: { password: "supersecret" },
|
||||||
|
scope: "store",
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(res).toEqual({
|
expect(res).toEqual({
|
||||||
@@ -136,6 +139,7 @@ describe("AuthenticationModuleService - AuthProvider", () => {
|
|||||||
email: "test@test.com",
|
email: "test@test.com",
|
||||||
password: "password",
|
password: "password",
|
||||||
},
|
},
|
||||||
|
scope: "store",
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(res).toEqual({
|
expect(res).toEqual({
|
||||||
|
|||||||
@@ -10,6 +10,15 @@ export function getInitModuleConfig() {
|
|||||||
schema: process.env.MEDUSA_AUTHENTICATION_DB_SCHEMA,
|
schema: process.env.MEDUSA_AUTHENTICATION_DB_SCHEMA,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
providers: [
|
||||||
|
{
|
||||||
|
name: "usernamePassword",
|
||||||
|
scopes: {
|
||||||
|
admin: {},
|
||||||
|
store: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
const injectedDependencies = {}
|
const injectedDependencies = {}
|
||||||
|
|||||||
@@ -1,21 +1,38 @@
|
|||||||
import * as defaultProviders from "@providers"
|
import * as defaultProviders from "@providers"
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
asClass,
|
||||||
AwilixContainer,
|
AwilixContainer,
|
||||||
ClassOrFunctionReturning,
|
ClassOrFunctionReturning,
|
||||||
Constructor,
|
Constructor,
|
||||||
Resolver,
|
Resolver,
|
||||||
asClass,
|
|
||||||
} from "awilix"
|
} from "awilix"
|
||||||
import { LoaderOptions, ModulesSdkTypes } from "@medusajs/types"
|
import {
|
||||||
|
AuthModuleProviderConfig,
|
||||||
|
AuthProviderScope,
|
||||||
|
LoaderOptions,
|
||||||
|
ModulesSdkTypes,
|
||||||
|
} from "@medusajs/types"
|
||||||
|
|
||||||
|
type AuthModuleProviders = {
|
||||||
|
providers: AuthModuleProviderConfig[]
|
||||||
|
}
|
||||||
|
|
||||||
export default async ({
|
export default async ({
|
||||||
container,
|
container,
|
||||||
|
options,
|
||||||
}: LoaderOptions<
|
}: LoaderOptions<
|
||||||
|
(
|
||||||
| ModulesSdkTypes.ModuleServiceInitializeOptions
|
| ModulesSdkTypes.ModuleServiceInitializeOptions
|
||||||
| ModulesSdkTypes.ModuleServiceInitializeCustomDataLayerOptions
|
| ModulesSdkTypes.ModuleServiceInitializeCustomDataLayerOptions
|
||||||
|
) &
|
||||||
|
AuthModuleProviders
|
||||||
>): Promise<void> => {
|
>): Promise<void> => {
|
||||||
// if(options.providers?.length) {
|
const providerMap = new Map(
|
||||||
|
options?.providers?.map((provider) => [provider.name, provider.scopes]) ??
|
||||||
|
[]
|
||||||
|
)
|
||||||
|
// if(options?.providers?.length) {
|
||||||
// TODO: implement plugin provider registration
|
// TODO: implement plugin provider registration
|
||||||
// }
|
// }
|
||||||
|
|
||||||
@@ -25,20 +42,30 @@ export default async ({
|
|||||||
container.register({
|
container.register({
|
||||||
[`auth_provider_${provider.PROVIDER}`]: asClass(
|
[`auth_provider_${provider.PROVIDER}`]: asClass(
|
||||||
provider as Constructor<any>
|
provider as Constructor<any>
|
||||||
).singleton(),
|
)
|
||||||
|
.singleton()
|
||||||
|
.inject(() => ({ scopes: providerMap.get(provider.PROVIDER) ?? {} })),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
container.register({
|
container.register({
|
||||||
[`auth_providers`]: asArray(providersToLoad),
|
[`auth_providers`]: asArray(providersToLoad, providerMap),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function asArray(
|
function asArray(
|
||||||
resolvers: (ClassOrFunctionReturning<unknown> | Resolver<unknown>)[]
|
resolvers: (ClassOrFunctionReturning<unknown> | Resolver<unknown>)[],
|
||||||
|
providerScopeMap: Map<string, Record<string, AuthProviderScope>>
|
||||||
): { resolve: (container: AwilixContainer) => unknown[] } {
|
): { resolve: (container: AwilixContainer) => unknown[] } {
|
||||||
return {
|
return {
|
||||||
resolve: (container: AwilixContainer) =>
|
resolve: (container: AwilixContainer) =>
|
||||||
resolvers.map((resolver) => container.build(resolver)),
|
resolvers.map((resolver) =>
|
||||||
|
asClass(resolver as Constructor<any>)
|
||||||
|
.inject(() => ({
|
||||||
|
// @ts-ignore
|
||||||
|
scopes: providerScopeMap.get(resolver.PROVIDER) ?? {},
|
||||||
|
}))
|
||||||
|
.resolve(container)
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4,9 +4,11 @@ import {
|
|||||||
} from "@medusajs/utils"
|
} from "@medusajs/utils"
|
||||||
import { AuthProviderService, AuthUserService } from "@services"
|
import { AuthProviderService, AuthUserService } from "@services"
|
||||||
import jwt, { JwtPayload } from "jsonwebtoken"
|
import jwt, { JwtPayload } from "jsonwebtoken"
|
||||||
|
import {
|
||||||
import { AuthProvider } from "@models"
|
AuthenticationInput,
|
||||||
import { AuthenticationResponse } from "@medusajs/types"
|
AuthenticationResponse,
|
||||||
|
AuthProviderScope,
|
||||||
|
} from "@medusajs/types"
|
||||||
import { AuthorizationCode } from "simple-oauth2"
|
import { AuthorizationCode } from "simple-oauth2"
|
||||||
import url from "url"
|
import url from "url"
|
||||||
|
|
||||||
@@ -15,14 +17,6 @@ type InjectedDependencies = {
|
|||||||
authProviderService: AuthProviderService
|
authProviderService: AuthProviderService
|
||||||
}
|
}
|
||||||
|
|
||||||
type AuthenticationInput = {
|
|
||||||
connection: { encrypted: boolean }
|
|
||||||
url: string
|
|
||||||
headers: { host: string }
|
|
||||||
query: Record<string, string>
|
|
||||||
body: Record<string, string>
|
|
||||||
}
|
|
||||||
|
|
||||||
type ProviderConfig = {
|
type ProviderConfig = {
|
||||||
clientID: string
|
clientID: string
|
||||||
clientSecret: string
|
clientSecret: string
|
||||||
@@ -37,7 +31,7 @@ class GoogleProvider extends AbstractAuthenticationModuleProvider {
|
|||||||
protected readonly authProviderService_: AuthProviderService
|
protected readonly authProviderService_: AuthProviderService
|
||||||
|
|
||||||
constructor({ authUserService, authProviderService }: InjectedDependencies) {
|
constructor({ authUserService, authProviderService }: InjectedDependencies) {
|
||||||
super()
|
super(arguments[0])
|
||||||
|
|
||||||
this.authUserSerivce_ = authUserService
|
this.authUserSerivce_ = authUserService
|
||||||
this.authProviderService_ = authProviderService
|
this.authProviderService_ = authProviderService
|
||||||
@@ -84,11 +78,11 @@ class GoogleProvider extends AbstractAuthenticationModuleProvider {
|
|||||||
|
|
||||||
const code = req.query?.code ?? req.body?.code
|
const code = req.query?.code ?? req.body?.code
|
||||||
|
|
||||||
return await this.validateCallbackToken(code, config)
|
return await this.validateCallbackToken(code, req.scope, config)
|
||||||
}
|
}
|
||||||
|
|
||||||
// abstractable
|
// abstractable
|
||||||
async verify_(refreshToken: string) {
|
async verify_(refreshToken: string, scope: string) {
|
||||||
const jwtData = (await jwt.decode(refreshToken, {
|
const jwtData = (await jwt.decode(refreshToken, {
|
||||||
complete: true,
|
complete: true,
|
||||||
})) as JwtPayload
|
})) as JwtPayload
|
||||||
@@ -108,6 +102,7 @@ class GoogleProvider extends AbstractAuthenticationModuleProvider {
|
|||||||
entity_id,
|
entity_id,
|
||||||
provider_id: GoogleProvider.PROVIDER,
|
provider_id: GoogleProvider.PROVIDER,
|
||||||
user_metadata: jwtData!.payload,
|
user_metadata: jwtData!.payload,
|
||||||
|
app_metadata: { scope },
|
||||||
},
|
},
|
||||||
])
|
])
|
||||||
} else {
|
} else {
|
||||||
@@ -121,6 +116,7 @@ class GoogleProvider extends AbstractAuthenticationModuleProvider {
|
|||||||
// abstractable
|
// abstractable
|
||||||
private async validateCallbackToken(
|
private async validateCallbackToken(
|
||||||
code: string,
|
code: string,
|
||||||
|
scope: string,
|
||||||
{ clientID, callbackURL, clientSecret }: ProviderConfig
|
{ clientID, callbackURL, clientSecret }: ProviderConfig
|
||||||
) {
|
) {
|
||||||
const client = this.getAuthorizationCodeHandler({ clientID, clientSecret })
|
const client = this.getAuthorizationCodeHandler({ clientID, clientSecret })
|
||||||
@@ -133,24 +129,34 @@ class GoogleProvider extends AbstractAuthenticationModuleProvider {
|
|||||||
try {
|
try {
|
||||||
const accessToken = await client.getToken(tokenParams)
|
const accessToken = await client.getToken(tokenParams)
|
||||||
|
|
||||||
return await this.verify_(accessToken.token.id_token)
|
return await this.verify_(accessToken.token.id_token, scope)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return { success: false, error: error.message }
|
return { success: false, error: error.message }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async validateConfig(config: Partial<ProviderConfig>) {
|
private getConfigFromScope(config: AuthProviderScope): ProviderConfig {
|
||||||
if (!config.clientID) {
|
const providerConfig: Partial<ProviderConfig> = {}
|
||||||
|
|
||||||
|
if (config.clientId) {
|
||||||
|
providerConfig.clientID = config.clientId
|
||||||
|
} else {
|
||||||
throw new Error("Google clientID is required")
|
throw new Error("Google clientID is required")
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!config.clientSecret) {
|
if (config.clientSecret) {
|
||||||
|
providerConfig.clientSecret = config.clientSecret
|
||||||
|
} else {
|
||||||
throw new Error("Google clientSecret is required")
|
throw new Error("Google clientSecret is required")
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!config.callbackURL) {
|
if (config.callbackURL) {
|
||||||
|
providerConfig.callbackURL = config.callbackUrl
|
||||||
|
} else {
|
||||||
throw new Error("Google callbackUrl is required")
|
throw new Error("Google callbackUrl is required")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return providerConfig as ProviderConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
private originalURL(req: AuthenticationInput) {
|
private originalURL(req: AuthenticationInput) {
|
||||||
@@ -165,11 +171,11 @@ class GoogleProvider extends AbstractAuthenticationModuleProvider {
|
|||||||
private async getProviderConfig(
|
private async getProviderConfig(
|
||||||
req: AuthenticationInput
|
req: AuthenticationInput
|
||||||
): Promise<ProviderConfig> {
|
): Promise<ProviderConfig> {
|
||||||
const { config } = (await this.authProviderService_.retrieve(
|
await this.authProviderService_.retrieve(GoogleProvider.PROVIDER)
|
||||||
GoogleProvider.PROVIDER
|
|
||||||
)) as AuthProvider & { config: ProviderConfig }
|
|
||||||
|
|
||||||
this.validateConfig(config || {})
|
const scopeConfig = this.scopes_[req.scope]
|
||||||
|
|
||||||
|
const config = this.getConfigFromScope(scopeConfig)
|
||||||
|
|
||||||
const { callbackURL } = config
|
const { callbackURL } = config
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { AbstractAuthenticationModuleProvider, isString } from "@medusajs/utils"
|
import { AbstractAuthenticationModuleProvider, isString } from "@medusajs/utils"
|
||||||
|
|
||||||
import { AuthUserService } from "@services"
|
import { AuthUserService } from "@services"
|
||||||
import { AuthenticationResponse } from "@medusajs/types"
|
import { AuthenticationInput, AuthenticationResponse } from "@medusajs/types"
|
||||||
import Scrypt from "scrypt-kdf"
|
import Scrypt from "scrypt-kdf"
|
||||||
|
|
||||||
class UsernamePasswordProvider extends AbstractAuthenticationModuleProvider {
|
class UsernamePasswordProvider extends AbstractAuthenticationModuleProvider {
|
||||||
@@ -10,14 +10,14 @@ class UsernamePasswordProvider extends AbstractAuthenticationModuleProvider {
|
|||||||
|
|
||||||
protected readonly authUserSerivce_: AuthUserService
|
protected readonly authUserSerivce_: AuthUserService
|
||||||
|
|
||||||
constructor({ authUserService: AuthUserService }) {
|
constructor({ authUserService }: { authUserService: AuthUserService }) {
|
||||||
super()
|
super(arguments[0])
|
||||||
|
|
||||||
this.authUserSerivce_ = AuthUserService
|
this.authUserSerivce_ = authUserService
|
||||||
}
|
}
|
||||||
|
|
||||||
async authenticate(
|
async authenticate(
|
||||||
userData: Record<string, any>
|
userData: AuthenticationInput
|
||||||
): Promise<AuthenticationResponse> {
|
): Promise<AuthenticationResponse> {
|
||||||
const { email, password } = userData.body
|
const { email, password } = userData.body
|
||||||
|
|
||||||
@@ -43,7 +43,7 @@ class UsernamePasswordProvider extends AbstractAuthenticationModuleProvider {
|
|||||||
const password_hash = authUser.provider_metadata?.password
|
const password_hash = authUser.provider_metadata?.password
|
||||||
|
|
||||||
if (isString(password_hash)) {
|
if (isString(password_hash)) {
|
||||||
const buf = Buffer.from(password_hash, "base64")
|
const buf = Buffer.from(password_hash as string, "base64")
|
||||||
|
|
||||||
const success = await Scrypt.verify(buf, password)
|
const success = await Scrypt.verify(buf, password)
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import {
|
import {
|
||||||
|
AuthenticationInput,
|
||||||
AuthenticationResponse,
|
AuthenticationResponse,
|
||||||
AuthenticationTypes,
|
AuthenticationTypes,
|
||||||
Context,
|
Context,
|
||||||
@@ -353,7 +354,8 @@ export default class AuthenticationModuleService<
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected getRegisteredAuthenticationProvider(
|
protected getRegisteredAuthenticationProvider(
|
||||||
provider: string
|
provider: string,
|
||||||
|
{ scope }: AuthenticationInput
|
||||||
): AbstractAuthenticationModuleProvider {
|
): AbstractAuthenticationModuleProvider {
|
||||||
let containerProvider: AbstractAuthenticationModuleProvider
|
let containerProvider: AbstractAuthenticationModuleProvider
|
||||||
try {
|
try {
|
||||||
@@ -365,18 +367,22 @@ export default class AuthenticationModuleService<
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
containerProvider.validateScope(scope)
|
||||||
|
|
||||||
return containerProvider
|
return containerProvider
|
||||||
}
|
}
|
||||||
|
|
||||||
async authenticate(
|
async authenticate(
|
||||||
provider: string,
|
provider: string,
|
||||||
authenticationData: Record<string, unknown>
|
authenticationData: AuthenticationInput
|
||||||
): Promise<AuthenticationResponse> {
|
): Promise<AuthenticationResponse> {
|
||||||
try {
|
try {
|
||||||
await this.retrieveAuthProvider(provider, {})
|
await this.retrieveAuthProvider(provider, {})
|
||||||
|
|
||||||
const registeredProvider =
|
const registeredProvider = this.getRegisteredAuthenticationProvider(
|
||||||
this.getRegisteredAuthenticationProvider(provider)
|
provider,
|
||||||
|
authenticationData
|
||||||
|
)
|
||||||
|
|
||||||
return await registeredProvider.authenticate(authenticationData)
|
return await registeredProvider.authenticate(authenticationData)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -386,13 +392,15 @@ export default class AuthenticationModuleService<
|
|||||||
|
|
||||||
async validateCallback(
|
async validateCallback(
|
||||||
provider: string,
|
provider: string,
|
||||||
authenticationData: Record<string, unknown>
|
authenticationData: AuthenticationInput
|
||||||
): Promise<AuthenticationResponse> {
|
): Promise<AuthenticationResponse> {
|
||||||
try {
|
try {
|
||||||
await this.retrieveAuthProvider(provider, {})
|
await this.retrieveAuthProvider(provider, {})
|
||||||
|
|
||||||
const registeredProvider =
|
const registeredProvider = this.getRegisteredAuthenticationProvider(
|
||||||
this.getRegisteredAuthenticationProvider(provider)
|
provider,
|
||||||
|
authenticationData
|
||||||
|
)
|
||||||
|
|
||||||
return await registeredProvider.validateCallback(authenticationData)
|
return await registeredProvider.validateCallback(authenticationData)
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -2,4 +2,21 @@ export type AuthenticationResponse = {
|
|||||||
success: boolean
|
success: boolean
|
||||||
authUser?: any
|
authUser?: any
|
||||||
error?: string
|
error?: string
|
||||||
|
location?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type AuthModuleProviderConfig = {
|
||||||
|
name: string
|
||||||
|
scopes: Record<string, AuthProviderScope>
|
||||||
|
}
|
||||||
|
|
||||||
|
export type AuthProviderScope = Record<string, string>
|
||||||
|
|
||||||
|
export type AuthenticationInput = {
|
||||||
|
connection: { encrypted: boolean }
|
||||||
|
url: string
|
||||||
|
headers: Record<string, string>
|
||||||
|
query: Record<string, string>
|
||||||
|
body: Record<string, string>
|
||||||
|
scope: string
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
import {
|
import {
|
||||||
|
AuthenticationInput,
|
||||||
|
AuthenticationResponse,
|
||||||
AuthProviderDTO,
|
AuthProviderDTO,
|
||||||
AuthUserDTO,
|
AuthUserDTO,
|
||||||
AuthenticationResponse,
|
|
||||||
CreateAuthProviderDTO,
|
CreateAuthProviderDTO,
|
||||||
CreateAuthUserDTO,
|
CreateAuthUserDTO,
|
||||||
FilterableAuthProviderProps,
|
FilterableAuthProviderProps,
|
||||||
@@ -17,12 +18,12 @@ import { IModuleService } from "../modules-sdk"
|
|||||||
export interface IAuthenticationModuleService extends IModuleService {
|
export interface IAuthenticationModuleService extends IModuleService {
|
||||||
authenticate(
|
authenticate(
|
||||||
provider: string,
|
provider: string,
|
||||||
providerData: Record<string, unknown>
|
providerData: AuthenticationInput
|
||||||
): Promise<AuthenticationResponse>
|
): Promise<AuthenticationResponse>
|
||||||
|
|
||||||
validateCallback(
|
validateCallback(
|
||||||
provider: string,
|
provider: string,
|
||||||
providerData: Record<string, unknown>
|
providerData: AuthenticationInput
|
||||||
): Promise<AuthenticationResponse>
|
): Promise<AuthenticationResponse>
|
||||||
|
|
||||||
retrieveAuthProvider(
|
retrieveAuthProvider(
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
import { AuthenticationResponse } from "@medusajs/types"
|
import { AuthenticationResponse, AuthProviderScope } from "@medusajs/types"
|
||||||
|
import { MedusaError } from "../common"
|
||||||
|
|
||||||
export abstract class AbstractAuthenticationModuleProvider {
|
export abstract class AbstractAuthenticationModuleProvider {
|
||||||
public static PROVIDER: string
|
public static PROVIDER: string
|
||||||
public static DISPLAY_NAME: string
|
public static DISPLAY_NAME: string
|
||||||
|
protected readonly scopes_: Record<string, AuthProviderScope>
|
||||||
|
|
||||||
public get provider() {
|
public get provider() {
|
||||||
return (this.constructor as Function & { PROVIDER: string }).PROVIDER
|
return (this.constructor as Function & { PROVIDER: string }).PROVIDER
|
||||||
@@ -13,6 +15,19 @@ export abstract class AbstractAuthenticationModuleProvider {
|
|||||||
.DISPLAY_NAME
|
.DISPLAY_NAME
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected constructor({ scopes }) {
|
||||||
|
this.scopes_ = scopes
|
||||||
|
}
|
||||||
|
|
||||||
|
public validateScope(scope) {
|
||||||
|
if (!this.scopes_[scope]) {
|
||||||
|
throw new MedusaError(
|
||||||
|
MedusaError.Types.INVALID_ARGUMENT,
|
||||||
|
`Scope "${scope}" is not valid for provider ${this.provider}`
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
abstract authenticate(
|
abstract authenticate(
|
||||||
data: Record<string, unknown>
|
data: Record<string, unknown>
|
||||||
): Promise<AuthenticationResponse>
|
): Promise<AuthenticationResponse>
|
||||||
|
|||||||
Reference in new issue
Block a user