Skip to content

Make Openpay SDK credentials request-safe for php-fpm and FrankenPHP worker#88

Open
HecFranco wants to merge 1 commit into
open-pay:masterfrom
nowo-tech:feature/request-safe-credentials-frankenphp-fpm
Open

Make Openpay SDK credentials request-safe for php-fpm and FrankenPHP worker#88
HecFranco wants to merge 1 commit into
open-pay:masterfrom
nowo-tech:feature/request-safe-credentials-frankenphp-fpm

Conversation

@HecFranco

Copy link
Copy Markdown

Summary

This PR hardens openpay/sdk so merchant credentials stored in process-global statics can be explicitly configured and cleared per logical API session.

Upstream Openpay PHP keeps merchant id, api key, country, endpoints and related state in static properties on Openpay\Data\Openpay. That design is acceptable when the PHP process lifetime equals a single HTTP request (classic short-lived workers). It is unsafe when the same process serves many requests:

Runtime Process model Risk without this change
php-fpm Worker often reused across requests Residual statics from request N may affect request N+1 if getInstance() only partially updates fields
FrankenPHP classic Closer to request-scoped Lower risk, still safer to clear explicitly
FrankenPHP worker (ZTS) Long-lived worker; application state may be reused between requests High: credentials of merchant A can leak into merchant B’s request

The Composer package name remains openpay/sdk so this repository can replace Packagist via a VCS or path repository without renaming the dependency.

What changed

Openpay\Data\Openpay

  • configure(string $id, string $apiKey, string $country = 'MX', string $publicIp = '127.0.0.1'): void
    Overwrites merchant context in full (no merge with previous values) and refreshes endpoint URLs for the country.

  • reset(): void
    Clears merchant id, API key, country, public IP, endpoints, sandbox flags, classification, user agent and the cached instance. Safe to call after each API session and on framework request/kernel reset hooks.

  • getInstance(...)
    Always goes through configure() (defaults country to MX and public IP to 127.0.0.1 when empty/null), then returns OpenpayApi::createRoot().
    Behavioural fix vs upstream: empty strings or partial updates no longer leave a previous merchant’s credentials in place.

Openpay\Data\OpenpayApi

  • createRoot(): self
    Public factory used after credentials are configured (avoids relying on a public getInstance for the API root).

  • Minor clean-ups aligned with PHP 8.x (declare(strict_types=1), self::class, #[Override] where applicable).

composer.json

  • Document request-safe credential handling in the package description.
  • Require PHP >=8.1.
  • Point support URLs at this repository.

Why this is needed

Packagist upstream does not expose configure() / reset(). Without those APIs (or an equivalent override), application code cannot reliably clear static merchant state between requests in a long-lived process.

Upstream getInstance() also updates credentials conditionally (e.g. only when id/apiKey/country are non-empty). In a reused worker that can leave the previous merchant’s values in place when a later call omits or empties a field.

Recommended usage

Prefer an explicit session boundary:

Openpay::configure($merchantId, $apiKey, $country, $publicIp);
$api = OpenpayApi::createRoot();

try {
    // charges, webhooks, customers, …
} finally {
    Openpay::reset();
}

Openpay::getInstance($id, $apiKey, $country, $publicIp) remains supported and now always reconfigures before returning the API root.

In frameworks that support request-scoped service reset (e.g. Symfony ResetInterface), call Openpay::reset() from that hook as a safety net in addition to the finally block above.

Compatibility

  • API surface: additive for configure, reset, createRoot; getInstance remains the primary entry point.
  • php-fpm: compatible; reset() is cheap insurance on worker reuse.
  • FrankenPHP worker: required for multi-tenant / multi-merchant safety in one process.
  • Upstream feature parity: based on Openpay PHP 3.1.1 (5a922d4); Resources and connectors unchanged aside from the Data layer above.

Test plan

  • configure(A) then configure(B)getId() / getApiKey() / country / public IP equal B only (no leftover A).
  • After reset(), static id, apiKey, country and publicIp are null (or equivalent cleared state).
  • getInstance(...) after a previous merchant still returns an API root bound to the new credentials.
  • reset() in a finally block runs when the callback throws (no credential left for the next call in the same process).
  • Smoke: sandbox webhook or charge for two different merchants sequentially in one PHP process.
  • Confirm Composer resolves openpay/sdk from this repository (VCS/path) and autoloads Openpay\Data\Openpay from this package, not an older Packagist copy without reset().

Checklist

  • Request-scoped credential overwrite (configure)
  • Explicit cleanup (reset)
  • Safe getInstance path (no partial merge with previous merchant)
  • Package metadata updated in composer.json
  • Tag a release after merge (e.g. 3.1.1-1 or 3.1.2) for pinable Composer constraints

@HecFranco

Copy link
Copy Markdown
Author

Thank you for maintaining and publishing this package — it has been very useful for integrating Openpay into our PHP applications.

We have opened this MR to make credential handling safe under long-lived PHP workers (php-fpm and FrankenPHP worker), where process-global statics can otherwise leak merchant credentials across requests. The changes are additive (configure() / reset() / createRoot()) and keep getInstance() as the main entry point.

We would appreciate it if you could review and approve this MR when you have a moment. Happy to adjust anything based on your feedback.

Thanks again for your work on the SDK.

@HecFranco
HecFranco force-pushed the feature/request-safe-credentials-frankenphp-fpm branch from 8fbe8a4 to 7d95fa4 Compare July 17, 2026 08:31
Add configure()/reset() and createRoot() so merchant statics can be
cleared between requests in long-lived workers (FrankenPHP) and FPM.
@HecFranco
HecFranco force-pushed the feature/request-safe-credentials-frankenphp-fpm branch from 7d95fa4 to d27bd63 Compare July 17, 2026 08:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant