Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Features: #123 Array like options #124

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions packages/medusa-plugin-auth/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@
"@medusajs/medusa": ">=1.17.x",
"@types/express": "^4.17.17",
"@types/jest": "^29.1.2",
"@types/passport-auth0": "^1.0.9",
"@types/passport-azure-ad": "^4.3.5",
"@types/passport-facebook": "^3.0.3",
"@types/passport-google-oauth2": "^0.1.8",
"@types/passport-linkedin-oauth2": "^1.5.6",
"@types/passport-oauth2": "^1.4.15",
"jest": "^29.1.2",
"passport": "^0.6.0",
Expand Down
42 changes: 31 additions & 11 deletions packages/medusa-plugin-auth/src/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,43 @@ import FirebaseStrategy from '../auth-strategies/firebase';
import Auth0Strategy from '../auth-strategies/auth0';
import AzureStrategy from '../auth-strategies/azure-oidc';

import { AuthOptions } from '../types';
import { AuthOptions, AuthOptionsWrapper, handleOption } from '../types';

export default function (rootDirectory, pluginOptions: AuthOptions): Router[] {
const configModule = loadConfig(rootDirectory) as ConfigModule;
export default async function (rootDirectory, pluginOptions: AuthOptions[]): Promise<Router[]> {
const configModule = loadConfig(rootDirectory);
return loadRouters(configModule, pluginOptions);
}

function loadRouters(configModule: ConfigModule, options: AuthOptions): Router[] {
async function loadRouters(configModule: ConfigModule, options: AuthOptionsWrapper[]): Promise<Router[]> {
const routers: Router[] = [];

routers.push(...OAuth2Strategy.getRouter(configModule, options));
routers.push(...GoogleStrategy.getRouter(configModule, options));
routers.push(...FacebookStrategy.getRouter(configModule, options));
routers.push(...LinkedinStrategy.getRouter(configModule, options));
routers.push(...FirebaseStrategy.getRouter(configModule, options));
routers.push(...Auth0Strategy.getRouter(configModule, options));
routers.push(...AzureStrategy.getRouter(configModule, options));
for (const opt of options) {
const option = await handleOption(opt, configModule);

switch (option.type) {
case 'azure_oidc':
stephane-segning marked this conversation as resolved.
Show resolved Hide resolved
routers.push(...AzureStrategy.getRouter(configModule, option));
break;
case 'google':
routers.push(...GoogleStrategy.getRouter(configModule, option));
break;
case 'facebook':
routers.push(...FacebookStrategy.getRouter(configModule, option));
break;
case 'linkedin':
routers.push(...LinkedinStrategy.getRouter(configModule, option));
break;
case 'firebase':
routers.push(...FirebaseStrategy.getRouter(configModule, option));
break;
case 'auth0':
routers.push(...Auth0Strategy.getRouter(configModule, option));
break;
case 'oauth2':
routers.push(...OAuth2Strategy.getRouter(configModule, option));
break;
}
}

return routers;
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { ConfigModule, MedusaContainer } from '@medusajs/medusa/dist/types/global';
import { Auth0AdminStrategy } from '../../admin';
import { AUTH_PROVIDER_KEY } from '../../../../types';
import { Auth0Options, AUTH0_ADMIN_STRATEGY_NAME, Profile, ExtraParams } from '../../types';
import { AUTH_PROVIDER_KEY, IStrategy } from '../../../../types';
import { AUTH0_ADMIN_STRATEGY_NAME, Auth0Options, ExtraParams } from '../../types';
import { Profile } from 'passport-auth0';
import { getAuth0AdminStrategy } from '../../admin';

describe('Auth0 admin strategy verify callback', function () {
const existsEmail = 'exists@test.fr';
Expand All @@ -12,9 +13,9 @@ describe('Auth0 admin strategy verify callback', function () {
let req: Request;
let accessToken: string;
let refreshToken: string;
let profile: Profile;
let profile: Partial<Profile>;
let extraParams: ExtraParams;
let auth0AdminStrategy: Auth0AdminStrategy;
let auth0AdminStrategy: IStrategy;

beforeEach(() => {
profile = {
Expand All @@ -38,7 +39,7 @@ describe('Auth0 admin strategy verify callback', function () {
return {
id: 'test2',
metadata: {
[AUTH_PROVIDER_KEY]: AUTH0_ADMIN_STRATEGY_NAME,
[AUTH_PROVIDER_KEY]: AUTH0_ADMIN_STRATEGY_NAME + '_test',
},
};
}
Expand All @@ -64,6 +65,7 @@ describe('Auth0 admin strategy verify callback', function () {

describe('when strict is set to admin', function () {
beforeEach(() => {
const Auth0AdminStrategy = getAuth0AdminStrategy('test');
auth0AdminStrategy = new Auth0AdminStrategy(
container,
{} as ConfigModule,
Expand Down Expand Up @@ -130,6 +132,7 @@ describe('Auth0 admin strategy verify callback', function () {

describe('when strict is set for store only', function () {
beforeEach(() => {
const Auth0AdminStrategy = getAuth0AdminStrategy('test');
auth0AdminStrategy = new Auth0AdminStrategy(
container,
{} as ConfigModule,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { Auth0StoreStrategy } from '../../store';
import { ConfigModule, MedusaContainer } from '@medusajs/medusa/dist/types/global';
import { AUTH_PROVIDER_KEY, CUSTOMER_METADATA_KEY } from '../../../../types';
import { Auth0Options, AUTH0_STORE_STRATEGY_NAME, Profile, ExtraParams } from '../../types';
import { AUTH_PROVIDER_KEY, CUSTOMER_METADATA_KEY, IStrategy } from '../../../../types';
import { AUTH0_STORE_STRATEGY_NAME, Auth0Options, ExtraParams } from '../../types';
import { Profile } from 'passport-auth0';
import { getAuth0StoreStrategy } from '../../store';

describe('Auth0 store strategy verify callback', function () {
const existsEmail = 'exists@test.fr';
Expand All @@ -13,9 +14,9 @@ describe('Auth0 store strategy verify callback', function () {
let req: Request;
let accessToken: string;
let refreshToken: string;
let profile: Profile;
let profile: Partial<Profile>;
let extraParams: ExtraParams;
let auth0StoreStrategy: Auth0StoreStrategy;
let auth0StoreStrategy: IStrategy;
let updateFn;
let createFn;

Expand Down Expand Up @@ -67,7 +68,7 @@ describe('Auth0 store strategy verify callback', function () {
id: 'test3',
metadata: {
[CUSTOMER_METADATA_KEY]: true,
[AUTH_PROVIDER_KEY]: AUTH0_STORE_STRATEGY_NAME,
[AUTH_PROVIDER_KEY]: AUTH0_STORE_STRATEGY_NAME + '_test',
},
};
}
Expand All @@ -94,6 +95,7 @@ describe('Auth0 store strategy verify callback', function () {

describe('when strict is set to store', function () {
beforeEach(() => {
const Auth0StoreStrategy = getAuth0StoreStrategy('test');
auth0StoreStrategy = new Auth0StoreStrategy(
container,
{} as ConfigModule,
Expand Down Expand Up @@ -183,6 +185,7 @@ describe('Auth0 store strategy verify callback', function () {

describe('when strict is set to admin', function () {
beforeEach(() => {
const Auth0StoreStrategy = getAuth0StoreStrategy('test');
auth0StoreStrategy = new Auth0StoreStrategy(
container,
{} as ConfigModule,
Expand Down
102 changes: 54 additions & 48 deletions packages/medusa-plugin-auth/src/auth-strategies/auth0/admin.ts
Original file line number Diff line number Diff line change
@@ -1,77 +1,83 @@
import { Strategy as Auth0Strategy } from 'passport-auth0';
import { Profile, Strategy as Auth0Strategy, StrategyOptionWithRequest } from 'passport-auth0';
import { ConfigModule, MedusaContainer } from '@medusajs/medusa/dist/types/global';
import { Router } from 'express';
import { AUTH0_ADMIN_STRATEGY_NAME, Auth0Options, Profile, ExtraParams } from './types';
import { AUTH0_ADMIN_STRATEGY_NAME, Auth0Options, ExtraParams } from './types';
import { PassportStrategy } from '../../core/passport/Strategy';
import { validateAdminCallback } from '../../core/validate-callback';
import { passportAuthRoutesBuilder } from '../../core/passport/utils/auth-routes-builder';
import { AuthOptions } from '../../types';
import { AuthProvider, StrategyFactory } from '../../types';

export class Auth0AdminStrategy extends PassportStrategy(Auth0Strategy, AUTH0_ADMIN_STRATEGY_NAME) {
constructor(
protected readonly container: MedusaContainer,
protected readonly configModule: ConfigModule,
protected readonly strategyOptions: Auth0Options,
protected readonly strict?: AuthOptions['strict']
) {
super({
domain: strategyOptions.auth0Domain,
clientID: strategyOptions.clientID,
clientSecret: strategyOptions.clientSecret,
callbackURL: strategyOptions.admin.callbackUrl,
passReqToCallback: true,
state: true,
});
}
export function getAuth0AdminStrategy(id: string): StrategyFactory<Auth0Options> {
const strategyName = `${AUTH0_ADMIN_STRATEGY_NAME}_${id}`;
return class extends PassportStrategy(Auth0Strategy, strategyName) {
constructor(
protected readonly container: MedusaContainer,
protected readonly configModule: ConfigModule,
protected readonly strategyOptions: Auth0Options,
protected readonly strict?: AuthProvider['strict']
) {
super({
domain: strategyOptions.auth0Domain,
clientID: strategyOptions.clientID,
clientSecret: strategyOptions.clientSecret,
callbackURL: strategyOptions.admin.callbackUrl,
passReqToCallback: true,
state: true,
} as StrategyOptionWithRequest);
}

async validate(
req: Request,
accessToken: string,
refreshToken: string,
extraParams: ExtraParams,
profile: Profile
): Promise<null | { id: string; accessToken: string }> {
if (this.strategyOptions.admin.verifyCallback) {
const validateRes = await this.strategyOptions.admin.verifyCallback(
this.container,
req,
accessToken,
refreshToken,
extraParams,
profile,
this.strict
);
async validate(
req: Request,
accessToken: string,
refreshToken: string,
extraParams: ExtraParams,
profile: Profile
): Promise<null | { id: string; accessToken: string }> {
if (this.strategyOptions.admin.verifyCallback) {
const validateRes = await this.strategyOptions.admin.verifyCallback(
this.container,
req,
accessToken,
refreshToken,
extraParams,
profile,
this.strict
);

return {
...validateRes,
accessToken,
};
}
const validateRes = await validateAdminCallback(profile, {
container: this.container,
strategyErrorIdentifier: 'auth0',
strict: this.strict,
strategyName,
});
return {
...validateRes,
accessToken,
};
}
const validateRes = await validateAdminCallback(profile, {
container: this.container,
strategyErrorIdentifier: 'auth0',
strict: this.strict,
});
return {
...validateRes,
accessToken,
};
}
};
}

/**
* Return the router that holds the auth0 admin authentication routes
* @param id
* @param auth0
* @param configModule
*/
export function getAuth0AdminAuthRouter(auth0: Auth0Options, configModule: ConfigModule): Router {
export function getAuth0AdminAuthRouter(id: string, auth0: Auth0Options, configModule: ConfigModule): Router {
const strategyName = `${AUTH0_ADMIN_STRATEGY_NAME}_${id}`;
return passportAuthRoutesBuilder({
domain: 'admin',
configModule,
authPath: auth0.admin.authPath ?? '/admin/auth/auth0',
authCallbackPath: auth0.admin.authCallbackPath ?? '/admin/auth/auth0/cb',
successRedirect: auth0.admin.successRedirect,
strategyName: AUTH0_ADMIN_STRATEGY_NAME,
strategyName,
passportAuthenticateMiddlewareOptions: {
scope: 'openid email profile',
},
Expand Down
34 changes: 19 additions & 15 deletions packages/medusa-plugin-auth/src/auth-strategies/auth0/index.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,38 @@
import { ConfigModule, MedusaContainer } from '@medusajs/medusa/dist/types/global';
import { AuthOptions, StrategyExport } from '../../types';
import { StrategyExport } from '../../types';
import { Router } from 'express';
import { getAuth0AdminAuthRouter, Auth0AdminStrategy } from './admin';
import { getAuth0StoreAuthRouter, Auth0StoreStrategy } from './store';
import { getAuth0AdminAuthRouter, getAuth0AdminStrategy } from './admin';
import { getAuth0StoreAuthRouter, getAuth0StoreStrategy } from './store';
import { Auth0Options } from './types';

export * from './admin';
export * from './store';
export * from './types';

export default {
load: (container: MedusaContainer, configModule: ConfigModule, options: AuthOptions): void => {
if (options.auth0?.admin) {
new Auth0AdminStrategy(container, configModule, options.auth0, options.strict);
load: (container, configModule, option): void => {
const id = option.identifier ?? option.type;
if (option.admin) {
const Clazz = getAuth0AdminStrategy(id);
new Clazz(container, configModule, option, option.strict);
}

if (options.auth0?.store) {
new Auth0StoreStrategy(container, configModule, options.auth0, options.strict);
if (option.store) {
const Clazz = getAuth0StoreStrategy(id);
new Clazz(container, configModule, option, option.strict);
}
},
getRouter: (configModule: ConfigModule, options: AuthOptions): Router[] => {
getRouter: (configModule, option): Router[] => {
const routers = [];
const id = option.identifier ?? option.type;

if (options.auth0?.admin) {
routers.push(getAuth0AdminAuthRouter(options.auth0, configModule));
if (option.admin) {
routers.push(getAuth0AdminAuthRouter(id, option, configModule));
}

if (options.auth0?.store) {
routers.push(getAuth0StoreAuthRouter(options.auth0, configModule));
if (option.store) {
routers.push(getAuth0StoreAuthRouter(id, option, configModule));
}

return routers;
},
} as StrategyExport;
} as StrategyExport<Auth0Options>;
Loading
Loading