Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
9f6141b
feat: riskAssessments integration
josh-cain Nov 24, 2025
2bf229d
feedback: nest new device settings under riskAssessment
josh-cain Dec 4, 2025
659aed8
Merge branch 'master' into addRiskAssessmentConfig
josh-cain Dec 4, 2025
9f11f9d
Merge branch 'master' into addRiskAssessmentConfig
josh-cain Dec 5, 2025
a3145bc
feedbadck: null check for status code
josh-cain Dec 5, 2025
8b30faf
feedback: remove useless catch
josh-cain Dec 5, 2025
98b09de
remove additional references to previous/legacy format
josh-cain Dec 5, 2025
c83d43f
null checkery
josh-cain Dec 5, 2025
318b968
shorthand
josh-cain Dec 5, 2025
6818cb8
feedback: singular-ize riskAssessments
josh-cain Dec 8, 2025
3e38f5c
Update docs/resource-specific-documentation.md
josh-cain Dec 12, 2025
c73ad14
Update src/tools/constants.ts
josh-cain Dec 12, 2025
6c9931a
feedback: more renaming
josh-cain Dec 12, 2025
b64421f
fix: tests should reflect singular naming too
josh-cain Dec 12, 2025
11b651b
Merge branch 'master' into addRiskAssessmentConfig
kushalshit27 Dec 14, 2025
863a41e
Merge branch 'master' into addRiskAssessmentConfig
kushalshit27 Dec 20, 2025
cf25eea
feat: update risk assessment schema structure
kushalshit27 Dec 20, 2025
3c7b539
feat: update risk assessment structure and tests
kushalshit27 Dec 20, 2025
63a5f2d
feat: update risk assessment configuration and examples
kushalshit27 Dec 20, 2025
bb528f1
update e2e
kushalshit27 Dec 21, 2025
168018a
feat: update risk assessment types and remove settings.json
kushalshit27 Dec 21, 2025
592fc28
update e2e
kushalshit27 Dec 21, 2025
fcf3bbb
update e2e
kushalshit27 Dec 21, 2025
9b5f240
E2E add cross_origin_authentication to client configurations test-data
kushalshit27 Dec 21, 2025
53ce517
E2E updated
kushalshit27 Dec 21, 2025
9206aa6
E2E:enable cross_origin_authentication for Deploy CLI client on test-…
kushalshit27 Dec 21, 2025
c499cb0
e2e update
kushalshit27 Dec 22, 2025
4422674
e2e update
kushalshit27 Dec 22, 2025
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
37 changes: 37 additions & 0 deletions docs/resource-specific-documentation.md
Original file line number Diff line number Diff line change
Expand Up @@ -707,3 +707,40 @@ clients:
```

For more details, see the [Management API documentation](https://auth0.com/docs/api/management/v2).

## Risk Assessments

Risk assessments configuration allows you to enable or disable risk assessment features for your tenant.

- `settings.enabled`: toggles the feature true/flase (required)
- `new_device.remember_for` (optional): days to remember devices

### YAML Example

```yaml
# Contents of ./tenant.yaml
riskAssessment:
settings:
enabled: true
new_device:
remember_for: 30
```

### Directory Example

Folder: `./risk-assessment/`

File: `./risk-assessment/settings.json`

```json
{
"settings": {
"enabled": true
},
"new_device": {
"remember_for": 30
}
}
```

For more details, see the [Management API documentation](https://auth0.com/docs/api/management/v2#!/Risk_Assessments/get_settings).
5 changes: 5 additions & 0 deletions examples/directory/risk-assessment/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"settings": {
"enabled": false
}
}
6 changes: 6 additions & 0 deletions examples/yaml/tenant.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -451,3 +451,9 @@ userAttributeProfiles:
type: "email"
required: true

riskAssessment:
settings:
enabled: false
# new_device:
# remember_for: 30

2 changes: 2 additions & 0 deletions src/context/directory/handlers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import actions from './actions';
import organizations from './organizations';
import triggers from './triggers';
import attackProtection from './attackProtection';
import riskAssessment from './riskAssessment';
import branding from './branding';
import phoneProviders from './phoneProvider';
import phoneTemplates from './phoneTemplates';
Expand Down Expand Up @@ -71,6 +72,7 @@ const directoryHandlers: {
organizations,
triggers,
attackProtection,
riskAssessment,
branding,
phoneProviders,
phoneTemplates,
Expand Down
51 changes: 51 additions & 0 deletions src/context/directory/handlers/riskAssessment.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import path from 'path';
import fs from 'fs-extra';
import { constants } from '../../../tools';
import { dumpJSON, existsMustBeDir, isFile, loadJSON } from '../../../utils';
import { DirectoryHandler } from '.';
import DirectoryContext from '..';
import { ParsedAsset } from '../../../types';
import { RiskAssessment } from '../../../tools/auth0/handlers/riskAssessment';

type ParsedRiskAssessment = ParsedAsset<'riskAssessment', RiskAssessment>;

function parse(context: DirectoryContext): ParsedRiskAssessment {
const riskAssessmentDirectory = path.join(context.filePath, constants.RISK_ASSESSMENT_DIRECTORY);
const riskAssessmentFile = path.join(riskAssessmentDirectory, 'settings.json');

if (!existsMustBeDir(riskAssessmentDirectory)) {
return { riskAssessment: null };
}

if (!isFile(riskAssessmentFile)) {
return { riskAssessment: null };
}

const riskAssessment = loadJSON(riskAssessmentFile, {
mappings: context.mappings,
disableKeywordReplacement: context.disableKeywordReplacement,
});

return {
riskAssessment,
};
}

async function dump(context: DirectoryContext): Promise<void> {
const { riskAssessment } = context.assets;

if (!riskAssessment) return;

const riskAssessmentDirectory = path.join(context.filePath, constants.RISK_ASSESSMENT_DIRECTORY);
const riskAssessmentFile = path.join(riskAssessmentDirectory, 'settings.json');

fs.ensureDirSync(riskAssessmentDirectory);
dumpJSON(riskAssessmentFile, riskAssessment);
}

const riskAssessmentHandler: DirectoryHandler<ParsedRiskAssessment> = {
parse,
dump,
};

export default riskAssessmentHandler;
2 changes: 2 additions & 0 deletions src/context/yaml/handlers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import organizations from './organizations';
import actions from './actions';
import triggers from './triggers';
import attackProtection from './attackProtection';
import riskAssessment from './riskAssessment';
import branding from './branding';
import phoneProviders from './phoneProvider';
import phoneTemplates from './phoneTemplates';
Expand Down Expand Up @@ -69,6 +70,7 @@ const yamlHandlers: { [key in AssetTypes]: YAMLHandler<{ [key: string]: unknown
organizations,
triggers,
attackProtection,
riskAssessment,
branding,
phoneProviders,
phoneTemplates,
Expand Down
33 changes: 33 additions & 0 deletions src/context/yaml/handlers/riskAssessment.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { YAMLHandler } from '.';
import YAMLContext from '..';
import { RiskAssessment } from '../../../tools/auth0/handlers/riskAssessment';
import { ParsedAsset } from '../../../types';

type ParsedRiskAssessment = ParsedAsset<'riskAssessment', RiskAssessment>;

async function parse(context: YAMLContext): Promise<ParsedRiskAssessment> {
const { riskAssessment } = context.assets;

if (!riskAssessment) return { riskAssessment: null };

return {
riskAssessment,
};
}

async function dump(context: YAMLContext): Promise<ParsedRiskAssessment> {
const { riskAssessment } = context.assets;

if (!riskAssessment) return { riskAssessment: null };

return {
riskAssessment,
};
}

const riskAssessmentHandler: YAMLHandler<ParsedRiskAssessment> = {
parse,
dump,
};

export default riskAssessmentHandler;
2 changes: 2 additions & 0 deletions src/tools/auth0/handlers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import * as actions from './actions';
import * as triggers from './triggers';
import * as organizations from './organizations';
import * as attackProtection from './attackProtection';
import * as riskAssessment from './riskAssessment';
import * as logStreams from './logStreams';
import * as customDomains from './customDomains';
import * as themes from './themes';
Expand Down Expand Up @@ -69,6 +70,7 @@ const auth0ApiHandlers: { [key in AssetTypes]: any } = {
triggers,
organizations,
attackProtection,
riskAssessment,
logStreams,
customDomains,
themes,
Expand Down
109 changes: 109 additions & 0 deletions src/tools/auth0/handlers/riskAssessment.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
import DefaultAPIHandler from './default';
import { Assets } from '../../../types';
import { Management, ManagementError } from 'auth0';

export const schema = {
type: 'object',
properties: {
settings: {
type: 'object',
properties: {
enabled: {
type: 'boolean',
description: 'Whether or not risk assessment is enabled.',
},
},
required: ['enabled'],
},
new_device: {
type: 'object',
properties: {
remember_for: {
type: 'number',
description: 'Length of time to remember devices for, in days.',
},
},
required: ['remember_for'],
},
},
required: ['settings'],
};

export type RiskAssessment = {
settings: Management.GetRiskAssessmentsSettingsResponseContent;
new_device?: Management.GetRiskAssessmentsSettingsNewDeviceResponseContent;
};

export default class RiskAssessmentHandler extends DefaultAPIHandler {
existing: RiskAssessment;

constructor(config: DefaultAPIHandler) {
super({
...config,
type: 'riskAssessment',
});
}

async getType(): Promise<RiskAssessment> {
if (this.existing) {
return this.existing;
}

try {
const [settings, newDeviceSettings] = await Promise.all([
this.client.riskAssessments.settings.get(),
this.client.riskAssessments.settings.newDevice.get().catch((err) => {
if (err instanceof ManagementError && err?.statusCode === 404) {
return { remember_for: 0 };
}
throw err;
}),
]);

const riskAssessment: RiskAssessment = {
settings: settings,
new_device: newDeviceSettings,
...(newDeviceSettings.remember_for > 0 && {
new_device: newDeviceSettings,
}),
};

this.existing = riskAssessment;
return this.existing;
} catch (err) {
if (err instanceof ManagementError && err.statusCode === 404) {
const riskAssessment: RiskAssessment = {
settings: { enabled: false },
};
this.existing = riskAssessment;
return this.existing;
}
throw err;
}
}

async processChanges(assets: Assets): Promise<void> {
const { riskAssessment } = assets;

// Non-existing section means it doesn't need to be processed
if (!riskAssessment) {
return;
}

const updates: Promise<unknown>[] = [];

// Update main settings (enabled flag)
updates.push(this.client.riskAssessments.settings.update(riskAssessment?.settings));

// Update new device settings if provided
if (riskAssessment.new_device) {
updates.push(
this.client.riskAssessments.settings.newDevice.update(riskAssessment.new_device)
);
}

await Promise.all(updates);
this.updated += 1;
this.didUpdate(riskAssessment);
}
}
1 change: 1 addition & 0 deletions src/tools/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ const constants = {
CONNECTIONS_ID_NAME: 'id',
ROLES_DIRECTORY: 'roles',
ATTACK_PROTECTION_DIRECTORY: 'attack-protection',
RISK_ASSESSMENT_DIRECTORY: 'risk-assessment',
GUARDIAN_FACTORS: [
'sms',
'push-notification',
Expand Down
3 changes: 3 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { NetworkACL } from './tools/auth0/handlers/networkACLs';
import { UserAttributeProfile } from './tools/auth0/handlers/userAttributeProfiles';
import { AttackProtection } from './tools/auth0/handlers/attackProtection';
import { TokenExchangeProfile } from './tools/auth0/handlers/tokenExchangeProfiles';
import { RiskAssessment } from './tools/auth0/handlers/riskAssessment';

type SharedPaginationParams = {
checkpoint?: boolean;
Expand Down Expand Up @@ -97,6 +98,7 @@ export type Asset = { [key: string]: any };
export type Assets = Partial<{
actions: Action[] | null;
attackProtection: AttackProtection | null;
riskAssessment: RiskAssessment | null;
branding:
| (Asset & {
templates?: { template: string; body: string }[] | null;
Expand Down Expand Up @@ -180,6 +182,7 @@ export type AssetTypes =
| 'organizations'
| 'triggers'
| 'attackProtection'
| 'riskAssessment'
| 'branding'
| 'phoneProviders'
| 'phoneTemplates'
Expand Down
Loading