Browse
On this page

Manage sign-in security, API keys and webhooks from one settings page

Active sessions, per-role session limits, timeouts, blocked IPs and users, geographic access, API keys and webhooks, all live on Settings > Security > Access & Sessions.

You need An account with view access to Settings - saving the top card or the Sessions cards needs the tenant's own owner email or an internal Super Admin.

What you will have

  • See who is signed in right now and force one of them out.
  • Set how many sessions each role can hold at once, and how long an idle session lasts before it expires.
  • Read the sign-in safeguards at the top of the page: two-factor enforcement and the shared failed-login and lockout numbers.
  • Block a suspect IP address, and see how that differs from the two lists on the Geographic Access card.
  • Turn on Geographic Access to restrict logins by country, and see how an IP entry can bypass it.
  • Read the Recent Admin Connections list and know exactly where its rows come from.
  • Issue an API key and a webhook, and see exactly what each one shows you once.

Why it works this way

Every field on this page's top card and its Sessions cards is Owner-tier, not the ordinary Settings edit permission - only the tenant's own owner email, or an internal Super Admin, can save changes there, even though an ordinary Admin can still view the page.

Two separate IP lists live on this one page and do different jobs: the Access Control Blocked IPs list denies matching addresses outright, and the Geographic Access IP Allowlist bypasses the country check. An address added to one is not automatically in the other - add it wherever you need that specific effect. The older mid-session 'IP changed, re-authenticate' safeguard and its CSV whitelist were retired 2026-07-15 after they false-fired behind Cloudflare and WARP; MFA plus these per-role session caps are the containment now.

Geographic Access is an allow list only - there is no separate block list. It uses geoip-lite, which lazy-loads its country data on the first lookup (a multi-second cold start, cached after that); an IP it cannot resolve to a country is let through rather than blocked, and an IP in the allowlist below bypasses the country check entirely.

The CIDR matcher behind both the Geographic Access IP allowlist and the brute-force auto-block reads IPv4 and IPv6 alike, and folds an IPv4-mapped IPv6 address such as ::ffff:1.2.3.4 back to plain IPv4 first, so a dual-stack listener still matches an IPv4 rule.

An API key's plaintext token and a webhook's signing secret are each shown exactly once, at the moment they are created. Copy it then - the portal stores only a hash of it afterward and can never show it to you again.

