authn-sh/sdk-php
Composer 安装命令:
composer require authn-sh/sdk-php
包简介
PHP backend SDK for authn.sh — BAPI client, JWT verification, and webhook signature verification.
README 文档
README
PHP backend SDK for 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 package.
Status: 0.1.x pre-release. APIs may change before
1.0.
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, so installingguzzlehttp/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
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
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
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
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
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, withgetRetryAfter()).Authn\Sdk\Http\NetworkException— connection-level failures.
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
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
$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
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
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
authn-sh/sdk-php 适用场景与选型建议
authn-sh/sdk-php 是一款 基于 PHP 开发的 Composer 扩展包,目前已累计 189 次下载、GitHub Stars 达 0, 最近一次更新时间为 2026 年 05 月 03 日, 在 PHP 生态内属于活跃度较高的组件。
它主要适用于以下技术方向: 「Authentication」 「sdk」 「identity」 「authn」 等业务场景。在实际项目中,围绕这些方向常见需要落地的问题包括:接口对接、性能调优、并发安全、与既有框架(Laravel / ThinkPHP / Yii / Webman 等)的兼容适配,以及生产环境的日志埋点与稳定性保障。
我们在过去多个企业项目中使用过 authn-sh/sdk-php 或与其功能相近的方案,如果你在选型或落地过程中遇到问题,例如 版本兼容、二次改造、私有化封装、与内部系统对接、生产 BUG 排查,欢迎联系我们协助评估。
基于 authn-sh/sdk-php 在你已有业务上做功能扩展、字段裁剪、UI 适配、与内部账号 / 权限 / 日志系统的深度对接。
线上偶发问题、内存泄漏、慢查询、并发异常等排查修复;针对高流量场景做缓存、队列、索引层面的调优。
承接完整的项目从需求 → 设计 → 开发 → 上线 → 长期运维;也可按月提供技术保姆服务。
与 authn-sh/sdk-php 相关的其它包
同方向 / 同关键字的高下载量 PHP Composer 包推荐,方便对比选型:
Automatically logs-in users if they are already authenticated by a remote source. (e.g. environment variable REMOTE_USER)
GraphQL authentication for your headless Craft CMS applications.
Laravel middleware to restrict a site or specific routes using HTTP basic authentication
Email Toolkit Plugin for CakePHP
Identity authorizator class for Nette Framework
Identity ACL extension for Nette Framework
统计信息
- 总下载量: 189
- 月度下载量: 0
- 日度下载量: 0
- 收藏数: 0
- 点击次数: 48
- 依赖项目数: 1
- 推荐数: 0
其他信息
- 授权协议: AGPL-3.0-only
- 更新时间: 2026-05-03