Skip to content

feat(paykit): add trusted origin allowlist#184

Open
almeidazs wants to merge 1 commit into
getpaykit:mainfrom
almeidazs:feat/trusted-origins
Open

feat(paykit): add trusted origin allowlist#184
almeidazs wants to merge 1 commit into
getpaykit:mainfrom
almeidazs:feat/trusted-origins

Conversation

@almeidazs
Copy link
Copy Markdown

@almeidazs almeidazs commented May 18, 2026

Summary

This adds a trustedOrigins option to PayKit so relative successUrl, cancelUrl, and returnUrl values can be resolved only from an explicit allowlist of trusted origins.

That tightens the request boundary for embedded billing flows and avoids trusting arbitrary request hosts or forwarded headers when the app uses path-based return URLs.

Closes #74

How it works

  • trustedOrigins?: string[] is now available on createPayKit({...})
  • when PayKit resolves a relative return URL like /billing/success, it first derives the request origin as before
  • if trustedOrigins is configured, the resolved origin must match the allowlist or the request is rejected with TRUSTED_ORIGIN_INVALID
  • config validation also rejects invalid trustedOrigins entries that include paths, queries, or hashes

Example

const paykit = createPayKit({
  database: process.env.DATABASE_URL!,
  provider: stripe({
    secretKey: process.env.STRIPE_SECRET_KEY!,
    webhookSecret: process.env.STRIPE_WEBHOOK_SECRET!,
  }),
  trustedOrigins: [
    "https://app.example.com",
    "https://staging.example.com",
  ],
});

With that in place, this stays valid:

await paykit.subscribe({
  customerId: "cus_123",
  planId: "pro",
  successUrl: "/billing/success",
  cancelUrl: "/billing/cancel",
});

But PayKit will only expand those relative URLs if the incoming request origin is in trustedOrigins.

Breaking change

No required breaking change.

This is fully opt-in. Existing apps keep the current behavior unless they set trustedOrigins.

Tests

  • node ./node_modules/vitest/vitest.mjs run --config vitest.unit.config.ts packages/paykit/src/api/__tests__/define-route.test.ts
  • bun run typecheck --filter=paykitjs

Summary by CodeRabbit

  • New Features

    • Added trustedOrigins configuration option to PayKitOptions, allowing you to specify an allowlist of accepted origins when resolving return URLs in your payment flows.
    • Enhanced origin validation checks during return URL resolution.
  • Tests

    • Comprehensive test suite added for trusted origin validation functionality.

Review Change Stack

@vercel
Copy link
Copy Markdown
Contributor

vercel Bot commented May 18, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
paykit Skipped Skipped May 18, 2026 1:07pm

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 18, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 47c3fe14-da06-48de-b503-de15bea72754

📥 Commits

Reviewing files that changed from the base of the PR and between 55a0bda and 95599a9.

📒 Files selected for processing (5)
  • packages/paykit/src/api/__tests__/define-route.test.ts
  • packages/paykit/src/api/define-route.ts
  • packages/paykit/src/core/errors.ts
  • packages/paykit/src/core/validate-options.ts
  • packages/paykit/src/types/options.ts

📝 Walkthrough

Walkthrough

This PR adds optional trustedOrigins configuration to PayKitOptions to validate and enforce allowed origins when resolving relative return URLs. The feature includes schema definition, configuration validation, error handling, threading through the normalization pipeline, and test coverage for trusted and untrusted origin scenarios.

Changes

Trusted Origins Configuration and Validation

Layer / File(s) Summary
Configuration schema and validation
packages/paykit/src/types/options.ts, packages/paykit/src/core/validate-options.ts
PayKitOptions now includes optional trustedOrigins?: string[] property with documentation. A new validator ensures each origin is an absolute URL with path / only, rejecting any with pathname, query, or hash.
Error code for origin validation
packages/paykit/src/core/errors.ts
TRUSTED_ORIGIN_INVALID error code is added to PAYKIT_ERROR_CODES to indicate when a resolved origin is not in the allowlist.
Return URL resolution with origin validation
packages/paykit/src/api/define-route.ts
normalizeMethodInput now accepts optional paykit options and threads it through normalizeReturnUrlValue and resolveAbsoluteUrl. resolveOrigin is refactored to validate the resolved origin against paykit.options.trustedOrigins when present, throwing TRUSTED_ORIGIN_INVALID if not allowed.
Test suite for trusted and untrusted origins
packages/paykit/src/api/__tests__/define-route.test.ts
New tests verify that relative return URLs resolve to absolute URLs when the request origin is trusted, and are rejected with TRUSTED_ORIGIN_INVALID when the origin is not in the allowlist.

Sequence Diagram

sequenceDiagram
  participant definePayKitMethod
  participant normalizeMethodInput
  participant resolveAbsoluteUrl
  participant resolveOrigin
  definePayKitMethod->>normalizeMethodInput: paykit.options
  normalizeMethodInput->>resolveAbsoluteUrl: paykit options
  resolveAbsoluteUrl->>resolveOrigin: request, headers, paykit
  resolveOrigin->>resolveOrigin: validate against trustedOrigins
  alt origin in trustedOrigins
    resolveOrigin-->>resolveAbsoluteUrl: origin
  else origin not trusted
    resolveOrigin-->>definePayKitMethod: TRUSTED_ORIGIN_INVALID error
  end
Loading

🎯 3 (Moderate) | ⏱️ ~25 minutes

🐰 A trusted origin for the return,
Guards against spoofing in each turn,
Return URLs now validate with care,
Host headers checked with fairness fair,
Security blooms in PayKit's layer!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(paykit): add trusted origin allowlist' clearly and concisely describes the main feature addition—a trusted origin allowlist mechanism for PayKit.
Linked Issues check ✅ Passed The PR successfully implements the objective from issue #74: adding a trustedOrigins configuration option to protect return URL resolution at the config level.
Out of Scope Changes check ✅ Passed All changes are directly related to implementing the trusted origin allowlist feature; no unrelated modifications were introduced.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint skipped: no ESLint configuration detected in root package.json. To enable, add eslint to devDependencies.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@almeidazs almeidazs marked this pull request as ready for review May 18, 2026 13:08
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.

feat(api): trustedOrigins in config

1 participant