Skip to content

Policies ​

A password policy describes what a valid password looks like, and how lockout behaves after failed sign-ins. Each policy can be attached to Gatelin roles (roleIds). A user is governed by the policies attached to all of their roles, combined into the strictest rules; users with no role attached to a policy fall back to the first non-archived pwd_policy row (lowest id), which also drives server-side generation when you create a pwd row. The result applies to the passwords users choose in the recovery and expired-password workflows, to the password checklist shown on those pages, and to lockout and expiry.

Keeping these rules in the database rather than in code means you can tighten requirements without redeploying, but see How It Works for what takes effect immediately versus what needs a restart.

How It Works ​

There is no active flag. The migration seeds three policies (Public User, High Security, Standard), attached to the Gatelin roles guest, super admin/admin and user. Roles that no policy lists, and users unknown to the user service, get the first non-archived row by id.

A user's roles come from the user service (USER_SEARCH_URL, roles field). Gatelin grants the union of a user's roles and does not rank them, so Foxnox does not pick one: it merges the policies attached to the user's roles into the strictest rules.

RuleMerged value
lengththe longest
number, symbol, lowerCase, upperCase, strictrequired if any policy requires it
expiryDaysthe shortest, ignoring 0 (never expires) unless every policy has 0
maxFailedAttemptsthe lowest
lockoutMinutesthe longest

Roles are picked in the admin Policies page from the list returned by the Gatelin roles search route (ADMIN_ROLES_SEARCH_URL).

Character-class and expiry rules for user-chosen passwords are read at the moment a password is rotated, not at boot. Generated passwords (POST /foxnox/pwd) follow the policy that was loaded during initPwdGeneration at process start — restart Foxnox after changing generation rules.

expiryDays is used to compute the pwdExpiry stamped on a pwd row when the password is set. Set it to 0 to disable expiry entirely.

maxFailedAttempts and lockoutMinutes are applied on each failed POST /foxnox/pwd/compare. Defaults when a policy omits them (or no policy exists) are 5 attempts and 15 minutes.

Passken generates passwords between 12 and 64 characters. A policy length below 12 is still enforced when users choose a password, but generated passwords are clamped up to 12.

The custom symbols pool is used when validating user-chosen passwords. The generator draws from Passken's built-in symbol list and does not take that pool as an argument.

Search Policies ​

POST /foxnox/policies/search
Content-Type: application/json
Authorization: Bearer <access_token>

{
  "filters": {
    "archived": { "value": false, "matchMode": "=" }
  }
}

Response (200 OK):

json
{
  "rows": [
    {
      "id": 1,
      "name": "Public User",
      "description": "Default password policy for regular users",
      "length": 10,
      "number": true,
      "symbol": true,
      "lowerCase": true,
      "upperCase": true,
      "strict": true,
      "symbols": "!@#%*_-+=:?><./()",
      "expiryDays": 0,
      "maxFailedAttempts": 5,
      "lockoutMinutes": 15,
      "archived": false
    }
  ]
}

Get Policy History ​

GET /foxnox/policies/:id/history
Authorization: Bearer <access_token>

Create Policies ​

POST /foxnox/policies/
Content-Type: application/json
Authorization: Bearer <access_token>

{
  "rows": [
    {
      "name": "strict-2026",
      "description": "Tightened requirements",
      "length": 16,
      "number": true,
      "symbol": true,
      "lowerCase": true,
      "upperCase": true,
      "strict": true,
      "symbols": "!@#$%^&*()-_=+",
      "expiryDays": 60,
      "maxFailedAttempts": 5,
      "lockoutMinutes": 15
    }
  ]
}

Policy fields ​

FieldRangeDescription
name1–50 charsPolicy identifier
description0–100 charsHuman-readable note
length6–64Minimum password length
numberbooleanRequire at least one digit
symbolbooleanRequire at least one symbol
lowerCasebooleanRequire at least one lower-case letter
upperCasebooleanRequire at least one upper-case letter
strictbooleanWhen true, every enabled character class must be present. When false, the classes act as a pool to draw from rather than a checklist.
symbols0–50 charsThe set of symbols considered valid for user-chosen passwords
expiryDays≥ 0Days until a new password expires; 0 disables expiry
maxFailedAttempts≥ 1Failed POST /foxnox/pwd/compare attempts before lockedUntil is set
lockoutMinutes≥ 0How long that lock lasts
roleIdsarray of integersGatelin role ids this policy applies to (empty = none). Roles are not validated against Gatelin

At least one of number, symbol, lowerCase, or upperCase must be true (enforced by a database check).

A newly inserted row only becomes the default policy (used for generation and for users without a mapped role) if every lower-id policy is archived, because that lookup is "first non-archived by id".

Update Policies ​

PUT /foxnox/policies/
Content-Type: application/json
Authorization: Bearer <access_token>

{
  "rows": [
    {
      "id": 1,
      "name": "Public User",
      "length": 16,
      "number": true,
      "symbol": true,
      "lowerCase": true,
      "upperCase": true,
      "strict": true,
      "symbols": "!@#$%^&*()-_=+",
      "expiryDays": 60,
      "maxFailedAttempts": 5,
      "lockoutMinutes": 15
    }
  ]
}

Response (200 OK): the updated rows.

Most fields are required on PUT — send the whole policy rather than a partial patch.

Archive Policies ​

POST /foxnox/policies/archive
Content-Type: application/json
Authorization: Bearer <access_token>

{
  "rows": [
    { "id": 2 }
  ]
}

Response (204 No Content). Do not archive every policy — password generation and validation need one non-archived row to read. Archiving the lowest-id row is how you switch to the next remaining policy.

Get Entity Schema ​

GET /foxnox/policies/schema
Authorization: Bearer <access_token>

Published and maintained by ALTEN