@atlasauth/cli 0.11.0 → 0.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -0
- package/dist/args.d.ts +106 -0
- package/dist/args.js +38 -0
- package/dist/args.js.map +1 -1
- package/dist/commands/init.js +13 -8
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/migrate.d.ts +6 -2
- package/dist/commands/migrate.js +13 -3
- package/dist/commands/migrate.js.map +1 -1
- package/dist/help.d.ts +1 -1
- package/dist/help.js +38 -0
- package/dist/help.js.map +1 -1
- package/dist/migrate/auth0/plugin.d.ts +2 -0
- package/dist/migrate/auth0/plugin.js +126 -0
- package/dist/migrate/auth0/plugin.js.map +1 -0
- package/dist/migrate/clerk/plugin.d.ts +2 -0
- package/dist/migrate/clerk/plugin.js +76 -0
- package/dist/migrate/clerk/plugin.js.map +1 -0
- package/dist/migrate/descope/plugin.d.ts +2 -0
- package/dist/migrate/descope/plugin.js +83 -0
- package/dist/migrate/descope/plugin.js.map +1 -0
- package/dist/migrate/export/auth0-config.d.ts +29 -0
- package/dist/migrate/export/auth0-config.js +249 -0
- package/dist/migrate/export/auth0-config.js.map +1 -0
- package/dist/migrate/export/auth0.d.ts +62 -0
- package/dist/migrate/export/auth0.js +575 -0
- package/dist/migrate/export/auth0.js.map +1 -0
- package/dist/migrate/export/clerk-config.d.ts +26 -0
- package/dist/migrate/export/clerk-config.js +227 -0
- package/dist/migrate/export/clerk-config.js.map +1 -0
- package/dist/migrate/export/clerk.d.ts +46 -0
- package/dist/migrate/export/clerk.js +486 -0
- package/dist/migrate/export/clerk.js.map +1 -0
- package/dist/migrate/export/descope.d.ts +35 -0
- package/dist/migrate/export/descope.js +208 -0
- package/dist/migrate/export/descope.js.map +1 -0
- package/dist/migrate/export/fake-vendor.test-helper.d.ts +27 -0
- package/dist/migrate/export/fake-vendor.test-helper.js +41 -0
- package/dist/migrate/export/fake-vendor.test-helper.js.map +1 -0
- package/dist/migrate/export/frameworks/app-users.d.ts +42 -0
- package/dist/migrate/export/frameworks/app-users.js +161 -0
- package/dist/migrate/export/frameworks/app-users.js.map +1 -0
- package/dist/migrate/export/frameworks/authjs.d.ts +41 -0
- package/dist/migrate/export/frameworks/authjs.js +146 -0
- package/dist/migrate/export/frameworks/authjs.js.map +1 -0
- package/dist/migrate/export/frameworks/devise.d.ts +39 -0
- package/dist/migrate/export/frameworks/devise.js +218 -0
- package/dist/migrate/export/frameworks/devise.js.map +1 -0
- package/dist/migrate/export/frameworks/django.d.ts +45 -0
- package/dist/migrate/export/frameworks/django.js +315 -0
- package/dist/migrate/export/frameworks/django.js.map +1 -0
- package/dist/migrate/export/frameworks/lucia.d.ts +42 -0
- package/dist/migrate/export/frameworks/lucia.js +263 -0
- package/dist/migrate/export/frameworks/lucia.js.map +1 -0
- package/dist/migrate/export/frameworks/tables.d.ts +90 -0
- package/dist/migrate/export/frameworks/tables.js +325 -0
- package/dist/migrate/export/frameworks/tables.js.map +1 -0
- package/dist/migrate/export/frameworks/webauthn.d.ts +25 -0
- package/dist/migrate/export/frameworks/webauthn.js +130 -0
- package/dist/migrate/export/frameworks/webauthn.js.map +1 -0
- package/dist/migrate/export/kinde-descope-config.d.ts +38 -0
- package/dist/migrate/export/kinde-descope-config.js +172 -0
- package/dist/migrate/export/kinde-descope-config.js.map +1 -0
- package/dist/migrate/export/kinde.d.ts +57 -0
- package/dist/migrate/export/kinde.js +333 -0
- package/dist/migrate/export/kinde.js.map +1 -0
- package/dist/migrate/export/okta-config.d.ts +30 -0
- package/dist/migrate/export/okta-config.js +205 -0
- package/dist/migrate/export/okta-config.js.map +1 -0
- package/dist/migrate/export/okta.d.ts +43 -0
- package/dist/migrate/export/okta.js +337 -0
- package/dist/migrate/export/okta.js.map +1 -0
- package/dist/migrate/export/plugin-kit.d.ts +25 -0
- package/dist/migrate/export/plugin-kit.js +82 -0
- package/dist/migrate/export/plugin-kit.js.map +1 -0
- package/dist/migrate/export/record-set.d.ts +44 -0
- package/dist/migrate/export/record-set.js +98 -0
- package/dist/migrate/export/record-set.js.map +1 -0
- package/dist/migrate/export/translate-kit.d.ts +46 -0
- package/dist/migrate/export/translate-kit.js +148 -0
- package/dist/migrate/export/translate-kit.js.map +1 -0
- package/dist/migrate/export/vendor-http.d.ts +46 -0
- package/dist/migrate/export/vendor-http.js +138 -0
- package/dist/migrate/export/vendor-http.js.map +1 -0
- package/dist/migrate/export/zip.d.ts +8 -0
- package/dist/migrate/export/zip.js +66 -0
- package/dist/migrate/export/zip.js.map +1 -0
- package/dist/migrate/framework/builtins.d.ts +2 -0
- package/dist/migrate/framework/builtins.js +23 -0
- package/dist/migrate/framework/builtins.js.map +1 -0
- package/dist/migrate/framework/commands.d.ts +20 -0
- package/dist/migrate/framework/commands.js +58 -0
- package/dist/migrate/framework/commands.js.map +1 -0
- package/dist/migrate/framework/custom.d.ts +12 -0
- package/dist/migrate/framework/custom.js +96 -0
- package/dist/migrate/framework/custom.js.map +1 -0
- package/dist/migrate/framework/orchestrator.d.ts +113 -0
- package/dist/migrate/framework/orchestrator.js +531 -0
- package/dist/migrate/framework/orchestrator.js.map +1 -0
- package/dist/migrate/framework/plugin.d.ts +165 -0
- package/dist/migrate/framework/plugin.js +3 -0
- package/dist/migrate/framework/plugin.js.map +1 -0
- package/dist/migrate/framework/registry.d.ts +11 -0
- package/dist/migrate/framework/registry.js +44 -0
- package/dist/migrate/framework/registry.js.map +1 -0
- package/dist/migrate/framework/report.d.ts +17 -0
- package/dist/migrate/framework/report.js +103 -0
- package/dist/migrate/framework/report.js.map +1 -0
- package/dist/migrate/frameworks/plugins.d.ts +29 -0
- package/dist/migrate/frameworks/plugins.js +402 -0
- package/dist/migrate/frameworks/plugins.js.map +1 -0
- package/dist/migrate/frameworks/report.d.ts +92 -0
- package/dist/migrate/frameworks/report.js +207 -0
- package/dist/migrate/frameworks/report.js.map +1 -0
- package/dist/migrate/frameworks/translate-js.d.ts +5 -0
- package/dist/migrate/frameworks/translate-js.js +503 -0
- package/dist/migrate/frameworks/translate-js.js.map +1 -0
- package/dist/migrate/frameworks/translate-rails-django.d.ts +3 -0
- package/dist/migrate/frameworks/translate-rails-django.js +1391 -0
- package/dist/migrate/frameworks/translate-rails-django.js.map +1 -0
- package/dist/migrate/kinde/plugin.d.ts +2 -0
- package/dist/migrate/kinde/plugin.js +105 -0
- package/dist/migrate/kinde/plugin.js.map +1 -0
- package/dist/migrate/okta/plugin.d.ts +2 -0
- package/dist/migrate/okta/plugin.js +105 -0
- package/dist/migrate/okta/plugin.js.map +1 -0
- package/package.json +5 -4
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.auth0Plugin = void 0;
|
|
4
|
+
const auth0_1 = require("../export/auth0");
|
|
5
|
+
const auth0_config_1 = require("../export/auth0-config");
|
|
6
|
+
const errors_1 = require("../../errors");
|
|
7
|
+
const plugin_kit_1 = require("../export/plugin-kit");
|
|
8
|
+
const vendor_http_1 = require("../export/vendor-http");
|
|
9
|
+
/**
|
|
10
|
+
* `atlas migrate auth0` (also Okta Customer Identity Cloud) — the tenant's
|
|
11
|
+
* settings through the Management API, users through a users-export job (or
|
|
12
|
+
* an export file), the password hashes and MFA secrets from Auth0 support's
|
|
13
|
+
* encrypted export when the owner has it, the `auth0` bridge preset (the ID
|
|
14
|
+
* token in the app session, verified against the tenant's JWKS) and lazy
|
|
15
|
+
* migration through the password-realm grant for every other password.
|
|
16
|
+
*/
|
|
17
|
+
const DOMAIN = { flag: '--auth0-domain', env: 'AUTH0_DOMAIN', label: 'your Auth0 domain (tenant.us.auth0.com)', required: true };
|
|
18
|
+
const MGMT_CLIENT_ID = { flag: '--auth0-mgmt-client-id', env: 'AUTH0_MGMT_CLIENT_ID', label: 'the client id of a machine-to-machine app authorized for the Management API', required: false };
|
|
19
|
+
const MGMT_CLIENT_SECRET = { flag: '--auth0-mgmt-client-secret', env: 'AUTH0_MGMT_CLIENT_SECRET', label: 'that app\'s client secret', required: false, secret: true };
|
|
20
|
+
const MGMT_TOKEN = { flag: '--auth0-mgmt-token', env: 'AUTH0_MGMT_TOKEN', label: 'a Management API token', required: false, secret: true };
|
|
21
|
+
const CLIENT_ID = { flag: '--auth0-client-id', env: 'AUTH0_CLIENT_ID', label: 'your application\'s client id (the ID token audience)', required: false };
|
|
22
|
+
const CLIENT_SECRET = { flag: '--auth0-client-secret', env: 'AUTH0_CLIENT_SECRET', label: 'your application\'s client secret (for a confidential application)', required: false, secret: true };
|
|
23
|
+
const CONNECTION = { flag: '--auth0-connection', env: 'AUTH0_CONNECTION', label: 'the database connection', required: false };
|
|
24
|
+
const USERS_FILE = { flag: '--auth0-users-file', env: 'AUTH0_USERS_FILE', label: 'a users export file (NDJSON or JSON)', required: false };
|
|
25
|
+
const HASHES_FILE = { flag: '--auth0-hashes-file', env: 'AUTH0_HASHES_FILE', label: 'the decrypted password-hash export from Auth0 support', required: false };
|
|
26
|
+
const RP_ID = { flag: '--rp-id', env: 'ATLAS_MIGRATE_RP_ID', label: 'the WebAuthn relying party id passkeys were registered for', required: false };
|
|
27
|
+
function domainOf(p) {
|
|
28
|
+
return (0, plugin_kit_1.hostOf)((0, plugin_kit_1.need)(p, DOMAIN));
|
|
29
|
+
}
|
|
30
|
+
/** The Management API, with a token or client credentials (asked for on this machine, sent only to Auth0). */
|
|
31
|
+
function managementHttp(p, domain) {
|
|
32
|
+
const token = p.credential(MGMT_TOKEN);
|
|
33
|
+
const clientId = p.credential(MGMT_CLIENT_ID);
|
|
34
|
+
const clientSecret = p.credential(MGMT_CLIENT_SECRET);
|
|
35
|
+
if (!token && !(clientId && clientSecret)) {
|
|
36
|
+
throw new errors_1.CliError('Auth0: pass a Management API token (--auth0-mgmt-token / AUTH0_MGMT_TOKEN), or the client id and secret of a machine-to-machine app authorized for it (AUTH0_MGMT_CLIENT_ID, AUTH0_MGMT_CLIENT_SECRET).');
|
|
37
|
+
}
|
|
38
|
+
let bearer = token;
|
|
39
|
+
return new vendor_http_1.VendorHttp({
|
|
40
|
+
vendor: 'Auth0',
|
|
41
|
+
baseUrl: `https://${domain}/api/v2`,
|
|
42
|
+
headers: async () => ({ authorization: `Bearer ${(bearer ??= await (0, auth0_1.managementToken)(domain, { domain, clientId, clientSecret }, p.fetch))}` }),
|
|
43
|
+
fetchImpl: p.fetch,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
exports.auth0Plugin = {
|
|
47
|
+
vendor: 'auth0',
|
|
48
|
+
source: 'auth0',
|
|
49
|
+
label: 'Auth0',
|
|
50
|
+
help: 'Move an Auth0 (Okta Customer Identity Cloud) tenant: its connections, MFA, password policy, applications, APIs, roles and organizations as Atlas config; its users (export job), identities, organizations, members, roles and invitations, plus password hashes and MFA secrets from the encrypted export Auth0 support provides; a zero-logout bridge; lazy migration for every password you do not have; and the code. Management credentials stay on this machine.',
|
|
51
|
+
config: {
|
|
52
|
+
reads: 'your Auth0 tenant via the Management API',
|
|
53
|
+
credentials: [DOMAIN, MGMT_TOKEN, MGMT_CLIENT_ID, MGMT_CLIENT_SECRET],
|
|
54
|
+
async translate(p) {
|
|
55
|
+
const domain = domainOf(p);
|
|
56
|
+
const snap = await (0, plugin_kit_1.vendorStep)('Auth0', () => (0, auth0_config_1.fetchAuth0Config)(managementHttp(p, domain), domain));
|
|
57
|
+
return (0, auth0_config_1.translateAuth0Config)(snap);
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
export: {
|
|
61
|
+
reads: 'the Auth0 Management API (users-export job, organizations, roles) and the support hash export (--auth0-hashes-file)',
|
|
62
|
+
credentials: [DOMAIN, MGMT_TOKEN, MGMT_CLIENT_ID, MGMT_CLIENT_SECRET, USERS_FILE, HASHES_FILE, CONNECTION],
|
|
63
|
+
limits: [
|
|
64
|
+
'Password hashes and MFA secrets never come out of the Management API: Auth0 support exports them on request (paid plans, encrypted to your PGP key). Pass the decrypted file with --auth0-hashes-file; without it, passwords move by lazy migration.',
|
|
65
|
+
'Users-export jobs are not available on the Free plan: export from the dashboard (or the User Import / Export extension) and pass the file with --auth0-users-file.',
|
|
66
|
+
'Passkey private keys never leave the authenticator; with --authentication-methods the public credentials are exported and keep working when your Atlas domain matches the relying party (--rp-id).',
|
|
67
|
+
'Sessions are not exported: the auth0 bridge preset exchanges the ID token from the app session.',
|
|
68
|
+
],
|
|
69
|
+
async run(p, writer, resume) {
|
|
70
|
+
const domain = domainOf(p);
|
|
71
|
+
const usersText = (0, plugin_kit_1.localFile)(p, USERS_FILE, 'text');
|
|
72
|
+
const token = p.credential(MGMT_TOKEN);
|
|
73
|
+
const clientId = p.credential(MGMT_CLIENT_ID);
|
|
74
|
+
const clientSecret = p.credential(MGMT_CLIENT_SECRET);
|
|
75
|
+
if (!usersText && !token && !(clientId && clientSecret)) {
|
|
76
|
+
throw new errors_1.CliError('Auth0: pass Management API credentials (AUTH0_MGMT_TOKEN, or AUTH0_MGMT_CLIENT_ID and AUTH0_MGMT_CLIENT_SECRET), or a users export file (--auth0-users-file).');
|
|
77
|
+
}
|
|
78
|
+
const set = await (0, plugin_kit_1.vendorStep)('Auth0', () => (0, auth0_1.exportAuth0)({
|
|
79
|
+
domain,
|
|
80
|
+
token,
|
|
81
|
+
clientId,
|
|
82
|
+
clientSecret,
|
|
83
|
+
usersText,
|
|
84
|
+
hashesText: (0, plugin_kit_1.localFile)(p, HASHES_FILE, 'text'),
|
|
85
|
+
connectionId: p.credential(CONNECTION),
|
|
86
|
+
authenticationMethods: (0, plugin_kit_1.flag)(p, 'authentication-methods'),
|
|
87
|
+
rpId: p.credential(RP_ID),
|
|
88
|
+
fetchImpl: p.fetch,
|
|
89
|
+
onProgress: (m) => p.say(` reading ${m}`),
|
|
90
|
+
}));
|
|
91
|
+
await (0, plugin_kit_1.writeRecordSet)(set, writer, resume, p.say);
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
bridge: {
|
|
95
|
+
preset: 'auth0',
|
|
96
|
+
vars(p, t) {
|
|
97
|
+
const vars = { ...t?.bridge?.vars };
|
|
98
|
+
const domain = p.credential({ ...DOMAIN, required: false });
|
|
99
|
+
if (domain)
|
|
100
|
+
vars.domain = (0, plugin_kit_1.hostOf)(domain);
|
|
101
|
+
const clientId = p.credential(CLIENT_ID);
|
|
102
|
+
if (clientId)
|
|
103
|
+
vars.client_id = clientId;
|
|
104
|
+
return vars;
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
lazy: {
|
|
108
|
+
preset: 'auth0',
|
|
109
|
+
config(p, t) {
|
|
110
|
+
const config = { ...t?.lazy?.config };
|
|
111
|
+
const domain = p.credential({ ...DOMAIN, required: false });
|
|
112
|
+
if (domain)
|
|
113
|
+
config.domain = (0, plugin_kit_1.hostOf)(domain);
|
|
114
|
+
const clientId = p.credential(CLIENT_ID);
|
|
115
|
+
if (clientId)
|
|
116
|
+
config.client_id = clientId;
|
|
117
|
+
const connection = p.credential(CONNECTION);
|
|
118
|
+
if (connection)
|
|
119
|
+
config.connection = connection;
|
|
120
|
+
return config;
|
|
121
|
+
},
|
|
122
|
+
secret: CLIENT_SECRET,
|
|
123
|
+
},
|
|
124
|
+
codemod: 'auth0',
|
|
125
|
+
};
|
|
126
|
+
//# sourceMappingURL=plugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../../src/migrate/auth0/plugin.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.clerkPlugin = void 0;
|
|
4
|
+
const clerk_1 = require("../export/clerk");
|
|
5
|
+
const clerk_config_1 = require("../export/clerk-config");
|
|
6
|
+
const backend_1 = require("@atlasauth/backend");
|
|
7
|
+
const errors_1 = require("../../errors");
|
|
8
|
+
const plugin_kit_1 = require("../export/plugin-kit");
|
|
9
|
+
/**
|
|
10
|
+
* `atlas migrate clerk` — Clerk's Backend API (secret key) plus the dashboard
|
|
11
|
+
* CSV export (the only source of password digests and TOTP secrets), the
|
|
12
|
+
* `clerk` JWT bridge preset (session tokens verified against the Frontend
|
|
13
|
+
* API's JWKS), lazy password verification through Clerk's verify_password
|
|
14
|
+
* for users the CSV does not cover, and the `clerk` codemod.
|
|
15
|
+
*/
|
|
16
|
+
const SECRET_KEY = { flag: '--clerk-secret-key', env: 'CLERK_SECRET_KEY', label: 'your Clerk secret key (sk_…)', required: false, secret: true };
|
|
17
|
+
const PUBLISHABLE_KEY = { flag: '--clerk-publishable-key', env: 'CLERK_PUBLISHABLE_KEY', label: 'your Clerk publishable key (pk_…)', required: false };
|
|
18
|
+
const CSV = { flag: '--clerk-csv', env: 'CLERK_CSV_EXPORT', label: 'the Clerk dashboard CSV export (Users → Export)', required: false };
|
|
19
|
+
/** The publishable key from the flag / CLERK_PUBLISHABLE_KEY, else the framework-prefixed env vars apps already have. */
|
|
20
|
+
function publishableKey(p) {
|
|
21
|
+
return (p.credential(PUBLISHABLE_KEY) ??
|
|
22
|
+
['NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY', 'VITE_CLERK_PUBLISHABLE_KEY', 'PUBLIC_CLERK_PUBLISHABLE_KEY', 'EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY'].map((k) => p.ctx.env[k]?.trim()).find(Boolean));
|
|
23
|
+
}
|
|
24
|
+
exports.clerkPlugin = {
|
|
25
|
+
vendor: 'clerk',
|
|
26
|
+
source: 'clerk',
|
|
27
|
+
label: 'Clerk',
|
|
28
|
+
help: 'Move a Clerk instance: its settings (social connections, sign-in methods, MFA, organizations, JWT templates), its users with their password digests and TOTP secrets from the dashboard CSV export, organizations, members, roles, invitations, enterprise connections and API keys from the Backend API, a zero-logout bridge for signed-in users, and the code. Your secret key stays on this machine.',
|
|
29
|
+
config: {
|
|
30
|
+
reads: 'your Clerk instance (the public environment via the publishable key, plus JWT templates, redirect URLs and roles with the secret key)',
|
|
31
|
+
credentials: [PUBLISHABLE_KEY, SECRET_KEY],
|
|
32
|
+
async translate(p) {
|
|
33
|
+
const pk = publishableKey(p);
|
|
34
|
+
if (!pk)
|
|
35
|
+
throw new errors_1.CliError('Clerk: the publishable key is needed (--clerk-publishable-key, CLERK_PUBLISHABLE_KEY or NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY).');
|
|
36
|
+
const snap = await (0, plugin_kit_1.vendorStep)('Clerk', () => (0, clerk_config_1.fetchClerkConfig)({ publishableKey: pk, secretKey: p.credential(SECRET_KEY), fetchImpl: p.fetch }));
|
|
37
|
+
return (0, clerk_config_1.translateClerkConfig)(snap);
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
export: {
|
|
41
|
+
reads: 'the Clerk Backend API (secret key) and/or the dashboard CSV export (--clerk-csv)',
|
|
42
|
+
credentials: [SECRET_KEY, CSV],
|
|
43
|
+
limits: [
|
|
44
|
+
'Password digests and TOTP secrets only come from the dashboard CSV export (Users → Export); without it, users keep their passwords through lazy migration (verify_password) instead.',
|
|
45
|
+
'Passkeys (only their names are readable) and backup codes cannot be exported: those users enrol again.',
|
|
46
|
+
'Sessions are not exported: Clerk session tokens are JWTs, exchanged by the clerk bridge preset.',
|
|
47
|
+
],
|
|
48
|
+
async run(p, writer, resume) {
|
|
49
|
+
const secretKey = p.credential(SECRET_KEY);
|
|
50
|
+
const csv = (0, plugin_kit_1.localFile)(p, CSV, 'text');
|
|
51
|
+
if (!secretKey && !csv)
|
|
52
|
+
throw new errors_1.CliError('Clerk: pass the secret key (--clerk-secret-key / CLERK_SECRET_KEY), the dashboard CSV export (--clerk-csv), or both.');
|
|
53
|
+
const set = await (0, plugin_kit_1.vendorStep)('Clerk', () => (0, clerk_1.exportClerk)({ secretKey, csv, fetchImpl: p.fetch, skipApiKeys: (0, plugin_kit_1.flag)(p, 'skip-api-keys'), onProgress: (m) => p.say(` reading ${m}`) }));
|
|
54
|
+
await (0, plugin_kit_1.writeRecordSet)(set, writer, resume, p.say);
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
bridge: {
|
|
58
|
+
preset: 'clerk',
|
|
59
|
+
vars(p, t) {
|
|
60
|
+
const pk = publishableKey(p);
|
|
61
|
+
const fromKey = pk ? (0, backend_1.clerkFrontendApiFromPublishableKey)(pk) : null;
|
|
62
|
+
const frontend_api = t?.bridge?.vars.frontend_api ?? fromKey;
|
|
63
|
+
const vars = {};
|
|
64
|
+
if (frontend_api)
|
|
65
|
+
vars.frontend_api = frontend_api;
|
|
66
|
+
return vars;
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
lazy: {
|
|
70
|
+
preset: 'clerk',
|
|
71
|
+
config: () => ({}),
|
|
72
|
+
secret: { ...SECRET_KEY, required: true },
|
|
73
|
+
},
|
|
74
|
+
codemod: 'clerk',
|
|
75
|
+
};
|
|
76
|
+
//# sourceMappingURL=plugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../../src/migrate/clerk/plugin.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.descopePlugin = void 0;
|
|
4
|
+
const descope_1 = require("../export/descope");
|
|
5
|
+
const kinde_descope_config_1 = require("../export/kinde-descope-config");
|
|
6
|
+
const plugin_kit_1 = require("../export/plugin-kit");
|
|
7
|
+
const vendor_http_1 = require("../export/vendor-http");
|
|
8
|
+
/**
|
|
9
|
+
* `atlas migrate descope` — users, tenants, roles and permissions through the
|
|
10
|
+
* Descope Management API (project id + management key, on this machine),
|
|
11
|
+
* password hashes from the export Descope support provides when the owner
|
|
12
|
+
* has it, the `descope` bridge preset (DS session JWTs verified against the
|
|
13
|
+
* project's keys) and lazy migration through Descope's password sign-in for
|
|
14
|
+
* every other password.
|
|
15
|
+
*/
|
|
16
|
+
const PROJECT_ID = { flag: '--descope-project-id', env: 'DESCOPE_PROJECT_ID', label: 'your Descope project id (P…)', required: true };
|
|
17
|
+
const MANAGEMENT_KEY = { flag: '--descope-management-key', env: 'DESCOPE_MANAGEMENT_KEY', label: 'a Descope management key', required: true, secret: true };
|
|
18
|
+
const BASE_URL = { flag: '--descope-base-url', env: 'DESCOPE_BASE_URL', label: 'the Descope API base URL (regional or custom domain)', required: false };
|
|
19
|
+
const HASHES_FILE = { flag: '--descope-hashes-file', env: 'DESCOPE_HASHES_FILE', label: 'the password-hash export from Descope support', required: false };
|
|
20
|
+
function projectId(p) {
|
|
21
|
+
return p.credential({ ...PROJECT_ID, required: false }) ?? (p.ctx.env.NEXT_PUBLIC_DESCOPE_PROJECT_ID?.trim() || (0, plugin_kit_1.need)(p, PROJECT_ID));
|
|
22
|
+
}
|
|
23
|
+
function baseUrl(p) {
|
|
24
|
+
return (p.credential(BASE_URL) ?? (p.ctx.env.NEXT_PUBLIC_DESCOPE_BASE_URL?.trim() || undefined))?.replace(/\/+$/, '');
|
|
25
|
+
}
|
|
26
|
+
exports.descopePlugin = {
|
|
27
|
+
vendor: 'descope',
|
|
28
|
+
source: 'descope',
|
|
29
|
+
label: 'Descope',
|
|
30
|
+
help: 'Move a Descope project: password policy, roles and permissions as Atlas config; users with their login ids, verified emails and phones, social and SSO links, tenants (as organizations), roles and custom attributes; password hashes from the export Descope support provides; a zero-logout bridge for DS session tokens; lazy migration for the other passwords; and the code. Your management key stays on this machine.',
|
|
31
|
+
config: {
|
|
32
|
+
reads: 'your Descope project via the Management API (password settings, roles, permissions)',
|
|
33
|
+
credentials: [PROJECT_ID, MANAGEMENT_KEY],
|
|
34
|
+
async translate(p) {
|
|
35
|
+
const pid = projectId(p);
|
|
36
|
+
const http = new vendor_http_1.VendorHttp({ vendor: 'Descope', baseUrl: baseUrl(p) ?? 'https://api.descope.com', headers: { authorization: `Bearer ${pid}:${(0, plugin_kit_1.need)(p, MANAGEMENT_KEY)}` }, fetchImpl: p.fetch });
|
|
37
|
+
const snap = await (0, plugin_kit_1.vendorStep)('Descope', () => (0, kinde_descope_config_1.fetchDescopeConfig)(http, pid));
|
|
38
|
+
return (0, kinde_descope_config_1.translateDescopeConfig)(snap);
|
|
39
|
+
},
|
|
40
|
+
},
|
|
41
|
+
export: {
|
|
42
|
+
reads: 'the Descope Management API (users, tenants, roles) and the support hash export (--descope-hashes-file)',
|
|
43
|
+
credentials: [PROJECT_ID, MANAGEMENT_KEY, HASHES_FILE],
|
|
44
|
+
limits: [
|
|
45
|
+
'Password hashes are not returned by the Management API: Descope support can export them on request. Pass that file with --descope-hashes-file; without it, passwords move by lazy migration.',
|
|
46
|
+
'TOTP seeds, passkeys and magic-link / OTP state cannot be exported: users enrol their second factor and passkeys again (email and SMS codes simply work).',
|
|
47
|
+
'Sessions are not exported: Descope session tokens are JWTs, exchanged by the descope bridge preset.',
|
|
48
|
+
],
|
|
49
|
+
async run(p, writer, resume) {
|
|
50
|
+
const set = await (0, plugin_kit_1.vendorStep)('Descope', () => (0, descope_1.exportDescope)({
|
|
51
|
+
projectId: projectId(p),
|
|
52
|
+
managementKey: (0, plugin_kit_1.need)(p, MANAGEMENT_KEY),
|
|
53
|
+
baseUrl: baseUrl(p),
|
|
54
|
+
hashesText: (0, plugin_kit_1.localFile)(p, HASHES_FILE, 'text'),
|
|
55
|
+
fetchImpl: p.fetch,
|
|
56
|
+
onProgress: (m) => p.say(` reading ${m}`),
|
|
57
|
+
}));
|
|
58
|
+
await (0, plugin_kit_1.writeRecordSet)(set, writer, resume, p.say);
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
bridge: {
|
|
62
|
+
preset: 'descope',
|
|
63
|
+
vars(p, t) {
|
|
64
|
+
const vars = { ...t?.bridge?.vars, project_id: t?.bridge?.vars.project_id ?? projectId(p) };
|
|
65
|
+
const base = baseUrl(p);
|
|
66
|
+
if (base)
|
|
67
|
+
vars.base_url = base;
|
|
68
|
+
return vars;
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
lazy: {
|
|
72
|
+
preset: 'descope',
|
|
73
|
+
config(p, t) {
|
|
74
|
+
const config = { ...t?.lazy?.config, project_id: t?.lazy?.config.project_id ?? projectId(p) };
|
|
75
|
+
const base = baseUrl(p);
|
|
76
|
+
if (base)
|
|
77
|
+
config.base_url = base;
|
|
78
|
+
return config;
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
codemod: 'descope',
|
|
82
|
+
};
|
|
83
|
+
//# sourceMappingURL=plugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../../src/migrate/descope/plugin.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { TranslationResult } from '../framework/plugin';
|
|
2
|
+
import { type Obj } from './record-set';
|
|
3
|
+
import { VendorHttp } from './vendor-http';
|
|
4
|
+
/**
|
|
5
|
+
* `atlas migrate auth0 config` — an Auth0 tenant's settings → Atlas config,
|
|
6
|
+
* read with the Management API on this machine: tenant settings (session
|
|
7
|
+
* lifetimes), database connections (password policy, username, sign-up,
|
|
8
|
+
* passkeys), passwordless and social connections, MFA factors and policy,
|
|
9
|
+
* breached-password detection, applications (callback URLs, web origins),
|
|
10
|
+
* APIs, roles and permissions. Actions, Rules, Hooks and branding are code
|
|
11
|
+
* or design: reported as manual.
|
|
12
|
+
*/
|
|
13
|
+
export interface Auth0ConfigSnapshot {
|
|
14
|
+
domain: string;
|
|
15
|
+
tenant: Obj;
|
|
16
|
+
connections: Obj[];
|
|
17
|
+
guardianFactors: Obj[];
|
|
18
|
+
guardianPolicies: string[];
|
|
19
|
+
breachedPassword: Obj | null;
|
|
20
|
+
clients: Obj[];
|
|
21
|
+
resourceServers: Obj[];
|
|
22
|
+
roles: Array<Obj & {
|
|
23
|
+
permissions?: Obj[];
|
|
24
|
+
}>;
|
|
25
|
+
actions: Obj[];
|
|
26
|
+
rules: Obj[];
|
|
27
|
+
}
|
|
28
|
+
export declare function fetchAuth0Config(http: VendorHttp, domain: string): Promise<Auth0ConfigSnapshot>;
|
|
29
|
+
export declare function translateAuth0Config(snap: Auth0ConfigSnapshot): TranslationResult;
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.fetchAuth0Config = fetchAuth0Config;
|
|
4
|
+
exports.translateAuth0Config = translateAuth0Config;
|
|
5
|
+
const record_set_1 = require("./record-set");
|
|
6
|
+
const translate_kit_1 = require("./translate-kit");
|
|
7
|
+
const vendor_http_1 = require("./vendor-http");
|
|
8
|
+
async function fetchAuth0Config(http, domain) {
|
|
9
|
+
const get = async (path, fallback) => {
|
|
10
|
+
try {
|
|
11
|
+
return (await http.get(path)).body ?? fallback;
|
|
12
|
+
}
|
|
13
|
+
catch (err) {
|
|
14
|
+
if (err instanceof vendor_http_1.VendorApiError && [403, 404].includes(err.status))
|
|
15
|
+
return fallback;
|
|
16
|
+
throw err;
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
const list = async (path, key) => {
|
|
20
|
+
const body = await get(path, []);
|
|
21
|
+
return Array.isArray(body) ? (0, record_set_1.objs)(body) : (0, record_set_1.isObj)(body) ? (0, record_set_1.objs)(body[key]) : [];
|
|
22
|
+
};
|
|
23
|
+
const roles = (await list('/roles?per_page=100', 'roles'));
|
|
24
|
+
for (const r of roles)
|
|
25
|
+
r.permissions = await list(`/roles/${(0, record_set_1.str)(r.id)}/permissions?per_page=100`, 'permissions');
|
|
26
|
+
return {
|
|
27
|
+
domain,
|
|
28
|
+
tenant: await get('/tenants/settings', {}),
|
|
29
|
+
connections: await list('/connections?per_page=100', 'connections'),
|
|
30
|
+
guardianFactors: await list('/guardian/factors', 'factors'),
|
|
31
|
+
guardianPolicies: (0, record_set_1.strs)(await get('/guardian/policies', [])),
|
|
32
|
+
breachedPassword: await get('/attack-protection/breached-password-detection', null),
|
|
33
|
+
clients: await list('/clients?per_page=100&is_global=false', 'clients'),
|
|
34
|
+
resourceServers: await list('/resource-servers?per_page=100', 'resource_servers'),
|
|
35
|
+
roles,
|
|
36
|
+
actions: await list('/actions/actions?per_page=100', 'actions'),
|
|
37
|
+
rules: await list('/rules?per_page=100', 'rules'),
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
const HOUR = 3600_000;
|
|
41
|
+
function translateAuth0Config(snap) {
|
|
42
|
+
const b = new translate_kit_1.ConfigBuilder();
|
|
43
|
+
// ── sessions ──
|
|
44
|
+
const t = snap.tenant;
|
|
45
|
+
if (typeof t.session_lifetime === 'number') {
|
|
46
|
+
const ms = (0, translate_kit_1.clampSessionMs)(t.session_lifetime * HOUR);
|
|
47
|
+
b.set('session.absoluteMs', ms);
|
|
48
|
+
b.add(ms === t.session_lifetime * HOUR ? 'mapped' : 'differs', 'tenant settings', 'session_lifetime', `${t.session_lifetime} hour(s)${ms !== t.session_lifetime * HOUR ? ' (clamped to Atlas\'s 90-day maximum)' : ''}.`, 'auth_config.session.absoluteMs');
|
|
49
|
+
}
|
|
50
|
+
if (typeof t.idle_session_lifetime === 'number') {
|
|
51
|
+
const ms = (0, translate_kit_1.clampSessionMs)(t.idle_session_lifetime * HOUR);
|
|
52
|
+
b.set('session.idleMs', ms);
|
|
53
|
+
b.add('mapped', 'tenant settings', 'idle_session_lifetime', `${t.idle_session_lifetime} hour(s) of inactivity.`, 'auth_config.session.idleMs');
|
|
54
|
+
}
|
|
55
|
+
// ── database connections ──
|
|
56
|
+
const dbs = snap.connections.filter((c) => (0, record_set_1.str)(c.strategy) === 'auth0');
|
|
57
|
+
if (dbs.length > 1)
|
|
58
|
+
b.add('differs', 'connections', 'database connections', `${dbs.length} database connections: Atlas has one user store per instance; their users are imported together (an email in two connections becomes one user).`, 'users');
|
|
59
|
+
const db = dbs.find((c) => (0, record_set_1.str)(c.name) === 'Username-Password-Authentication') ?? dbs[0];
|
|
60
|
+
b.set('strategies.password', Boolean(db));
|
|
61
|
+
if (db) {
|
|
62
|
+
const o = (0, record_set_1.isObj)(db.options) ? db.options : {};
|
|
63
|
+
const name = (0, record_set_1.str)(db.name);
|
|
64
|
+
const area = `connections ${name}`;
|
|
65
|
+
b.add('mapped', area, 'strategy auth0', 'Email + password sign-in. Imported password hashes (support export) verify as-is; lazy migration covers the rest.', 'auth_config.strategies.password');
|
|
66
|
+
const complexity = (0, record_set_1.isObj)(o.password_complexity_options) ? o.password_complexity_options : {};
|
|
67
|
+
const policyMin = { none: 1, low: 6, fair: 8, good: 8, excellent: 10 };
|
|
68
|
+
const policy = (0, record_set_1.str)(o.passwordPolicy) ?? 'good';
|
|
69
|
+
const min = typeof complexity.min_length === 'number' ? complexity.min_length : policyMin[policy] ?? 8;
|
|
70
|
+
b.set('passwordPolicy.minLength', Math.max(8, min));
|
|
71
|
+
b.add(min < 8 ? 'differs' : 'mapped', area, 'options.password_complexity_options.min_length', min < 8 ? `Auth0 allows ${min}; Atlas requires at least 8 (existing passwords still sign in).` : `${min}.`, 'auth_config.passwordPolicy.minLength');
|
|
72
|
+
if (policy === 'fair' || policy === 'good' || policy === 'excellent')
|
|
73
|
+
b.add('differs', area, `options.passwordPolicy "${policy}"`, 'Atlas follows NIST 800-63B (length and breached-password checks, no character-class rules).', 'auth_config.passwordPolicy');
|
|
74
|
+
if (o.password_history && (0, record_set_1.isObj)(o.password_history) && o.password_history.enable === true)
|
|
75
|
+
b.add('manual', area, 'options.password_history', 'Atlas does not keep a password history.');
|
|
76
|
+
if (o.password_dictionary && (0, record_set_1.isObj)(o.password_dictionary) && o.password_dictionary.enable === true)
|
|
77
|
+
b.add('differs', area, 'options.password_dictionary', 'Atlas checks breached-password corpora instead of a custom dictionary.', 'auth_config.passwordPolicy.checkBreaches');
|
|
78
|
+
if (o.requires_username === true) {
|
|
79
|
+
b.set('strategies.username', true);
|
|
80
|
+
const v = (0, record_set_1.isObj)(o.validation) && (0, record_set_1.isObj)(o.validation.username) ? o.validation.username : {};
|
|
81
|
+
if (typeof v.min === 'number')
|
|
82
|
+
b.set('accountUx.username.minLength', v.min);
|
|
83
|
+
if (typeof v.max === 'number')
|
|
84
|
+
b.set('accountUx.username.maxLength', v.max);
|
|
85
|
+
b.add('mapped', area, 'options.requires_username', 'Usernames (with the same length limits).', 'auth_config.strategies.username');
|
|
86
|
+
}
|
|
87
|
+
if (o.disable_signup === true) {
|
|
88
|
+
b.set('signUpMode', 'restricted');
|
|
89
|
+
b.add('mapped', area, 'options.disable_signup', 'Self sign-up is closed (invitations and the allowlist still work).', 'auth_config.signUpMode');
|
|
90
|
+
}
|
|
91
|
+
if (o.brute_force_protection !== false)
|
|
92
|
+
b.add('mapped', area, 'options.brute_force_protection', 'Atlas locks out repeated failed sign-ins per account and IP.', 'auth_config.rateLimit');
|
|
93
|
+
const methods = (0, record_set_1.isObj)(o.authentication_methods) ? o.authentication_methods : {};
|
|
94
|
+
if ((0, record_set_1.isObj)(methods.passkey) && methods.passkey.enabled === true) {
|
|
95
|
+
b.set('strategies.passkey', true);
|
|
96
|
+
b.add('mapped', area, 'options.authentication_methods.passkey', 'Passkeys. Existing Auth0 passkeys move with --authentication-methods when the RP id stays the same.', 'auth_config.strategies.passkey');
|
|
97
|
+
}
|
|
98
|
+
if (o.customScripts && (0, record_set_1.isObj)(o.customScripts) && o.enabledDatabaseCustomization === true) {
|
|
99
|
+
b.add('manual', area, 'options.customScripts', 'A custom database (Login / Get User scripts): point an Atlas legacy-auth connection at your user store instead (lazy migration webhook).', 'legacy_auth_connection');
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
// ── passwordless ──
|
|
103
|
+
for (const c of snap.connections) {
|
|
104
|
+
const strategy = (0, record_set_1.str)(c.strategy);
|
|
105
|
+
const o = (0, record_set_1.isObj)(c.options) ? c.options : {};
|
|
106
|
+
if (strategy === 'email') {
|
|
107
|
+
const link = (0, record_set_1.str)(o.authParams && (0, record_set_1.isObj)(o.authParams) ? o.authParams.response_type : undefined) === 'code' ? false : (0, record_set_1.str)(o.email && (0, record_set_1.isObj)(o.email) ? o.email.body : undefined)?.includes('@@link@@');
|
|
108
|
+
b.set(link ? 'strategies.emailLink' : 'strategies.emailCode', true);
|
|
109
|
+
b.add('mapped', 'connections email', 'strategy email', link ? 'Passwordless magic link.' : 'Passwordless email code.', link ? 'auth_config.strategies.emailLink' : 'auth_config.strategies.emailCode');
|
|
110
|
+
if (typeof o.totp === 'object' && (0, record_set_1.isObj)(o.totp) && typeof o.totp.time_step === 'number')
|
|
111
|
+
b.add('differs', 'connections email', 'options.totp.time_step', `Auth0 codes live ${o.totp.time_step}s; set Atlas's verification.emailCode.ttlMinutes.`, 'auth_config.verification.emailCode.ttlMinutes');
|
|
112
|
+
}
|
|
113
|
+
else if (strategy === 'sms') {
|
|
114
|
+
b.set('strategies.phoneCode', true);
|
|
115
|
+
b.add('mapped', 'connections sms', 'strategy sms', 'Passwordless SMS code (Atlas sends through its own SMS provider settings).', 'auth_config.strategies.phoneCode');
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
// ── social connections ──
|
|
119
|
+
const ENTERPRISE = new Set(['samlp', 'oidc', 'waad', 'adfs', 'okta', 'pingfederate', 'google-apps', 'ad', 'auth0-adldap', 'office365']);
|
|
120
|
+
for (const c of snap.connections) {
|
|
121
|
+
const strategy = (0, record_set_1.str)(c.strategy);
|
|
122
|
+
const name = (0, record_set_1.str)(c.name) ?? strategy ?? '';
|
|
123
|
+
if (!strategy || strategy === 'auth0' || strategy === 'email' || strategy === 'sms')
|
|
124
|
+
continue;
|
|
125
|
+
const o = (0, record_set_1.isObj)(c.options) ? c.options : {};
|
|
126
|
+
if (ENTERPRISE.has(strategy)) {
|
|
127
|
+
b.add(strategy === 'ad' || strategy === 'auth0-adldap' ? 'manual' : 'mapped', `connections ${name}`, `strategy ${strategy}`, strategy === 'ad' || strategy === 'auth0-adldap' ? 'AD/LDAP connector: no Atlas counterpart; use a lazy-migration webhook against your directory, or an enterprise IdP in front of it.' : 'Enterprise connection: moves with the data export as an Atlas SSO connection. Update the IdP with Atlas\'s ACS URL / redirect URI.', 'sso_connections');
|
|
128
|
+
continue;
|
|
129
|
+
}
|
|
130
|
+
if (strategy === 'oauth2') {
|
|
131
|
+
b.add('manual', `connections ${name}`, 'strategy oauth2', `Custom social connection "${name}": recreate it as an Atlas custom OAuth provider (authorization ${(0, record_set_1.str)(o.authorizationURL) ?? '?'}, token ${(0, record_set_1.str)(o.tokenURL) ?? '?'}); its fetchUserProfile script becomes a claim mapping.`, 'custom_oauth_providers');
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
const key = (0, translate_kit_1.socialKey)(strategy);
|
|
135
|
+
if (!key) {
|
|
136
|
+
b.add('manual', `connections ${name}`, `strategy ${strategy}`, `"${strategy}" is not a built-in Atlas provider; add it as a custom OAuth provider.`, 'custom_oauth_providers');
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
// Auth0's developer keys (no client_id) never work outside Auth0.
|
|
140
|
+
const clientId = (0, record_set_1.str)(o.client_id);
|
|
141
|
+
b.socialProvider({ atlasKey: key, vendorName: strategy, area: `connections ${name}`, setting: `strategy ${strategy}`, clientId, scopes: (0, record_set_1.strs)(o.scope ?? o.scopes) });
|
|
142
|
+
if (!clientId)
|
|
143
|
+
b.add('manual', `connections ${name}`, 'options.client_id', 'This connection uses Auth0\'s shared developer keys, which only work inside Auth0: create your own OAuth app (provider user ids change, so these users relink by email).', `oauth_providers ${key}`);
|
|
144
|
+
}
|
|
145
|
+
// ── MFA ──
|
|
146
|
+
const factors = new Map(snap.guardianFactors.map((f) => [(0, record_set_1.str)(f.name) ?? '', f.enabled === true]));
|
|
147
|
+
if (factors.get('otp')) {
|
|
148
|
+
b.set('mfa.factors.totp', true);
|
|
149
|
+
b.add('mapped', 'multi-factor', 'guardian factor otp', 'Authenticator apps. TOTP secrets move only with Auth0 support\'s secrets export.', 'auth_config.mfa.factors.totp');
|
|
150
|
+
}
|
|
151
|
+
if (factors.get('webauthn-roaming') || factors.get('webauthn-platform')) {
|
|
152
|
+
b.set('mfa.factors.passkey', true);
|
|
153
|
+
b.add('mapped', 'multi-factor', 'guardian factor webauthn', 'Security keys / device biometrics as a second factor.', 'auth_config.mfa.factors.passkey');
|
|
154
|
+
}
|
|
155
|
+
if (factors.get('email')) {
|
|
156
|
+
b.set('mfa.factors.emailCode', true);
|
|
157
|
+
b.add('mapped', 'multi-factor', 'guardian factor email', 'Email code second factor.', 'auth_config.mfa.factors.emailCode');
|
|
158
|
+
}
|
|
159
|
+
if (factors.get('sms') || factors.get('phone-message'))
|
|
160
|
+
b.add('differs', 'multi-factor', 'guardian factor sms', 'SMS second factor: phone factors move with --authentication-methods; Atlas recommends TOTP or passkeys.', 'auth_config.mfa');
|
|
161
|
+
if (factors.get('push-notification'))
|
|
162
|
+
b.add('manual', 'multi-factor', 'guardian factor push-notification', 'Auth0 Guardian push has no Atlas counterpart: those users enrol TOTP or a passkey.');
|
|
163
|
+
if (factors.get('recovery-code'))
|
|
164
|
+
b.add('mapped', 'multi-factor', 'guardian factor recovery-code', 'Backup codes (new ones are generated in Atlas).', 'auth_config.mfa.backupCodes');
|
|
165
|
+
if (snap.guardianPolicies.includes('all-applications')) {
|
|
166
|
+
b.set('mfaPolicy', 'required');
|
|
167
|
+
b.add('mapped', 'multi-factor', 'guardian policies all-applications', 'MFA always required.', 'auth_config.mfaPolicy');
|
|
168
|
+
}
|
|
169
|
+
else if (snap.guardianPolicies.includes('confidence-score')) {
|
|
170
|
+
b.add('differs', 'multi-factor', 'guardian policies confidence-score', 'Adaptive MFA: Atlas uses step-up and risk policies instead; review auth_config.stepUp.', 'auth_config.stepUp');
|
|
171
|
+
}
|
|
172
|
+
if (snap.breachedPassword) {
|
|
173
|
+
const on = snap.breachedPassword.enabled === true;
|
|
174
|
+
b.set('passwordPolicy.checkBreaches', on);
|
|
175
|
+
b.add('mapped', 'attack protection', 'breached-password-detection.enabled', on ? 'Breached passwords are refused.' : 'Breached-password check off.', 'auth_config.passwordPolicy.checkBreaches');
|
|
176
|
+
}
|
|
177
|
+
// ── applications ──
|
|
178
|
+
const origins = new Set();
|
|
179
|
+
const redirects = new Set();
|
|
180
|
+
for (const c of snap.clients) {
|
|
181
|
+
const app = (0, record_set_1.str)(c.name) ?? (0, record_set_1.str)(c.client_id) ?? 'application';
|
|
182
|
+
const type = (0, record_set_1.str)(c.app_type);
|
|
183
|
+
if (type === 'non_interactive') {
|
|
184
|
+
b.add('manual', `applications ${app}`, 'app_type non_interactive', 'A machine-to-machine application: create an Atlas M2M client (client credentials) for it.', 'oauth_clients');
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
for (const u of (0, record_set_1.strs)(c.callbacks))
|
|
188
|
+
redirects.add(u);
|
|
189
|
+
for (const u of [...(0, record_set_1.strs)(c.web_origins), ...(0, record_set_1.strs)(c.allowed_origins)])
|
|
190
|
+
origins.add(u);
|
|
191
|
+
if (c.is_first_party === false)
|
|
192
|
+
b.add('manual', `applications ${app}`, 'is_first_party false', 'A third-party application: register it as an Atlas OAuth client.', 'oauth_clients');
|
|
193
|
+
}
|
|
194
|
+
let exact = 0;
|
|
195
|
+
for (const url of redirects) {
|
|
196
|
+
if (url.includes('*')) {
|
|
197
|
+
b.add('differs', 'applications', `callbacks ${url}`, 'Atlas redirect URLs are exact (no wildcards); list each URL.', 'redirect_urls');
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
b.push('redirect_urls', { url });
|
|
201
|
+
exact++;
|
|
202
|
+
}
|
|
203
|
+
if (exact)
|
|
204
|
+
b.add('mapped', 'applications', 'callbacks', `${exact} callback URL(s) become redirect URLs.`, 'redirect_urls');
|
|
205
|
+
if (origins.size) {
|
|
206
|
+
b.instance.allowed_origins = [...origins].filter((o) => !o.includes('*'));
|
|
207
|
+
b.add('mapped', 'applications', 'web_origins / allowed_origins', 'Allowed origins for the browser SDK.', 'instance.allowed_origins');
|
|
208
|
+
}
|
|
209
|
+
// ── APIs, roles, permissions ──
|
|
210
|
+
for (const rs of snap.resourceServers) {
|
|
211
|
+
const identifier = (0, record_set_1.str)(rs.identifier);
|
|
212
|
+
if (!identifier || rs.is_system === true)
|
|
213
|
+
continue;
|
|
214
|
+
b.push('resource_servers', { identifier, name: (0, record_set_1.str)(rs.name) ?? identifier, scopes: (0, record_set_1.objs)(rs.scopes).map((s) => (0, record_set_1.str)(s.value)).filter((s) => !!s) });
|
|
215
|
+
b.add('mapped', 'APIs', `resource-servers ${identifier}`, `API with ${(0, record_set_1.objs)(rs.scopes).length} scope(s); access tokens for it keep "aud": "${identifier}".`, `resource_servers ${identifier}`);
|
|
216
|
+
}
|
|
217
|
+
const perms = new Map();
|
|
218
|
+
for (const r of snap.roles) {
|
|
219
|
+
const name = (0, record_set_1.str)(r.name);
|
|
220
|
+
if (!name)
|
|
221
|
+
continue;
|
|
222
|
+
const key = (0, translate_kit_1.keyOf)(name);
|
|
223
|
+
b.roles[name] = key;
|
|
224
|
+
const rp = (r.permissions ?? []).map((p) => (0, record_set_1.str)(p.permission_name)).filter((p) => !!p);
|
|
225
|
+
for (const p of r.permissions ?? []) {
|
|
226
|
+
const n = (0, record_set_1.str)(p.permission_name);
|
|
227
|
+
if (n)
|
|
228
|
+
perms.set(n, (0, record_set_1.str)(p.description) ?? '');
|
|
229
|
+
}
|
|
230
|
+
b.push('roles', { key, name, description: (0, record_set_1.str)(r.description) ?? '', permissions: rp });
|
|
231
|
+
}
|
|
232
|
+
for (const [key, description] of [...perms.entries()].sort())
|
|
233
|
+
b.push('permissions', { key, name: key, description });
|
|
234
|
+
if (snap.roles.length)
|
|
235
|
+
b.add('mapped', 'roles', 'roles', `${snap.roles.length} role(s) with their permissions; assignments move with the data export.`, 'roles');
|
|
236
|
+
// ── code ──
|
|
237
|
+
for (const a of snap.actions) {
|
|
238
|
+
const triggers = (0, record_set_1.objs)(a.supported_triggers).map((tr) => (0, record_set_1.str)(tr.id)).filter(Boolean).join(', ');
|
|
239
|
+
b.add('manual', 'actions', `actions ${(0, record_set_1.str)(a.name) ?? '?'}`, `Auth0 Action (${triggers || 'trigger unknown'}): port it to an Atlas action or webhook; token claims it adds become a JWT template or session claims.`, 'actions');
|
|
240
|
+
}
|
|
241
|
+
for (const r of snap.rules)
|
|
242
|
+
if (r.enabled !== false)
|
|
243
|
+
b.add('manual', 'rules', `rules ${(0, record_set_1.str)(r.name) ?? '?'}`, 'Auth0 Rule: port it to an Atlas action.', 'actions');
|
|
244
|
+
return b.result(`Auth0 tenant ${snap.domain}`, {
|
|
245
|
+
bridge: { preset: 'auth0', vars: { domain: snap.domain } },
|
|
246
|
+
lazy: db ? { preset: 'auth0', config: { domain: snap.domain, connection: (0, record_set_1.str)(db.name) ?? 'Username-Password-Authentication' } } : undefined,
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
//# sourceMappingURL=auth0-config.js.map
|