Steps

  1. Open Settings > Security > Access & Sessions and read the sign-in safeguards at the top.

    Require Two-Factor (MFA) defaults to Off (optional); Staff / internal accounts and Everyone are the other two choices. Max Failed Login Attempts (5 by default) and Lockout / Window Duration (1 hour by default) work as one pair: the same hour count is both the rolling window that counts failed logins and how long the automatic IP block lasts once that count is hit. Raising the number makes detection more lenient (a longer window to accumulate failures) and makes the resulting block longer at the same time; lowering it tightens detection and shortens the block together.

    Open Settings > Security > Access & Sessions and read the sign-in safeguards at the top.
  2. Scroll to Active Sessions to see who is signed in right now.

    Each row shows the user, role, IP address, device, when the session started, and when it was last active. The current session carries a you badge. Terminate signs that device out immediately - terminating your own session signs you out of the portal too. Sessions are also cleaned up automatically by the weekly Session Cleanup job (Sundays at 4 AM), regardless of what Terminate has or has not been used on.

    Scroll to Active Sessions to see who is signed in right now.
  3. Set Concurrent Session Limits for each role.

    A value of 0 means unlimited; the defaults cap Owner, Super Admin and Admin at 1 session, Primary Contact at 1, IT Admin at 2, and Client User & Billing at 3. When a user already at their role's cap signs in from a new device, the oldest existing session for that role is force-revoked to make room - useful for Owner or Super Admin, typically capped at 1, so a stolen session cannot silently sit alongside the legitimate one.

    Set Concurrent Session Limits for each role.
  4. Set Session Timeouts and click Save Session Settings.

    Staff Inactivity Timeout (8 hours by default), Client Inactivity Timeout (24 hours) and Absolute Session Lifetime (7 days) both apply at the next session-check tick, which runs every few minutes, never retroactively. Dropping Client Inactivity Timeout a lot - to less than half its previous value - signs out every active client portal user at the next check; they see "your session expired." Consider rolling a big drop like that in during off hours, or telling client primaries first.

    Warning: A saved drop in Client Inactivity Timeout applies to every client user already signed in, not just new sign-ins, at the next check.
    Set Session Timeouts and click Save Session Settings.
  5. Open Access Control and click Block IP.

    Block IP takes an IP address or CIDR range and an optional reason. This walkthrough blocks 203.0.113.0/24, a range reserved for documentation and safe to use as an example, with the reason "KB walk - example, safe to remove."

    Open Access Control and click Block IP.
  6. See the new entry on the Blocked IPs list.

    Blocked Users and Blocked IPs are Access Control's own deny lists. An IP blocked here is denied outright - it has nothing to do with the Geographic Access allowlists further down the page, which do the opposite job (letting traffic through). Adding an address to one list never adds or removes it from the other; add it wherever you need that specific effect.

    See the new entry on the Blocked IPs list.
  7. Scroll to Your Connection and Geographic Access Control.

    Your Connection shows the real IP address and country this session is signing in from, each with a one-click shortcut to allowlist it. Geographic Access Control restricts logins by country and is an allow list only - there is no separate block list. It stays Inactive until at least one country is added, and because it is checked on every request, not just at sign-in, turning it on immediately signs out anyone already working from a location that is not allowlisted.

    Scroll to Your Connection and Geographic Access Control.
  8. Add an IPv6 range to the IP Allowlist.

    The Country Allowlist and IP Allowlist are both checked on every request, and either one is enough on its own: an entry in the IP Allowlist bypasses the country check entirely, even while Geographic Access Control itself is off. The CIDR matcher accepts IPv6 ranges the same way it accepts IPv4 - adding 2001:db8::/32, a range reserved for documentation, lists it tagged CIDR exactly like an IPv4 range would.

    Add an IPv6 range to the IP Allowlist.
  9. Open Recent Admin Connections.

    This card is collapsed by default. It lists the last 20 distinct IP addresses that have signed in from any Admin or Super Admin account in the last 30 days, sorted by recency, each geo-resolved to a country (the city is not shown). It loads once, when the page loads - it does not poll. Priya Shah, a User-role contact, never appears here even though she has an active session, because that role is not Admin or Super Admin. Clicking an address's own Add link allowlists it, for either the IP Allowlist or the Geographic bypass.

    Open Recent Admin Connections.
  10. Open API Keys and start a new key.

    New Key asks for a name and at least one scope, and optionally a client organization binding or an expiry date. There is no rate-limit field here: every key is created with the same default of 1,000 requests per minute. That per-key limit is wired up in code, but it does nothing today, because Bearer-token requests never reach an API-key route - the sign-in proxy redirects any request without a session cookie to the login page first.

    Open API Keys and start a new key.
  11. Create the key and copy its plaintext token.

    The token is shown exactly once, under "Save this key now - it will not be shown again"; the database stores only a hash of it from this point on, so support can never read it back to you. It is masked in this screenshot for the same reason. The list below then shows each key's name, its scopes, its org scope (MSP-wide unless bound to one client), when it was last used, and its status. External callers use a key as an Authorization: Bearer ezk_live_... header. The three KB walk - example rows are this article's own sandbox keys from successive passes, and every one of them is Revoked now.

    Note: This walkthrough revoked its own sandbox API keys straight after capturing them, and masks the one-time token in the screenshot rather than publishing it. The rows stay on the tenant, marked Revoked.
    Create the key and copy its plaintext token.
  12. Create a webhook and copy its signing secret.

    New Webhook asks for a name, a destination URL, and which events to subscribe to; this one subscribes to ticket.created and points at https://example.com/webhook. The signing secret is shown exactly once, the same way an API key's token is, and it is masked in this screenshot for the same reason. Every matching event is then POSTed to that URL with an X-ezCyber-Signature header. After 10 consecutive delivery failures the webhook disables itself automatically, and that auto-disable is written to the audit log. Both KB walk - example rows are this article's own sandbox webhooks, and both are Disabled now.

    Note: This walkthrough disabled its own sandbox webhooks straight after capturing them, and masks the one-time signing secret in the screenshot rather than publishing it. The rows stay on the tenant, marked Disabled.
    Create a webhook and copy its signing secret.

