Skip to content

Security and operations for NextPDF Connect

NextPDF Connect authenticates networked transports with an API key bearer token. It treats the local Model Context Protocol (MCP) transport as a trusted subprocess. It gates every high-risk tool behind explicit human confirmation. This page explains the authentication model, transport security, and threat model.

Terminal window
composer require nextpdf/server

The server has three trust boundaries, one per transport.

The MCP stdio transport is a subprocess launched by a local client. It reads JSON-RPC on standard input and writes responses on standard output. This transport has no network listener and no API key. It inherits trust from the operating-system process boundary, which is the trust model the MCP specification defines for stdio. Logging goes to standard error, so it never corrupts the protocol stream.

The REST transport and the gRPC transport are networked. Both require an API key bearer token on every request except unauthenticated health probes. The same key store, key format, and constant-time validation support both transports. The gRPC transport reads the token from call metadata. REST reads it from the Authorization header.

Incorrect authentication is the failure that the OWASP Application Programming Interface (API) Security Top 10 identifies as API2:2023 Broken Authentication. Flaws in this area compromise the API’s ability to identify the caller and therefore compromise API security overall (OWASP API Security Top 10, API2:2023). Weak or predictable tokens are also called out as a broken-auth anti-pattern (same source, vulnerability list). The design below addresses both risks.

A key is npk_live_{kid}_{secret}. The kid is an eight-character identifier used for O(1) record lookup, and the secret carries the entropy. The store never keeps the raw key. It stores a SHA-256 digest of the full key material. On each request, the server hashes the presented token and compares it with the stored digest by using a constant-time comparison (hash_equals), so a wrong key reveals nothing through timing. A disabled or expired key is rejected after the hash check, not before.

The REST and gRPC validators share this logic. The REST middleware reads Authorization: Bearer npk_live_…. The gRPC authenticator reads the same bearer token from the gRPC authorization call metadata, which is carried as HTTP/2 headers. It fails the call with the gRPC UNAUTHENTICATED status.

Both transports also apply an anti-automation throttle to pre-authentication traffic: excessive attempts from one client identity are rate-limited and rejected — 429 Too Many Requests on REST, and the gRPC RESOURCE_EXHAUSTED status on gRPC. This control is active by default, so it protects a deployment that has not separately configured a rate-limit store. Clients should back off rather than retry immediately.

A REST request with a missing, malformed, disabled, or expired key receives 401 Unauthorized with a problem-details body and a WWW-Authenticate: Bearer response header. This matches the HTTP requirement that a 401 response MUST carry a WWW-Authenticate header field with at least one challenge (RFC 9110 §11.6.1). That requirement follows from the rule that a request with omitted or invalid credentials should receive 401 plus a WWW-Authenticate challenge (RFC 9110 §11.6).

Each key record carries a maximum product tier. The REST pipeline attaches the authenticated client’s identity and tier to the request, so downstream authorization can enforce capability and payload ceilings by tier. A core-tier key cannot run a Pro or Enterprise operation, even when those packages are installed.

  • The MCP transport has no API key. That is intentional and correct for a local subprocess. Do not expose the MCP server through a network shim. If a networked agent needs the tools, put it in front of the REST or gRPC transport, which authenticate.

  • Health probes are anonymous on purpose. /healthz and /readyz bypass authentication so orchestrators can probe liveness and readiness without a credential. They return only a status. They expose no tool data or document data.

  • A confirmation token is single-use and short-lived. The human-in-the-loop gate issues a token bound to the tool name with a 300-second lifetime. The token is consumed on first use. It is not an authentication credential and does not replace an API key.

Authentication is a single hash plus a constant-time comparison per request. That cost is negligible compared with the cost of a render. The hot-reloading key store re-reads the key file when it changes, so rotation does not require a restart and adds no per-request cost.

Every tool declares a risk level. Tools at the highest level, ApprovalRequired, do not run on first call. The confirmation gate returns a challenge that contains a single-use token. The agent must show the challenge to a human and re-invoke the tool with the token. This is a deliberate control at the point where automated action introduces risk. It is the point that IEC 31010 identifies for controlling risk introduced through human (here, agent) action, at or near the point of introduction (IEC 31010:2019). Configuration cannot weaken the gate: a config override may only raise a tool’s risk, never lower an ApprovalRequired tool. See /connect/hitl-risk-tiers/.

The networked transports do not terminate Transport Layer Security (TLS) themselves; TLS is a deployment concern. The reference combined deployment runs the gRPC transport with mutual TLS, with the key, certificate, and client CA supplied as deployment secrets. Under mutual TLS, the server presents a certificate and requires and verifies a client certificate. Run the REST transport behind a TLS terminator (reverse proxy or service mesh), and never expose a plaintext listener on an untrusted network. Configuration specifics are in /connect/deployment/. This is a posture statement, not a turnkey guarantee, and secure transport requires correct deployment configuration.

File-writing tools resolve the requested path against the configured base directory, canonicalize it, and reject null bytes, protocol wrappers, and .. traversal. They refuse any path that resolves outside the base. Keep the base directory on a dedicated volume with least-privilege filesystem permissions.

The server holds documents only in the in-memory document store for the configured time to live (TTL) (default 1800 seconds) and bounded count (default 50). It does not persist document content to disk unless you explicitly invoke a file-output tool and the path passes containment. The server makes no outbound network call to render or inspect a document, so document bytes do not leave the deployment unless a tool is explicitly configured to fetch a remote resource. For stateless, residency-sensitive deployments, disable file output (allow_file_output: false) and restrict enabled_tools to the minimum set.

Audit logging records tool executions at the Caution risk level and above, plus every issued confirmation challenge. The audit record carries the tool name, the risk level, and the success flag. Treat tool arguments as potentially sensitive: route logs to a sink with access controls, and do not raise the global log level to a verbosity that echoes argument payloads in shared environments. The MCP transport writes logs to standard error so log content never enters the protocol stream on standard output.

ClaimSourcereference_id
Broken authentication compromises API securityOWASP API Security Top 10, API2:2023
Weak/predictable tokens are a broken-auth anti-patternOWASP API Security Top 10, API2:2023
401 MUST carry a WWW-Authenticate challengeRFC 9110 §11.6.1
Missing/invalid credentials → 401 + challengeRFC 9110 §11.6
Control risk at the point of (human) introductionIEC 31010:2019

The Model Context Protocol stdio trust model follows the official MCP specification, revision 2025-06-18. Its URL is recorded on /transports/mcp/ because the MCP specification is not part of the gated standards corpus.

Signing, redaction, compliance, and forensic tools are present only when nextpdf/premium is installed alongside the server. Their presence does not change the authentication model. Their risk tier still places destructive tools behind the human-in-the-loop gate.

  • /connect/hitl-risk-tiers/ — the risk model and confirmation envelope in detail
  • /connect/deployment/ — TLS, mutual TLS, secrets, and worker tuning
  • /transports/rest/ — the REST middleware pipeline and OpenAPI security scheme
  • /transports/grpc/ — gRPC metadata authentication and status codes
  • /connect/configuration/ — enabled_tools, key store selection, risk overrides