PHPackages                             amtgard/idp-php-client - 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. amtgard/idp-php-client

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

amtgard/idp-php-client
======================

Opinionated PHP client for the Amtgard Identity Provider OAuth 2.0 and resource API

v1.4.1(1mo ago)013↓85.7%proprietaryPHPPHP ^8.3

Since Jun 8Pushed 1mo agoCompare

[ Source](https://github.com/amtgard/amtgard-idp-php-client)[ Packagist](https://packagist.org/packages/amtgard/idp-php-client)[ RSS](/packages/amtgard-idp-php-client/feed)WikiDiscussions main Synced 1w ago

READMEChangelog (5)Dependencies (24)Versions (12)Used By (0)

amtgard-idp-php-client
======================

[](#amtgard-idp-php-client)

Opinionated PHP client for the [Amtgard Identity Provider](https://github.com/amtgard/amtgard-bastion-idp) OAuth 2.0 authorization code + PKCE flow and resource API.

This library encodes **one** integration path so third-party apps stop re-implementing OAuth details incorrectly:

- Authorization code grant with **PKCE (S256)** — always, including confidential clients
- Scopes: `profile email` (space-separated)
- Resource calls: `GET /resources/userinfo`, `GET /resources/validate`, `GET /resources/jwt`
- Policy evaluation: local `checkAuthorization()` via `amtgard/ork-iam` (backend services)
- Typed results: `TokenSet`, `UserProfile`, `OrkProfile`, `ValidatedSession`, `AuthorizationCheck`

Apps can wire config manually (`IdpClientEnvironment`) or use the on-rails factories that read standard `IDP_*` environment variables.

Installation
------------

[](#installation)

```
composer require amtgard/idp-php-client guzzlehttp/guzzle
```

Slim apps should also install Slim to use the bundled auth controller:

```
composer require slim/slim
```

Configuration (`.env`)
----------------------

[](#configuration-env)

Load `.env` before your DI container boots (e.g. `vlucas/phpdotenv` in `public/index.php`). The on-rails factories expect these variables:

```
IDP_BASE_URL=https://idp.amtgard.com
IDP_CLIENT_ID=my-app
IDP_CLIENT_SECRET=your-confidential-client-secret
IDP_REDIRECT_URI=https://my.app/oauth/callback
# IDP_HTTP_USER_AGENT is optional — defaults to AmtgardIDP/1.0
# IDP_HTTP_USER_AGENT=MyApp/1.0
```

VariableRequiredExampleNotes`IDP_BASE_URL`Yes`https://idp.amtgard.com`No trailing slash`IDP_CLIENT_ID`Yes`my-app`Registered with IDP maintainers`IDP_REDIRECT_URI`Yes`https://my.app/oauth/callback`Must match registration **exactly**`IDP_CLIENT_SECRET`No`(secret)`Omit for public clients (PKCE only)`IDP_HTTP_USER_AGENT`No`AmtgardIDP/1.0`Sent on **every** server-side IDP request (`/oauth/token`, `/resources/*`, `/api/*`). Override only when IDP ops instruct you to.Quick start (on-rails factories)
--------------------------------

[](#quick-start-on-rails-factories)

With `.env` populated, one factory call wires environment, OAuth flow state, and HTTP client:

```
use Amtgard\IdpClient\Config\IdpClientFactory;

session_start();

$idp = IdpClientFactory::fromEnvVars();

// GET /login
return $idp->beginAuthorization(returnTo: '/dashboard');

// GET /oauth/callback
$session = $idp->completeLogin($request);
// $session->tokens, $session->profile, $session->returnTo
```

Factory chain:

FactoryBuilds`IdpClientEnvironmentFactory::fromEnvVars()``EnvIdpClientEnvironment` from `IDP_*` vars (throws `IdpConfigurationException` if required vars missing)`IdpClientFactory::fromEnvVars()`Full `IdpClient` with `SessionOAuthFlowStateStore` + Guzzle`IdpClient::completeLogin()`Token exchange + `/resources/userinfo` in one call`SessionAuthStore`Persist `AuthenticatedSession` in `$_SESSION` (framework-agnostic)### Session persistence (any PHP app)

[](#session-persistence-any-php-app)

```
use Amtgard\IdpClient\Session\SessionAuthStore;

$authStore = new SessionAuthStore();

// After callback:
$authStore->store($idp->completeLogin($request));

// Later requests:
if ($authStore->isAuthenticated()) {
    $session = $authStore->get();
    $email = $session->profile->email;
}

// Logout:
$authStore->clear();
```

Manual configuration (custom environments)
------------------------------------------

[](#manual-configuration-custom-environments)

When you cannot use `IDP_*` env vars (multi-tenant config, tests, non-`.env` apps), implement `IdpClientEnvironment` yourself or use `ArrayEnvironment`:

```
use Amtgard\IdpClient\Config\ArrayEnvironment;
use Amtgard\IdpClient\Config\IdpClientFactory;
use Amtgard\IdpClient\OAuth\SessionOAuthFlowStateStore;

$env = new ArrayEnvironment(
    idpBaseUrl: 'https://idp.amtgard.com',
    clientId: 'my-app',
    clientSecret: 'your-secret',
    redirectUri: 'https://my.app/oauth/callback',
);

$idp = IdpClientFactory::fromEnvironment($env, new SessionOAuthFlowStateStore());
```

Equivalent to the on-rails env factory, but explicit:

```
use Amtgard\IdpClient\Config\IdpClientEnvironmentFactory;

$env = IdpClientEnvironmentFactory::fromEnvVars([
    'IDP_BASE_URL' => 'https://idp.amtgard.com',
    'IDP_CLIENT_ID' => 'my-app',
    'IDP_REDIRECT_URI' => 'https://my.app/oauth/callback',
    'IDP_CLIENT_SECRET' => 'secret',
]);
```

For app-specific env layout, wrap or replace `EnvIdpClientEnvironment` with your own class implementing `IdpClientEnvironment` and pass it to `IdpClientFactory::fromEnvironment()`.

Public API reference
--------------------

[](#public-api-reference)

`IdpClient` is the main entry point. Factories and session helpers wire it; Slim accelerators wrap the OAuth methods.

### `IdpClient`

[](#idpclient)

MethodParametersReturnsPurpose`beginAuthorization``?string $returnTo = null``ResponseInterface` (302)Start OAuth: generate PKCE verifier/challenge and `state`, store flow state, redirect browser to IDP authorize URL. Optional `$returnTo` is stored and restored after callback.`completeAuthorization``ServerRequestInterface $callbackRequest``AuthorizationResult`Finish OAuth on `/oauth/callback`: validate `state`, exchange authorization `code` for tokens. Does **not** fetch user profile.`completeLogin``ServerRequestInterface $callbackRequest``AuthenticatedSession`Convenience wrapper: `completeAuthorization()` + `fetchUserProfile()`. Use on callback to get tokens and profile in one call.`fetchUserProfile``string $accessToken``UserProfile``GET /resources/userinfo` — full profile including optional ORK link data and embedded JWT.`validate``string $accessToken``ValidatedSession``GET /resources/validate` — lightweight session heartbeat (`id`, `email`, `jwt`).`fetchJwt``string $accessToken``string``GET /resources/jwt` — fresh authorization JWT string (server may cache for validate/pubsub).`checkAuthorization``Policy $policy`, `Requirement $requirement``AuthorizationCheck`Evaluate whether IAM policy claims satisfy a requirement. Uses **local** `amtgard/ork-iam` (`Policy::isAuthorized`) — same logic as the IDP `/api/is_authorized` endpoint, no HTTP round-trip.`policyFromOrns``list $orns``Amtgard\IAM\Allowance\Policy`Parse JWT-style policy claim strings into a `Policy` object.`requirementFromOrn``string $orn``Amtgard\IAM\Requirement\Requirement`Parse a requirement ORN string into a `Requirement` object.`refresh``TokenSet $tokens``TokenSet`Exchange `refresh_token` for a new token set via `POST /oauth/token`.### Factories and configuration

[](#factories-and-configuration)

ClassMethodPurpose`IdpClientFactory``fromEnvVars(?array $env, ?OAuthFlowStateStore, ?ClientInterface)`On-rails bootstrap from `IDP_*` environment variables.`IdpClientFactory``fromEnvironment(IdpClientEnvironment, OAuthFlowStateStore, ?ClientInterface)`Build `IdpClient` with explicit environment and flow-state store.`IdpClientEnvironmentFactory``fromEnvVars(?array $env)`Parse `IDP_*` vars into `EnvIdpClientEnvironment`.`ArrayEnvironment`constructorIn-memory `IdpClientEnvironment` for tests or custom config.### Session helpers

[](#session-helpers)

ClassMethodPurpose`SessionAuthStore``store(AuthenticatedSession)`Persist logged-in session in `$_SESSION`.`SessionAuthStore``get(): ?AuthenticatedSession`Read stored session.`SessionAuthStore``clear()`Log out (remove session data).`SessionAuthStore``isAuthenticated(): bool`Whether a session is stored.`SessionOAuthFlowStateStore``put` / `pull`Store OAuth `state` + PKCE verifier between `/login` and `/oauth/callback` (session-backed).`InMemoryOAuthFlowStateStore``put` / `pull`Same as above, in-memory (unit tests).### Slim accelerators (`Amtgard\IdpClient\Slim\`)

[](#slim-accelerators-amtgardidpclientslim)

ClassMethodPurpose`IdpAuthController``login`Calls `beginAuthorization()`; honors `?return_to=`.`IdpAuthController``callback`Calls `completeLogin()` and `SessionAuthStore::store()`.`IdpAuthController``logout`Clears `SessionAuthStore`.`SessionMiddleware``__invoke`Starts PHP session for OAuth flow state and auth store.### Result types

[](#result-types)

TypeFields / notes`TokenSet``accessToken()`, `refreshToken()`, `expiresIn()`, raw token array`AuthorizationResult``tokens`, `?returnTo``AuthenticatedSession``tokens`, `profile` (`UserProfile`), `?returnTo``UserProfile``id`, `email`, `jwt`, `?orkProfile``OrkProfile`ORK link fields when user has linked an ORK account`ValidatedSession``id`, `email`, `jwt``AuthorizationCheck``isAuthorized` (bool) — `Amtgard\IdpClient\Iam\AuthorizationCheck`### IAM types (`amtgard/ork-iam`)

[](#iam-types-amtgardork-iam)

TypeNamespaceRole`Policy``Amtgard\IAM\Allowance\Policy`User's IAM claim set — passed to `checkAuthorization()``Requirement``Amtgard\IAM\Requirement\Requirement`Action/resource being checked — passed to `checkAuthorization()`Supporting packages:

- `amtgard/ork-iam-orn-definitions` — registers ORK and Attendance ORN classes
- `Amtgard\IdpClient\Iam\OrnBootstrap` — registers IDP-namespace ORN classes (`Idp` prefix)
- `Amtgard\IdpClient\Iam\OrnParser` — internal parser used by `policyFromOrns()` / `requirementFromOrn()`

Custom integrator `iam_service` namespaces (Client IAM API, future) require additional ORN registration at runtime.

Resource API
------------

[](#resource-api)

After login, use the access token from `TokenSet` or `AuthenticatedSession`:

```
$token = $session->tokens->accessToken();

// Full profile (includes optional ORK link data)
$profile = $idp->fetchUserProfile($token);

// Session heartbeat — lighter than userinfo; returns id, email, jwt
$validated = $idp->validate($token);

// Fresh authorization JWT (cached server-side for validate/pubsub)
$jwt = $idp->fetchJwt($token);
```

Backend services can evaluate IAM policies without a user bearer token or extra HTTP call:

```
use Amtgard\IAM\Allowance\Policy;
use Amtgard\IAM\Requirement\Requirement;

// Build typed ORN objects (from JWT policy claim JSON, config, etc.)
$policy = $idp->policyFromOrns($userPolicyOrnArray);
$requirement = $idp->requirementFromOrn('Idp:0:0:0:0:IDP/EditClient');

$check = $idp->checkAuthorization($policy, $requirement);

if ($check->isAuthorized) {
    // allow action
}
```

`checkAuthorization()` accepts `ork-iam` `Policy` and `Requirement` objects — not raw strings. Use `policyFromOrns()` and `requirementFromOrn()` to parse ORN strings at your API boundary (HTTP handlers, JWT decode, etc.). Evaluation is local via `Policy::isAuthorized()`. Most OAuth client apps only need `fetchUserProfile()` and `validate()`; use policy evaluation when your service already holds a user's IAM policy claim array.

Slim 4 integration
------------------

[](#slim-4-integration)

[Slim 4](https://www.slimframework.com/) apps can use the bundled Slim helpers in `Amtgard\IdpClient\Slim\` — a drop-in auth controller and session middleware. Layout matches other Amtgard PHP projects: PHP-DI `container.php` + `routes.php`.

**Assumptions:** Slim 4, PHP-DI, `vlucas/phpdotenv`, `guzzlehttp/guzzle`, `.env` configured as above.

### On-rails Slim setup (recommended)

[](#on-rails-slim-setup-recommended)

**`config/container.php`** — minimal wiring with env factories:

```
