Skip to content

Conversation

@Koosha-Owji
Copy link
Contributor

Explain your changes

Fixes #77 — add PHP equivalent of @kinde/webhooks for webhook JWT validation/decoding, exposing event type constants and a decoder that reuses existing JWKS fetch/cache.

Checklist

🛟 If you need help, consider asking for advice over in the Kinde community.

@Koosha-Owji Koosha-Owji requested a review from a team as a code owner January 21, 2026 03:54
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 21, 2026

Walkthrough

Adds webhook validation helpers (decoder, event/source enums) and extends JWKS caching/parsing to accept a namespaced JWKS URL for trusted validation and cache isolation.

Changes

Cohort / File(s) Summary
Webhook utilities
lib/Webhooks/WebhookDecoder.php, lib/Webhooks/WebhookEventType.php, lib/Webhooks/WebhookSource.php
New WebhookDecoder::decodeWebhook(?string $token, ?string $domain): ?array (normalizes domain, builds JWKS URL, delegates to Utils::parseJWT, returns payload or null). New enum-like classes WebhookEventType and WebhookSource with constants and all() helpers.
JWKS cache & lookup (Storage)
lib/Sdk/Storage/Storage.php
JWKS cache methods now accept optional ?string $jwksUrl to namespace cache keys: getCachedJwks(?string $jwksUrl = null), setCachedJwks(array $jwks, int $ttlSeconds = 3600, ?string $jwksUrl = null), clearCachedJwks(?string $jwksUrl = null). Added private getJwksCacheKey(?string $jwksUrl = null): string.
JWT parsing utility (Utils)
lib/Sdk/Utils/Utils.php
parseJWT(string $token, ?string $jwksUrl = null) now accepts a JWKS URL, validates it via new validateTrustedJwksUrl(string $jwksUrl): string, and uses namespaced cache helpers (getCachedJwks/setCachedJwks/clearCachedJwks) when fetching/parsing JWKS.

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant Decoder as WebhookDecoder
  participant Utils as Utils::parseJWT
  participant Storage
  participant JWKS as JWKS Endpoint

  Client->>Decoder: decodeWebhook(token, domain)
  Decoder->>Decoder: normalize domain, build jwksUrl
  Decoder->>Utils: parseJWT(token, jwksUrl)
  Utils->>Storage: getCachedJwks(jwksUrl)
  alt cache miss / refresh
    Utils->>JWKS: fetch JWKS from jwksUrl
    JWKS-->>Utils: return keys
    Utils->>Storage: setCachedJwks(keys, ttl, jwksUrl)
  end
  Utils-->>Decoder: return payload or error
  alt payload returned
    Decoder-->>Client: return payload (array)
  else invalid / error
    Decoder-->>Client: return null
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat: Add webhook decoder' is concise and directly summarizes the main change of adding webhook decoding functionality to the PHP SDK.
Description check ✅ Passed The PR description is clearly related to the changeset, explaining that it adds a PHP equivalent of @kinde/webhooks for JWT validation/decoding and references issue #77.
Linked Issues check ✅ Passed The changeset addresses issue #77 by providing webhook JWT decoding/validation, WebhookEventType constants, and WebhookSource definitions with domain validation support as discussed in review comments.
Out of Scope Changes check ✅ Passed All changes are within scope: WebhookDecoder and related classes implement webhook validation per #77, while Storage and Utils modifications support the JWKS caching by URL needed for webhook validation.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

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

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Important

Action Needed: IP Allowlist Update

If your organization protects your Git platform with IP whitelisting, please add the new CodeRabbit IP address to your allowlist:

  • 136.113.208.247/32 (new)
  • 34.170.211.100/32
  • 35.222.179.152/32

Reviews will stop working after February 8, 2026 if the new IP is not added to your allowlist.


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.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@lib/Webhooks/WebhookDecoder.php`:
- Around line 24-33: In decodeWebhook, validate and parse the incoming $domain
before building $jwksUrl: use a URL/host parser (e.g., parse_url or filter_var)
to ensure the scheme is present and equals "https" and that the host is a valid
hostname (reject IPs/private ranges if required), and only then construct
$normalizedDomain and $jwksUrl; if validation fails, return null. Reference:
function decodeWebhook, variables $domain, $normalizedDomain, and $jwksUrl.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@lib/Webhooks/WebhookDecoder.php`:
- Around line 39-45: The code mutates global JWKS state via
Storage::getInstance()->setJwksUrl($jwksUrl) which causes race conditions;
instead remove that global mutation and pass the JWKS URL directly into the JWT
parsing call (e.g., change Utils::parseJWT($token) to Utils::parseJWT($token,
$jwksUrl) or an equivalent per-call parameter) from WebhookDecoder::...; update
Utils::parseJWT to accept and use the jwksUrl parameter (and preserve existing
exception handling) so each parseJWT call uses the provided jwksUrl and no
shared Storage state is modified.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
lib/Sdk/Utils/Utils.php (1)

121-137: Fix inconsistent indentation in the error recovery block.

Lines 125 and 130 have excessive leading whitespace that breaks the code's visual consistency.

Proposed fix
         } catch (Exception $e) {
             // If parsing fails with cached JWKS, try to refresh from server
             if ($jwks !== null) {
                 try {
-                        Storage::getInstance()->clearCachedJwks($jwks_url);
+                    Storage::getInstance()->clearCachedJwks($jwks_url);
                     $jwks_json = file_get_contents($jwks_url);
                     $jwks = json_decode($jwks_json, true);
                     
                     if ($jwks && isset($jwks['keys'])) {
-                            Storage::getInstance()->setCachedJwks($jwks, 3600, $jwks_url);
+                        Storage::getInstance()->setCachedJwks($jwks, 3600, $jwks_url);
                         return json_decode(json_encode(JWT::decode($token, JWK::parseKeySet($jwks))), true);
                     }
                 } catch (Exception $refreshException) {

@KeeganBeuthin
Copy link
Contributor

will look through this today

@KeeganBeuthin
Copy link
Contributor

Hey @Koosha-Owji, just finished running through this. Overall quality looks good and I’m happy with the approach.

Just wanted to check a couple things with you as well. Would you be open to adding a lightweight domain guard to prevent untrusted domains being used to fetch JWKS?

Also, can you confirm the customer requirement is strictly signature validation + decode, or do they expect additional claim checks, iss/aud/typ?

@Koosha-Owji
Copy link
Contributor Author

Hello @KeeganBeuthin Yes my understanding it they are looking for the same functionality as the https://github.com/kinde-oss/webhook

@Koosha-Owji
Copy link
Contributor Author

@KeeganBeuthin I have addressed your comments.

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.

Feature request: add PHP equivalent of @kinde/webhook for webhook validation

2 participants