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

Upgrading node-auth0 from v3 to v4 #887

Draft
wants to merge 9 commits into
base: master
Choose a base branch
from
Draft
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
1,142 changes: 116 additions & 1,026 deletions package-lock.json

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
"homepage": "https://github.com/auth0/auth0-deploy-cli#readme",
"dependencies": {
"ajv": "^6.12.6",
"auth0": "^3.0.0",
"dot-prop": "^5.2.0",
"fs-extra": "^10.1.0",
"global-agent": "^2.1.12",
Expand All @@ -52,6 +51,7 @@
"@types/mocha": "^10.0.0",
"@types/nconf": "^0.10.3",
"@typescript-eslint/parser": "^5.30.3",
"auth0": "^4.0.0-beta.9",
"chai": "^4.3.7",
"chai-as-promised": "^7.1.1",
"eslint": "^7.28.0",
Expand All @@ -62,6 +62,7 @@
"kacl": "^1.1.1",
"mocha": "^10.1.0",
"nock": "^13.2.9",
"node-fetch": "^2.7.0",
"nyc": "^15.0.1",
"prettier": "^2.6.2",
"pretty-quick": "^3.1.3",
Expand Down
9 changes: 5 additions & 4 deletions src/context/directory/handlers/clientGrants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,14 @@ async function dump(context: DirectoryContext): Promise<void> {

if (clientGrants.length === 0) return;

const allResourceServers = await context.mgmtClient.resourceServers.getAll({
paginate: true,
// TODO: Bring back paginate: true
const { data: { resource_servers: allResourceServers } } = await context.mgmtClient.resourceServers.getAll({
Copy link
Contributor Author

@willvedd willvedd Feb 7, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this is important to include. Before Node v4, Auth0 Node SDK didn't natively support pagination and I don't believe that v4 added it either but this needs to be confirmed. The getAll function is mutated by the Deploy CLI to support the paginate property.

Update: Yes, we need to bring this back and account for the pagination monkey-patch. Perhaps we should extract as a function instead?

include_totals: true,
});

const allClients = await context.mgmtClient.clients.getAll({
paginate: true,
// TODO: Bring back paginate: true
// @ts-ignore-error TODO: add pagination overload to client.getAll
const { data: { clients: allClients } } = await context.mgmtClient.clients.getAll({
include_totals: true,
});

Expand Down
2 changes: 0 additions & 2 deletions src/context/directory/handlers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import guardianPhoneFactorMessageTypes from './guardianPhoneFactorMessageTypes';
import guardianPhoneFactorSelectedProvider from './guardianPhoneFactorSelectedProvider';
import guardianPolicies from './guardianPolicies';
import roles from './roles';
import migrations from './migrations';
import actions from './actions';
import organizations from './organizations';
import triggers from './triggers';
Expand Down Expand Up @@ -54,7 +53,6 @@ const directoryHandlers: {
guardianFactors,
guardianFactorProviders,
guardianFactorTemplates,
migrations,
guardianPhoneFactorMessageTypes,
guardianPhoneFactorSelectedProvider,
guardianPolicies,
Expand Down
40 changes: 0 additions & 40 deletions src/context/directory/handlers/migrations.ts

This file was deleted.

2 changes: 1 addition & 1 deletion src/context/directory/handlers/resourceServers.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { ResourceServer } from 'auth0';
import path from 'path';
import fs from 'fs-extra';
import { constants } from '../../../tools';
import { getFiles, existsMustBeDir, dumpJSON, loadJSON, sanitize } from '../../../utils';
import { DirectoryHandler } from '.';
import DirectoryContext from '..';
import { ParsedAsset } from '../../../types';
import { ResourceServer } from '../../../tools/auth0/handlers/resourceServers';

type ParsedResourceServers = ParsedAsset<'resourceServers', ResourceServer[]>;

Expand Down
4 changes: 2 additions & 2 deletions src/context/directory/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import cleanAssets from '../../readonly';
import log from '../../logger';
import handlers, { DirectoryHandler } from './handlers';
import { isDirectory, isFile, stripIdentifiers, toConfigFn } from '../../utils';
import { Assets, Auth0APIClient, Config, AssetTypes } from '../../types';
import { Assets, Auth0APIClient, Config, AssetTypes, BaseAuth0APIClient } from '../../types';
import { filterOnlyIncludedResourceTypes } from '..';
import { preserveKeywords } from '../../keywordPreservation';

Expand All @@ -21,7 +21,7 @@ export default class DirectoryContext {
assets: Assets;
disableKeywordReplacement: boolean;

constructor(config: Config, mgmtClient: Auth0APIClient) {
constructor(config: Config, mgmtClient: BaseAuth0APIClient) {
this.filePath = config.AUTH0_INPUT_FILE;
this.config = config;
this.mappings = config.AUTH0_KEYWORD_REPLACE_MAPPINGS || {};
Expand Down
6 changes: 3 additions & 3 deletions src/context/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,19 +161,19 @@ export const setupContext = async (
return new AuthenticationClient({
domain: AUTH0_DOMAIN,
clientId: AUTH0_CLIENT_ID,
clientAssertionSigningKey: readFileSync(AUTH0_CLIENT_SIGNING_KEY_PATH),
clientAssertionSigningKey: readFileSync(AUTH0_CLIENT_SIGNING_KEY_PATH, 'utf8'),
clientAssertionSigningAlg: !!AUTH0_CLIENT_SIGNING_ALGORITHM
? AUTH0_CLIENT_SIGNING_ALGORITHM
: undefined,
});
})();

const clientCredentials = await authClient.clientCredentialsGrant({
const clientCredentials = await authClient.oauth.clientCredentialsGrant({
audience: config.AUTH0_AUDIENCE
? config.AUTH0_AUDIENCE
: `https://${config.AUTH0_DOMAIN}/api/v2/`,
});
return clientCredentials.access_token;
return clientCredentials.data?.access_token;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should introduce some checks to prevent an undefined access_token from being persisted through the rest of the process.

})();

const mgmtClient = new ManagementClient({
Expand Down
4 changes: 2 additions & 2 deletions src/context/yaml/handlers/guardianPolicies.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { YAMLHandler } from '.';
import YAMLContext from '..';
import { Asset, ParsedAsset } from '../../../types';
import { ParsedAsset } from '../../../types';

type ParsedGuardianPolicies = ParsedAsset<'guardianPolicies', { policies: Asset[] }>;
type ParsedGuardianPolicies = ParsedAsset<'guardianPolicies', { policies: string[] }>;

async function parseAndDump(context: YAMLContext): Promise<ParsedGuardianPolicies> {
const { guardianPolicies } = context.assets;
Expand Down
2 changes: 0 additions & 2 deletions src/context/yaml/handlers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ import guardianPhoneFactorSelectedProvider from './guardianPhoneFactorSelectedPr
import guardianPolicies from './guardianPolicies';
import roles from './roles';
import organizations from './organizations';
import migrations from './migrations';
import actions from './actions';
import triggers from './triggers';
import attackProtection from './attackProtection';
Expand Down Expand Up @@ -53,7 +52,6 @@ const yamlHandlers: { [key in AssetTypes]: YAMLHandler<{ [key: string]: unknown
guardianFactorProviders,
guardianFactorTemplates,
roles,
migrations,
guardianPhoneFactorMessageTypes,
guardianPhoneFactorSelectedProvider,
guardianPolicies,
Expand Down
20 changes: 0 additions & 20 deletions src/context/yaml/handlers/migrations.ts

This file was deleted.

2 changes: 1 addition & 1 deletion src/context/yaml/handlers/resourceServers.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ResourceServer } from 'auth0';
import { YAMLHandler } from '.';
import YAMLContext from '..';
import { ParsedAsset } from '../../../types';
import { ResourceServer } from '../../../tools/auth0/handlers/resourceServers';

type ParsedResourceServers = ParsedAsset<'resourceServers', ResourceServer[]>;

Expand Down
2 changes: 1 addition & 1 deletion src/tools/auth0/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ export default function pagedClient(client: BaseAuth0APIClient): Auth0APIClient
frequencyLimit: API_FREQUENCY_PER_SECOND,
frequencyWindow: 1000, // 1 sec
}),
};
} as unknown as Auth0APIClient;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks very weird. Can the unknown be removed or this type cast otherwise cleaned up?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Update: Looking at this with Frederik again, we should probably find a way to exclude the pool property or facilitate pagination some other way that can retain the Auth0APIClient type.


return pagedManager(clientWithPooling, clientWithPooling);
}
24 changes: 16 additions & 8 deletions src/tools/auth0/handlers/actions.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import _ from 'lodash';
import { GetActions200ResponseActionsInner, PostActionRequest } from 'auth0';
import DefaultAPIHandler, { order } from './default';
import log from '../../../logger';
import { areArraysEquals, sleep } from '../../utils';
Expand Down Expand Up @@ -92,29 +93,34 @@ export function isMarketplaceAction(action: Action): boolean {
}

export default class ActionHandler extends DefaultAPIHandler {
existing: Action[] | null;
existing: GetActions200ResponseActionsInner[] | null;

constructor(options: DefaultAPIHandler) {
super({
...options,
type: 'actions',
functions: {
create: (action: Action) => this.createAction(action),
create: (action: PostActionRequest) => this.createAction(action),
delete: (action: Action) => this.deleteAction(action),
},
stripUpdateFields: ['deployed', 'status'],
});
}

async createAction(action: Action) {
async createAction(action: PostActionRequest) {
// Strip the deployed flag
const addAction = { ...action };
delete addAction.deployed;
delete addAction.status;
const createdAction = await this.client.actions.create(addAction);

// TODO: Should we keep this?
delete (addAction as any).deployed;
delete (addAction as any).status;
Comment on lines +114 to +116
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes because when you create an action you cannot specify the deploy or status in the payload. However, this should be accomplished with the stripCreateFields: ['deployed', 'status'], in the handler definition above.


const { data: createdAction } = await this.client.actions.create(addAction);
// Add the action id so we can deploy it later
action.id = createdAction.id;

// TODO: Should we keep this?
(action as any).id = createdAction.id;
Comment on lines +121 to +122
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably keep this so we can have reference of the ID. Should double check through testing though.


return createdAction;
}

Expand Down Expand Up @@ -202,7 +208,9 @@ export default class ActionHandler extends DefaultAPIHandler {
// Actions API does not support include_totals param like the other paginate API's.
// So we set it to false otherwise it will fail with "Additional properties not allowed: include_totals"
try {
const actions = await this.client.actions.getAll({ paginate: true });
// TODO: bring back paginate: true
const { data } = await this.client.actions.getAll();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const { data } = await this.client.actions.getAll();
const { data: {actions} } = await this.client.actions.getAll();

const { actions } = data;
this.existing = actions;
return actions;
} catch (err) {
Expand Down
6 changes: 3 additions & 3 deletions src/tools/auth0/handlers/attackProtection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,9 @@ export default class AttackProtectionHandler extends DefaultAPIHandler {
]);

this.existing = {
breachedPasswordDetection,
bruteForceProtection,
suspiciousIpThrottling,
breachedPasswordDetection: breachedPasswordDetection.data,
bruteForceProtection: bruteForceProtection.data,
suspiciousIpThrottling: suspiciousIpThrottling.data,
};

return this.existing;
Expand Down
20 changes: 8 additions & 12 deletions src/tools/auth0/handlers/branding.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { GetBranding200Response, GetUniversalLogin200ResponseOneOf } from 'auth0';
import DefaultHandler, { order } from './default';
import constants from '../../constants';
import log from '../../../logger';
Expand Down Expand Up @@ -30,29 +31,25 @@ export default class BrandingHandler extends DefaultHandler {
}

async getType(): Promise<Asset> {
let branding: {
templates?: {
template: string;
body: string;
}[];
} = {};
let branding: GetBranding200Response = {} as any;

try {
// in case client version does not support branding
if (this.client.branding && typeof this.client.branding.getSettings === 'function') {
branding = await this.client.branding.getSettings();
const response = await this.client.branding.getSettings();
branding = response.data;
}

// in case client version does not custom domains
if (this.client.customDomains && typeof this.client.customDomains.getAll === 'function') {
const customDomains = await this.client.customDomains.getAll();
const { data: customDomains } = await this.client.customDomains.getAll();
// templates are only supported if there's custom domains.
if (customDomains && customDomains.length) {
const payload = await this.client.branding.getUniversalLoginTemplate();
const { data: payload } = await this.client.branding.getUniversalLoginTemplate();
branding.templates = [
{
template: constants.UNIVERSAL_LOGIN_TEMPLATE,
body: payload.body,
body: (payload as GetUniversalLogin200ResponseOneOf).body,
},
];
}
Expand Down Expand Up @@ -80,7 +77,7 @@ export default class BrandingHandler extends DefaultHandler {
}

if (brandingSettings && Object.keys(brandingSettings).length) {
await this.client.branding.updateSettings({}, brandingSettings);
await this.client.branding.updateSettings(brandingSettings);
this.updated += 1;
this.didUpdate(brandingSettings);
}
Expand All @@ -104,7 +101,6 @@ export default class BrandingHandler extends DefaultHandler {
);
if (templateDefinition && templateDefinition.body) {
await this.client.branding.setUniversalLoginTemplate(
{},
{ template: templateDefinition.body }
);
this.updated += 1;
Expand Down
11 changes: 8 additions & 3 deletions src/tools/auth0/handlers/clientGrants.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import DefaultHandler, { order } from './default';
import { convertClientNamesToIds } from '../../utils';
import { Asset, Assets, CalculatedChanges } from '../../../types';
import { Assets, CalculatedChanges } from '../../../types';
import DefaultAPIHandler from './default';

export const schema = {
Expand Down Expand Up @@ -48,7 +48,9 @@ export default class ClientGrantsHandler extends DefaultHandler {
if (this.existing) {
return this.existing;
}
this.existing = await this.client.clientGrants.getAll({ paginate: true, include_totals: true });
// TODO: Bring back paginate: true
const { data } = await this.client.clientGrants.getAll({ include_totals: true });
this.existing = data.client_grants;

// Always filter out the client we are using to access Auth0 Management API
// As it could cause problems if the grants are deleted or updated etc
Expand All @@ -67,7 +69,10 @@ export default class ClientGrantsHandler extends DefaultHandler {
// Do nothing if not set
if (!clientGrants) return;

const clients = await this.client.clients.getAll({ paginate: true, include_totals: true });
// TODO: Bring back paginate: true
const { data } = await this.client.clients.getAll({ include_totals: true });
// @ts-ignore-error TODO: add pagination overload to client.getAll
const { clients } = data;
const excludedClientsByNames = (assets.exclude && assets.exclude.clients) || [];
const excludedClients = convertClientNamesToIds(excludedClientsByNames, clients);

Expand Down
6 changes: 4 additions & 2 deletions src/tools/auth0/handlers/clients.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,11 +82,13 @@ export default class ClientHandler extends DefaultAPIHandler {

async getType() {
if (this.existing) return this.existing;
this.existing = await this.client.clients.getAll({
paginate: true,
// TODO: Bring back paginate: true
const { data } = await this.client.clients.getAll({
include_totals: true,
is_global: false,
});
// @ts-ignore-error TODO: add pagination overload to client.getAll
this.existing = data.clients;
return this.existing;
}
}
Loading
Loading