PHPackages                             authn-sh/sdk-php - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Authentication &amp; Authorization](/categories/authentication)
4. /
5. authn-sh/sdk-php

ActiveLibrary[Authentication &amp; Authorization](/categories/authentication)

authn-sh/sdk-php
================

PHP backend SDK for authn.sh — BAPI client, JWT verification, and webhook signature verification.

v0.7.0(4w ago)01891AGPL-3.0-onlyPHPPHP ^8.2CI passing

Since May 3Pushed 4w agoCompare

[ Source](https://github.com/authn-sh/sdk-php)[ Packagist](https://packagist.org/packages/authn-sh/sdk-php)[ Docs](https://authn.sh)[ RSS](/packages/authn-sh-sdk-php/feed)WikiDiscussions main Synced 1w ago

READMEChangelogDependencies (13)Versions (36)Used By (1)

authn-sh/sdk-php
================

[](#authn-shsdk-php)

PHP backend SDK for [authn.sh](https://authn.sh) — call the Backend API (BAPI), verify session JWTs, and verify webhook signatures from server-side PHP. The Laravel integration lives in the separate [`authn-sh/sdk-php-laravel`](https://github.com/authn-sh/sdk-php-laravel) package.

> Status: **0.1.x pre-release.** APIs may change before `1.0`.

Requirements
------------

[](#requirements)

- PHP **8.2+**
- A PSR-18 HTTP client (Guzzle, Symfony HttpClient, etc.) and PSR-17 factories. The SDK auto-discovers them via [`php-http/discovery`](https://docs.php-http.org/en/latest/discovery.html), so installing `guzzlehttp/guzzle` (or any PSR-18 client) is enough.
- A PSR-16 cache (optional, for the JWT verifier). Without one the JWKS document is re-fetched on every verify.

Install
-------

[](#install)

```
composer require authn-sh/sdk-php
```

If you don't already have a PSR-18 client in your project:

```
composer require guzzlehttp/guzzle
```

BAPI client
-----------

[](#bapi-client)

```
use Authn\Sdk\Client;

$client = new Client(secretKey: $_ENV['AUTHN_SECRET_KEY']);

$user = $client->users()->get('user_2x4yT…');
$session = $client->sessions()->revoke('sess_…');
$invite = $client->invitations()->create(['email_address' => 'a@b.com']);
```

Resource managers: `users()`, `sessions()`, `invitations()`, `allowlistIdentifiers()`, `blocklistIdentifiers()`, `redirectUrls()`, `instance()`, `webhookEndpoints()`, `organizations()`, `roles()`, `permissions()`, `oauthProviders()`, `enterpriseConnections()`, `enterpriseAccounts()`, `smsTemplates()`, `phoneNumbers()`, `externalAccounts()`, `passkeys()`, `appearance()`, `localization()`.

Organization sub-managers are accessed via `$client->organizations()`:

```
$orgs = $client->organizations();

// Org CRUD
$org  = $orgs->create(['name' => 'Acme', 'slug' => 'acme']);
$org  = $orgs->get('org_…');
$orgs->update('org_…', ['name' => 'Acme Corp']);
$orgs->delete('org_…');

// Memberships
$members = $orgs->members('org_…');
$members->list();
$members->create(['user_id' => 'user_…', 'role' => 'basic_member']);
$members->update('user_…', 'admin');
$members->delete('user_…');

// Invitations
$invites = $orgs->invitations('org_…');
$invites->create(['email_address' => 'a@b.com', 'role' => 'basic_member']);
$invites->bulkCreate([['email_address' => 'a@b.com'], ['email_address' => 'c@d.com']]);
$invites->revoke('orginv_…');

// Domains
$domains = $orgs->domains('org_…');
$domains->create('acme.com');
$domains->verify('orgdmn_…');
```

### Roles and permissions

[](#roles-and-permissions)

```
use Authn\Sdk\Resources\SystemPermissions;

// Custom roles
$role = $client->roles()->create(['name' => 'Billing Admin', 'key' => 'org:billing_admin']);
$client->roles()->setPermissions($role['id'], [
    SystemPermissions::ORG_SYS_ROLES_READ,
    SystemPermissions::ORG_SYS_ROLES_MANAGE,
]);
$client->roles()->delete($role['id']);

// Read the permissions catalog
$perms = $client->permissions()->list();
```

### Custom HTTP client / logger

[](#custom-http-client--logger)

```
use Authn\Sdk\Client;
use GuzzleHttp\Client as Guzzle;

$client = new Client(
    secretKey: $_ENV['AUTHN_SECRET_KEY'],
    apiUrl: 'https://api.authn.sh',
    http: new Guzzle(['timeout' => 5]),
    logger: $psr3Logger,
);
```

### Errors

[](#errors)

- `Authn\Sdk\Http\ApiException` — non-2xx responses; `getStatusCode()`, `getErrors()`, `getErrorCode()`, `getTraceId()`, `getRawBody()`.
- `Authn\Sdk\Http\AuthenticationException` (401), `Authn\Sdk\Http\ResourceNotFoundException` (404), `Authn\Sdk\Http\RateLimitExceededException` (429, with `getRetryAfter()`).
- `Authn\Sdk\Http\NetworkException` — connection-level failures.

Verify a session JWT
--------------------

[](#verify-a-session-jwt)

```
use Authn\Sdk\Tokens\TokenVerifier;
use Authn\Sdk\Tokens\TokenInvalidException;

$verifier = new TokenVerifier(
    publishableKey: $_ENV['AUTHN_PUBLISHABLE_KEY'], // pk_test_… / pk_live_…
    cache: $psr16Cache,                              // optional PSR-16 cache for JWKS
);

try {
    $claims = $verifier->verify($jwt);                 // throws TokenInvalidException
    // or: $claims = $verifier->tryVerify($jwt);       // returns null on failure

    $userId = $claims->sub;       // user_…
    $sessionId = $claims->sid;    // sess_…
} catch (TokenInvalidException $e) {
    // 401 the request
}

// Optional: enforce origin binding via the azp claim.
$claims = $verifier->verify($jwt, expectedAzp: ['https://app.acme.com']);
```

The verifier fetches the FAPI JWKS once and caches it (PSR-16). On an unknown `kid` it refreshes the JWKS once before failing.

### Organization claim

[](#organization-claim)

When the session JWT carries an `org` claim, `$claims->organization` is populated as a typed `Organization` object:

```
use Authn\Sdk\Resources\SystemPermissions;

$claims = $verifier->verify($jwt);

if ($claims->organization !== null) {
    $org = $claims->organization;

    $org->id;          // 'org_…'
    $org->slug;        // 'acme' or null
    $org->role;        // 'org:admin' or null
    $org->permissions; // ['org:sys_profile:read', …]

    $org->hasRole('org:admin');
    $org->hasPermission(SystemPermissions::ORG_SYS_PROFILE_READ);
}

// Convenience shortcuts directly on VerifiedClaims:
$claims->hasRole('org:admin');
$claims->hasPermission(SystemPermissions::ORG_SYS_PROFILE_MANAGE);
```

### Passkey claims

[](#passkey-claims)

`$claims->passkeyVerified` is `true` when the current session was authenticated by a passkey first-factor with `userVerification = required` (parsed from the `pkv` JWT claim). `$claims->passkeyCount` is the snapshot of the user's verified-passkey count at session creation (`pkc` claim).

```
$claims = $verifier->verify($jwt);

// Gate sensitive operations to passkey-authenticated sessions.
if (! $claims->wasVerifiedByPasskey()) {
    abort(403, 'Sensitive operation requires a passkey session.');
}

// Nudge a user who has zero passkeys towards enrollment.
if (! $claims->hasPasskey()) {
    // render passkey-enrollment CTA
}
```

Verify a webhook
----------------

[](#verify-a-webhook)

```
use Authn\Sdk\Webhooks\SignatureVerifier;
use Authn\Sdk\Webhooks\SignatureInvalidException;

// One signing secret, or many during a rotation overlap window.
$verifier = new SignatureVerifier($_ENV['AUTHN_WEBHOOK_SECRET']);

try {
    $event = $verifier->verify($rawBody, $request->getHeaders()); // throws SignatureInvalidException

    if ($event->type === 'user.created') {
        // $event->data carries the resource payload
    }
} catch (SignatureInvalidException $e) {
    // 401 the request
}
```

Replay protection is on by default with a 5-minute tolerance — pass `toleranceSeconds:` to widen or narrow it.

Development
-----------

[](#development)

```
composer install
composer test       # Pest
composer phpstan    # PHPStan @ level 10
composer pint       # code style check
composer pint:fix   # apply fixes
```

CI runs the full suite on PHP 8.2, 8.3, 8.4, and 8.5.

License
-------

[](#license)

[AGPL-3.0-only](LICENSE).

###  Health Score

43

—

FairBetter than 89% of packages

Maintenance94

Actively maintained with recent releases

Popularity15

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity47

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~1 days

Total

7

Last Release

28d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/6453240?v=4)[Vagner Cavalcante](/maintainers/vagnercsouza)[@vagnercsouza](https://github.com/vagnercsouza)

---

Top Contributors

[![vagnercsouza](https://avatars.githubusercontent.com/u/6453240?v=4)](https://github.com/vagnercsouza "vagnercsouza (35 commits)")

---

Tags

sdkAuthenticationidentityauthn

###  Code Quality

TestsPest

Static AnalysisPHPStan

Code StyleLaravel Pint

Type Coverage Yes

### Embed Badge

![Health badge](/badges/authn-sh-sdk-php/health.svg)

```
[![Health](https://phpackages.com/badges/authn-sh-sdk-php/health.svg)](https://phpackages.com/packages/authn-sh-sdk-php)
```

###  Alternatives

[cakephp/cakephp

The CakePHP framework

8.8k19.1M1.7k](/packages/cakephp-cakephp)[tempest/framework

The PHP framework that gets out of your way.

2.2k31.1k11](/packages/tempest-framework)[flow-php/flow

PHP ETL - Extract Transform Load - Data processing framework

84735.1k](/packages/flow-php-flow)[telnyx/telnyx-php

Official Telnyx PHP SDK — APIs for Voice, SMS, MMS, WhatsApp, Fax, SIP Trunking, Wireless IoT, Call Control, and more. Build global communications on Telnyx's private carrier-grade network.

35729.6k2](/packages/telnyx-telnyx-php)[shopware/core

Shopware platform is the core for all Shopware ecommerce products.

585.4M506](/packages/shopware-core)[laudis/neo4j-php-client

Neo4j-PHP-Client is the most advanced PHP Client for Neo4j

185671.3k41](/packages/laudis-neo4j-php-client)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
