Maintenance Mode

Maintenance mode temporarily restricts who can authenticate through a client, without touching the client’s configuration. It exists for the window where an application is mid-migration and should not be letting users in, but you do not want to disable the client and then try to remember exactly how it was set up.

Two things make it different from disabling a client:

  • It is reversible by one switch, and it changes nothing else. Redirect URIs, scopes, secrets all stay as they are.
  • It has a hole in it, on purpose. A whitelist of users and roles keeps authenticating, so your own team can verify the migration on the real client before reopening it.

Closing a client

FerrisKey client maintenance tab showing the maintenance switch, reason, session strategy and allowed users FerrisKey client maintenance tab showing the maintenance switch, reason, session strategy and allowed users
PUT /realms/{realm_name}/clients/{client_id}/maintenance
{
  "enabled": true,
  "reason": "Migration under way, back at 2pm.",
  "session_strategy": "expire"
}
FieldDefaultDescription
enabledrequiredtrue closes the client to everyone but the whitelist
reasonnoneMessage displayed to blocked users on the login page
session_strategyexpireWhat happens to sessions that are already open

The switch applies as soon as you flip it. There is no drain period.

Session strategy

ValueBehaviour
expireOpen sessions live until they run out. The default
terminateEvery session is cut on the spot

expire is the polite option and the right default: people already working keep working, and nobody new gets in. Reach for terminate when the reason for closing the client is that the sessions themselves are the problem — a leaked token, a compromised integration — and letting them run to expiry is the thing you are trying to prevent.

Write the reason as the user will read it

reason is shown on the login page, to someone who was trying to get on with their day. “Migration under way, back at 2pm” answers their actual question. “MAINT-4417” does not.

The whitelist

Whitelist entries name a user or a role. Everyone named, and every holder of a named role, authenticates normally while the client is in maintenance.

Entries exist at two levels, and they add up: a client’s effective whitelist is its own entries plus the realm’s.

Per client

GET    /realms/{realm_name}/clients/{client_id}/maintenance/whitelist
POST   /realms/{realm_name}/clients/{client_id}/maintenance/whitelist
DELETE /realms/{realm_name}/clients/{client_id}/maintenance/whitelist/{entry_id}

Per realm

Realm-level entries are inherited by every client of the realm placed under maintenance — the standing list of people who should never be locked out.

FerrisKey realm settings maintenance tab showing default maintenance members for users and roles FerrisKey realm settings maintenance tab showing default maintenance members for users and roles
GET    /realms/{realm_name}/settings/maintenance/whitelist
POST   /realms/{realm_name}/settings/maintenance/whitelist
DELETE /realms/{realm_name}/settings/maintenance/whitelist/{entry_id}
{
  "role_id": "01a0d3dd-a750-7817-aa2b-7e8b98f68e66"
}

Both user_id and role_id are optional in the payload; supply the one that describes the entry you want.

Put the role on the realm whitelist before you need it

A role-based realm entry — your platform team’s role, say — is the difference between a planned maintenance window and an incident. Adding a whitelist entry requires authenticating to the admin console, and if the console’s own client is the one you just closed, you have locked yourself out of the tool you need to unlock it.

Permissions

ActionPermission
Read a whitelistview_clients, or manage_clients
Toggle maintenance, add or remove entriesmanage_clients

manage_realm also grants all of them.

What gets recorded

Both transitions are observable, which matters because maintenance mode is a thing that gets left on by accident:

  • SeaWatch records client_maintenance_enabled and client_maintenance_disabled.
  • Webhooks fire client.maintenance.enabled and client.maintenance.disabled.

A webhook on the enabled trigger that opens a reminder, and one on disabled that closes it, is the cheapest way to stop a Friday-afternoon window from lasting until Monday.