Security Module
Guide

Security Module

An opt-in lockdown for your JetHost account. Instead of one all-or-nothing OAuth connection, you create credentials — named, expiring keys, each limited to the accounts, services, tools, and cPanel modules you choose. Built for agencies handing different people scoped, auditable AI access without giving anyone billing-area logins.

Opt-inOwner-onlyLive ACLPKCE required

What enabling it changes #

  • With the Security Module off, nothing changes — the standard OAuth flow with Dynamic Client Registration and the consent screen works exactly as documented.
  • With it on, self-service OAuth is shut off for your account: a generic AI client that reaches the consent screen gets a Security Module enabled error instead of an approve button, and enabling the module revokes all previously issued generic tokens. Access is granted only through credentials you create.
  • Only the account owner can enable the module and create or manage credentials. The people using the credentials need no JetHost login at all.
  • Every credential has a human label, so audit logs show who acted, not just that something happened.
  • The module cannot be switched off while credentials still exist — revoke them first.

Creating a credential #

The Security section lives in the client area at https://jethost.com/app/index.php?m=jethost_mcp_oauth&action=security — it is deliberately not linked from the client-area menu, so keep the URL handy. From there:

  • Name the key — a label like “Jane — SEO team”, shown in audit logs and on the key list.
  • Pick the accounts it may reach — a multi-select of every client account you are linked to (see Accounts & delegated access).
  • Scope it per account — tick account-level tool groups, per-service tools and cPanel modules, and individual domains. At least one tool or service is required.
  • Set the expiry — 30 days by default, 90 days maximum, enforced server-side.
  • Confirm with a PIN — a 6–8 digit code is emailed to your own account address. Five failed attempts lock activation for 15 minutes; resending delivers the same PIN.

On activation the connection details — the MCP server URL, an OAuth client_id, and an API token — are revealed exactly once. Copy them then; they are not recoverable later (you can mint a replacement token at any time, see Lifecycle).

Two ways to connect #

Each credential supports both connection methods; revoking the credential cuts off both at once.

  • OAuth (Claude, ChatGPT, and other OAuth-capable connectors) — add the MCP server and supply only the credential’s client_id: no login, no consent screen. The credential already pins its accounts and permissions, and the exchange is protected by PKCE and a fixed redirect-URI set. Treat the client_id like a password — with this module enabled it is a capability secret, not a public identifier.
  • API token (clients that take a pasted Bearer token) — an opaque 50-character token, jh_pat_…, sent as Authorization: Bearer. It is shown once at activation and stored only as a hash — JetHost cannot recover it. The MCP server validates it against the authorization server on every request and fails closed. The fixed jh_pat_ prefix makes a leaked token detectable by secret scanners.

What a credential can grant #

Grants are ticked per account. Account-level grants cover data that is not tied to one hosting service:

Account-level grantTools it enables
Invoices - view and historylist_invoices get_invoice search_invoices find_invoices_by_relation
Search and view domainslist_domains get_domain get_domain_nameservers get_domain_whois
Tickets - viewlist_tickets get_ticket
Plan catalogue / availabilitylist_hosting_plans get_hosting_plan check_domain_availability suggest_domains
Services - viewlist_services get_service

Per-service grants apply to individual hosting services you select:

Per-service grantTools it enables
Resource usageget_service_usage
Logsget_website_logs
Statisticsget_website_statistics
Site managementlist_website_domains get_deploy_status get_private_repo_deploy_status deploy_site_from_url deploy_private_repo provision_node_dependencies

Ticking any cPanel module for a service also grants the four cPanel tools for it — cpanel_uapi generate_deploy_key list_cpanel_operations get_cpanel_module — limited to the ticked modules.

The grant list is read live on every request and is never embedded in a token: editing a credential takes effect immediately, with no re-pairing and no new token.

Accounts & delegated access #

A credential may authorize several client accounts — any account you are linked to.

  • For accounts you own, everything is grantable.
  • For accounts where you are a delegated contact, each grant is gated by the contact permissions that account has given you — checked when the credential is created or edited and re-checked live on every request, both failing closed. If the account owner removes one of your permissions, the matching AI access stops on the very next request.
Contact permission requiredTool scopes it unlocks
products — View Products & Servicesread:services
invoices — View & Pay Invoicesread:invoices
domains — View Domainsread:domains
tickets — View & Open Support Ticketsread:tickets
none — public catalog dataread:domain_catalog read:product_catalog
manageproducts — Manage Products & Servicesread:logs read:websites read:analytics read:deploy write:deploy cpanel:uapi

Selecting cPanel modules for a delegated account’s service requires the manageproducts permission — viewing a product and using its cPanel API are separate rights.

Isolation guarantee: a resource the credential does not authorize behaves exactly like one that does not exist. The requested item does not exist, or it belongs to another account. Cross-account IDs are indistinguishable from missing ones by design.

Lifecycle #

  • Access tokens live 15 minutes. OAuth connections hold a rolling refresh token whose lifetime is clamped to the credential’s expiry, so connectors stay paired without re-setup until the credential itself expires.
  • The credential’s expiry is a hard cap — enforced live on every request, so even a freshly minted token dies with its credential.
  • New API token — minting a replacement runs a fresh PIN confirmation; the old token keeps working until the new one is revealed, so the person using the key is never stranded mid-swap.
  • Revoking a credential cuts off both connection methods instantly — the API token, every OAuth-minted access token, and their refresh tokens, in one step.
  • A credential is pending until its PIN activation, then active until it expires or is revoked.