If it did not work

  • If Save Session Settings, or the fields above it, will not save, check you are signed in as the tenant's owner email or an internal Super Admin - every field on the top card and the Sessions cards is Owner-tier, and the button does not work for anyone else.
  • If Recent Admin Connections is missing entirely, no Admin or Super Admin account has signed in during the last 30 days yet - the card only renders once there is at least one row to show.
  • If Terminate, Remove, or Revoke does not appear next to a row, your role does not carry the delete-tier permission that view-only accounts do not get by default.

Questions this page answers

Why does raising Lockout Duration also change detection?

One value drives BOTH the rolling window for counting failed logins AND the IP block duration when the threshold trips. Raising it makes detection more lenient (a longer window to accumulate failures) AND blocks the offender longer once tripped. Lowering it tightens detection AND shortens blocks. Splitting these into two separate settings is a planned follow-up.

How do session controls work?

Session controls let you view all active sessions, force-logout specific users, and configure session timeout. Sessions are cleaned up by the weekly session_cleanup cron job.

What does Max Sessions per role do?

Caps concurrent active sessions for that role. Value of 0 = unlimited. When a user already at the cap signs in from a new device, the oldest existing session is force-revoked. Useful for Owner / Super Admin (typically 1) where a stolen session shouldn't silently overlap with the legit one.

Staff timeout vs client timeout - what changes when I save?

Both apply at the NEXT session-check tick (every few minutes), not retroactively. Dropping client timeout aggressively will sign out every active client portal user at the next check - they'll see "your session expired." Consider rolling changes during off-hours or notifying client primaries first when reducing client timeout below 50% of the previous value.

How do the IP whitelist and the blocked-IP list differ?

The old mid-session "IP changed, re-authenticate" safeguard (and its CSV whitelist) was retired 2026-07-15, it false-fired behind Cloudflare/WARP; MFA plus the per-role session caps are the containment now. Two IP stores remain, with different effects: the Geographic Access IP whitelist bypasses the country allow-list check, and the Access Control blocked-IP list denies matching IPs outright. An IP in one is not automatically in the other, add it wherever you need that specific effect.

What is geographic access control?

Geographic access control restricts logins by country. When enabled, only sign-ins from approved countries are allowed. Configure it in the Geographic Access section of Settings → Security → Access & Sessions.

How does geographic access work?

Geographic access is an allow list: add the countries you permit and turn it on, and sign-ins from any country not on the list are rejected (there is no separate block list). It uses geoip-lite, which lazy-loads its bundled data on the first lookup (a multi-second cold start, cached after that). IPs it can't resolve to a country are allowed through, and IPs in the whitelist below bypass the country check entirely.

Does CIDR support IPv6?

Yes. The CIDR matcher now handles both IPv4 and IPv6 ranges, and it folds IPv4-mapped IPv6 addresses like ::ffff:1.2.3.4 back to their IPv4 form, so a dual-stack listener still matches your IPv4 rules. This applies to both the Geographic Access IP allow-list and the brute-force auto-block.

Where does the Recent Admin Connections list come from?

It's the last 20 distinct IPs that have signed in from any Admin or Super Admin account in the last 30 days, sorted by recency. Each row is geo-resolved via geoip-lite to show the country (city is not displayed). Click an IP to add it to the whitelist (for IP-safeguard or geographic bypass). It refreshes on page load, no polling.

Is there a rate-limit field, and does it do anything yet?

There is no rate-limit field when you create a key. A new key collects only a name, scopes, and an optional expiry, and is stored with the default limit of 1000 requests per minute. That per-key quota is wired to enforce (counted per key against a rolling 60-second window), but it does not take effect today because API-key (Bearer) authentication is not yet reachable: the sign-in proxy redirects any request without a session cookie to the login page before an API-key route can run. So there is nothing to configure here for now, and the effective ceiling on any route is whatever general per-route limiter it already has.

How do API keys work?

Bearer token alternative to session auth. Each key carries an org binding (ties API calls to a specific Organization), a set of scopes (which resource:action pairs it can access), and an optional rate limit. The plaintext token is shown ONCE on creation - copy it then; the DB stores only a hash for verification. Use the Bearer header: `Authorization: Bearer ezk_live_...`.

How do webhooks fire?

Pick events from the picker, point at an HTTPS URL, and save. Each event the portal emits that matches a subscription is POSTed to that URL with an HMAC signature header. After 10 consecutive delivery failures the webhook auto-disables, and that auto-disable is recorded in the audit log.

Was this helpful?

Last validated 2026-09-18