Skip to content
XID

sdk/php

PHP 8.1+ server SDK for networkless JWT verification, PSR-7 request authentication, and webhook signature validation.

Status

Implemented and verified locally. Real IdP round-trip verification (JWKS fetch, token sign/verify against a live XID instance) has not been performed yet and must be completed before production use.

XID publishes no packages to any registry. This SDK is distributed as source in the XID repository; use it from a checkout of the repository.

Request authentication is Bearer-only by default. An application-owned JWT cookie is read only when its exact name is configured. The opaque __Host-xid.rt.* Core cookie is never scanned or verified locally; exchange it by forwarding the complete Cookie header to exact same-origin POST /v1/sessions/token with redirects disabled, and accept only a response containing the token field.

Install

PHP 8.1+ required. Core dependencies are pulled automatically by Composer.

{
  "repositories": [
    { "type": "path", "url": "../xid/sdk/php" }
  ],
  "require": {
    "xid/xid": "dev-main"
  }
}

# composer update xid/xid

Quick start

use Xid\XidClient;
use Xid\Exception\TokenException;
use Xid\Exception\JwksException;

$xid = new XidClient([
    'issuer'   => 'https://xid.dev',
    'audience' => 'your-client-id',
    'cache'    => $psrSimpleCacheImpl, // PSR-16; null disables JWKS cache
]);

try {
    $claims = $xid->verifyToken($jwtString);
    echo $claims->sub();    // user ID
    echo $claims->scope();  // "openid profile email"
    echo implode(',', $claims->amr()); // "phr" / "otp"
} catch (TokenException $e) {
    http_response_code(401);
} catch (JwksException $e) {
    http_response_code(503);
}

Authenticate a PSR-7 request

$result = $xid->authenticateRequest($psrRequest);

if ($result->isAuthenticated()) {
    $userId = $result->claims()->sub();
} else {
    // $result->reason() for server-side logs only
    http_response_code(401);
}

$token = $xid->exchangeSessionToken(
    'https://app.example.com/account',
    $psrRequest->getHeaderLine('Cookie'),
    $sessionTokenTransport,
);

Verify webhook

use Xid\Exception\WebhookException;

try {
    $payload = $xid->verifyWebhook($psrRequest, 'whsec_...');
    $type = $payload->type();  // "user.created"
    $data = $payload->data();
} catch (WebhookException $e) {
    http_response_code(400);
}

XidClient options

Key Default Description
issuer required XID issuer URI
audience null Expected audience; null skips validation
cache null PSR-16 CacheInterface for JWKS caching
jwks_ttl 3600 JWKS cache TTL in seconds
clock_leeway 0 JWT clock skew tolerance in seconds
cookie_name disabled Application-owned JWT cookie name; disabled unless explicitly configured

XidClient methods

Method Returns Description
verifyToken(string $token) Claims Verify JWT string; throws on failure
authenticateRequest(ServerRequestInterface $request) AuthResult Authenticate PSR-7 request; does not throw
verifyWebhook(ServerRequestInterface $request, string $secret) WebhookPayload Validate webhook signature; throws on failure
refreshJwks() void Force-refresh the JWKS cache

Platform notes

  • Uses firebase/php-jwt for ES256/RS256 verification. HS256 and none alg are rejected.
  • Requires a PSR-7 request object for authenticateRequest and verifyWebhook. Convert framework-native requests with a PSR-7 bridge if needed.
  • Exception hierarchy: XidException -> TokenException, JwksException, WebhookException.

Type to search

Use arrow keys to navigateEnter to selectEscape to close