Optional application logout hooks

The live Web/PHP 0.1.6 release exposes two optional mount points for applications that want local enforcement of provider logout notifications. Applications may leave them unconfigured and rely on their existing authority introspection/refresh-family revocation behaviour. There is no SQL requirement or SDK-provided store, queue or scheduler.

Configure application code

Set M7_LOGOUT_HOOKS_FILE to an absolute readable PHP file outside the public document root and the installed SDK package. It returns an array of callables:

<?php
require '/etc/my-app/bootstrap.php';
return [
    'ingest' => fn(array $event): bool => appLogout()->acceptVerifiedLogout($event),
    'is_revoked' => function (array $context): bool {
        if ($context['token_response'] && $context['id_token'] !== null) {
            appSessions()->associateTokenResponse($context);
        }
        return appLogout()->isSessionRevoked($context);
    },
];

The example services belong to your application and must be implemented. Callbacks must return without printing, setting response headers or terminating the request. Never log credential context. Either callback can be omitted. An empty/unset setting disables both; a configured invalid file or callback fails with HTTP 503 logout_hooks_unavailable when reached. Configuration loads once per request.

Ingest verified notifications

ingest receives the trusted configured issuer and client_id, verified iat, exp, jti, and the verified sid and/or sub when present. It receives no raw logout JWT or browser credentials. The existing signature, issuer/audience, time, event, nonce and encryption checks run first.

Return exactly true after durable invalidation or durable queue acceptance, including an already-applied duplicate. Only then does the receiver send HTTP 200 ok. A throw, false or another return type gives HTTP 503 logout_ingestion_failed with retryable=true. Provider retry policy is separate. Application exception details are excluded from SDK logs/responses.

Without ingest, the receiver still acknowledges validated receipt only. Durable queue acceptance can leave an asynchronous enforcement delay unless your checker also sees queued invalidations immediately.

Check session revocation

is_revoked receives these fields:

Field Meaning
issuer, client_id Trusted deployment scope.
stage Operation, such as session_use, refresh, ack, or token_response.
access_token, refresh_token Selected credential inputs, strings or null.
id_token, id_token_nonce Token-response ID token and expected login nonce, strings or null.
token_response Whether this context comes from a successful server-to-server token response.

Return exactly false to allow normal processing or true to stop it with HTTP 401 session_revoked. Current-cookie operations clear SDK active/pending cookies; pending ACK clears pending cookies. A supplied/candidate credential does not clear a different current browser package. Throws/non-boolean results give HTTP 503 logout_check_failed, retaining cookies for retry.

The checker runs before cookie/supplied-token session resolution, refresh, pending-package use/installation, ACK, active-cookie installation and UserInfo. It rechecks session resolution and refresh/ACK/UserInfo results after outbound work. Checks may repeat within a request. The SDK does not recall already-sent responses or make application storage and SDK requests atomic.

Your application must establish the session association. Credential strings can be unvalidated browser input; the SDK supplies no decoded identity claim as a trusted lookup key. At token_response, validate ID-token issuer, client audience, nonce and signing/encryption policy before mapping credential digests to the root sid/subject. Preserve root identity across refresh and associate pending successors before ACK. Decide how unknown/legacy credentials are handled; a fresh sign-in may be required. The token_response marker does not itself assert ID-token claim validation. Existing signing/encryption policies are unchanged.

Independent protected endpoints

Host-owned pages/APIs and independent application sessions need their own integration. After loading the SDK shared.php, an endpoint can call:

m7_logout_require_session('my_api', ['access_token' => $accessToken]);
// Continue normal signature, proof, expiry and permission checks.

The helper returns when disabled or allowed, otherwise throws M7LogoutHookException. If your framework owns exception handling, catch it and deny access using httpStatus()/response(). Its optional third argument all or pending clears SDK cookies on revocation; the default none suits independent API credentials. This does not destroy a host PHP session or replace endpoint authorization. Pure signature/expiry validation without a revocation integration retains an access-token window until expiry.

Application storage duties

Scope writes/lookups by issuer and client; match sid/sub consistently. Handle duplicates idempotently and delayed/out-of-order events without revoking unrelated/new roots. Define the subject-only policy explicitly. Make accepted writes visible to every worker/node. Checking must not consume an invalidation needed by later requests. Keep records through the affected credential, pending-package and application-session lifetimes; the logout JWT's short expiry is not sufficient retention. Cleanup is application-owned.

The SDK's front-channel receiver retains its existing browser-cookie cleanup; these hooks do not add verified front-channel ingestion or stored sid matching. Register and test receivers using the provider logout contract.