Install M7 Identity SDK for CLI and background processes

The stable releases are token-php 0.1.2 and cli-php 0.1.1. The CLI requires token-php >=0.1.2 <0.2.0 for client credentials, device code, refresh-package exchange, ACK, ensure, and authenticated resource requests.

For the complete operator processes, use the public CLI subject guide, which covers client credentials, device authorization, managed ensure, ACK, and authenticated requests beside this installation page.

Download token-php 0.1.2 as its ZIP, SHA-256 checksum, and release manifest.

Download cli-php 0.1.1 as its ZIP, SHA-256 checksum, and release manifest.

Verify and extract the CLI

Keep each ZIP with its .sha256 and .manifest.json sidecars. Verify both archives before extraction:

shasum -a 256 -c m7-identity-token-php-0.1.2.zip.sha256
shasum -a 256 -c m7-identity-cli-php-0.1.1.zip.sha256
unzip m7-identity-token-php-0.1.2.zip -d ./vendor
unzip m7-identity-cli-php-0.1.1.zip -d ./vendor

Point the CLI at the separately installed token package:

export M7_IDENTITY_TOKEN_ROOT="$PWD/vendor/m7-identity-token-php-0.1.2"

Use the client-credentials CLI

Confirm the packaged command and dependency load:

./vendor/m7-identity-cli-php-0.1.1/bin/m7-identity --version
./vendor/m7-identity-cli-php-0.1.1/bin/m7-identity client-credentials --help
./vendor/m7-identity-cli-php-0.1.1/bin/m7-identity request --help

Start the controlling-terminal prompt flow with:

./vendor/m7-identity-cli-php-0.1.1/bin/m7-identity client-credentials --interactive

To use the protected keychain, select an existing machine app. Its profile defaults to default; a successful complete response is stored before stdout:

./vendor/m7-identity-cli-php-0.1.1/bin/m7-identity client-credentials \
  --app user.m7.org-cc \
  --interactive

./vendor/m7-identity-cli-php-0.1.1/bin/m7-identity token status \
  --app user.m7.org-cc \
  --grant client-credentials

The second command prints metadata, never the token. Calls without --app remain stateless.

Or configure an unattended call. The secret file must not be a symlink and must grant no group or other permissions:

chmod 0600 /run/secrets/m7-client-secret
export M7_CLIENT_CREDENTIALS_CLIENT_ID='YOUR_REGISTERED_CLIENT_ID'
export M7_CLIENT_CREDENTIALS_CLIENT_SECRET_FILE='/run/secrets/m7-client-secret'
export M7_CLIENT_CREDENTIALS_AUD='https://api.user.m7.org/'

./vendor/m7-identity-cli-php-0.1.1/bin/m7-identity client-credentials --output token

Any defined M7_CLIENT_CREDENTIALS_* value overrides its matching CLI option. An empty defined value also overrides the option and may fail validation; the command never silently falls back around deployment configuration.

Create and run a managed public device client from the same installation:

./vendor/m7-identity-cli-php-0.1.1/bin/m7-identity app upsert user.m7.org-device \
  --client-id YOUR_REGISTERED_DEVICE_CLIENT_ID \
  --type native \
  --authority consumer

./vendor/m7-identity-cli-php-0.1.1/bin/m7-identity profile upsert \
  --app user.m7.org-device \
  --grant device-code \
  --config-json '{"auth_method":"none","aud":["https://user.m7.org"],"scope":"openid profile offline_access","refresh_mode":"strict_rotation"}'

./vendor/m7-identity-cli-php-0.1.1/bin/m7-identity device-code \
  --app user.m7.org-device

The upserts make this setup block repeatable. They replace the editable app and profile definitions rather than merging stale fields, while retaining stored passwords and complete token history.

The raw stateless form is also available:

export M7_DEVICE_CODE_AUTH_METHOD='none'
export M7_DEVICE_CODE_CLIENT_ID='YOUR_REGISTERED_DEVICE_CLIENT_ID'
export M7_DEVICE_CODE_SCOPE='openid profile offline_access'

./vendor/m7-identity-cli-php-0.1.1/bin/m7-identity device-code

Interactive configuration is also available:

./vendor/m7-identity-cli-php-0.1.1/bin/m7-identity device-code --interactive

The browser approval page owns account authentication. Do not enter an M7 password into the CLI or store it beside the device code.

To rotate the managed bundle in place:

M7_EXCHANGE_REFRESH_MODE=strict_rotation \
  ./vendor/m7-identity-cli-php-0.1.1/bin/m7-identity exchange \
    --app user.m7.org-device

To exchange a stateless protected bundle returned by a raw device flow:

chmod 0600 /run/secrets/m7-refresh-bundle.json
export M7_EXCHANGE_AUTH_METHOD='none'
export M7_EXCHANGE_CLIENT_ID='YOUR_REGISTERED_DEVICE_CLIENT_ID'

./vendor/m7-identity-cli-php-0.1.1/bin/m7-identity exchange \
  --bundle-file /run/secrets/m7-refresh-bundle.json

The raw output is a rotated replacement package. It does not rewrite its input, so persist the entire output before retiring the preceding bundle. The separate store can import a protected complete bundle explicitly:

./vendor/m7-identity-cli-php-0.1.1/bin/m7-identity token import \
  --app YOUR_LOCAL_APP \
  --grant device-code \
  --file /run/secrets/m7-refresh-bundle.json

Omitting --profile selects default; app and grant are always explicit.

For managed two-phase activation, exchange stores pending and ACK promotes the exact generation after authority success:

M7_EXCHANGE_REFRESH_MODE=ack \
  ./vendor/m7-identity-cli-php-0.1.1/bin/m7-identity exchange \
    --app user.m7.org-device

./vendor/m7-identity-cli-php-0.1.1/bin/m7-identity ack \
  --app user.m7.org-device

On failure, pending storage is retained. Use --id GENERATION if several pending generations exist.

For a fault-tolerant ACK lifecycle, set M7_EXCHANGE_REFRESH_MODE=ack_supersede_pending and run exchange --app user.m7.org-device; then run ack --app user.m7.org-device. With no pending state it starts normally from active. If a pending child already exists, Identity disables it and issues the newest child while the predecessor stays active until ACK. A locally retained pending generation is removed only after its successor is stored. The protected-file forms remain available for stateless/manual operation.

Call a protected API with a managed token:

./vendor/m7-identity-cli-php-0.1.1/bin/m7-identity request \
  --app user.m7.org-device \
  --url https://api.user.m7.org/api/v2/session/me \
  --response json \
  --query include=groups

With --app, the command reuses a fresh token or ensures and stores a replacement before sending. Use --minimum-ttl and --refresh-mode to control managed preflight; native profiles without a configured mode default to ack_supersede_pending. Without --method, requests use GET unless JSON data is supplied, which selects POST. The command also accepts --bundle PATH, --bundle-stdin, protected manual token input, and separate fingerprint or fresh DPoP proof input; those explicit credential sources are never refreshed or stored. It does not blindly retry an API 401. With --response json, an incorrectly typed or malformed 2xx response also fails while retaining its original body for diagnosis.

The remainder of this page describes the independently published library artifact for PHP programs and background workers.

1. Check the library runtime

Use PHP 8.1 or newer with OpenSSL:

php -v
php -m | grep -E '^(curl|openssl)$'

OpenSSL is required. cURL is recommended for token acquisition, authenticated resource requests, live certificate retrieval, introspection, and UserInfo; supported PHP streams are the fallback transport.

2. Verify and extract the release

Keep these files together:

m7-identity-token-php-0.1.2.zip
m7-identity-token-php-0.1.2.zip.sha256
m7-identity-token-php-0.1.2.zip.manifest.json

Verify the archive with one available command:

shasum -a 256 -c m7-identity-token-php-0.1.2.zip.sha256
sha256sum -c m7-identity-token-php-0.1.2.zip.sha256

Extract it into an application-owned, non-public package directory:

unzip m7-identity-token-php-0.1.2.zip -d ./vendor

The archive creates m7-identity-token-php-0.1.2/ and includes its autoloader, source, package metadata, documentation, manifest, and payload checksums.

3. Load the package

Load the bundled autoloader from the extracted release:

require_once __DIR__ . '/vendor/m7-identity-token-php-0.1.2/autoload.php';

Do not edit the extracted package in place. Keep the archive manifest and digest as the installation receipt, and install a new verified release when upgrading.

4. Validate a token locally

The following command reads the serialized token from standard input so it does not need to appear in the process argument list:

<?php

require_once __DIR__ . '/vendor/m7-identity-token-php-0.1.2/autoload.php';

use M7\Identity\M7IdentitySDK;

$serializedToken = trim(stream_get_contents(STDIN));
if ($serializedToken === '') {
    fwrite(STDERR, "A token is required on standard input.\n");
    exit(2);
}

$certificate = file_get_contents('/path/to/trusted-public-certificate.pem');
$identity = new M7IdentitySDK();
$report = $identity->validate($serializedToken, [
    'audience' => 'https://api.example.m7.org/',
    'client_id' => 'YOUR_REGISTERED_CLIENT_ID',
    'principal_type' => 'consumer',
    'scope' => ['profile.read'],
    'cert_pem' => $certificate,
]);

if (!$report->ok()) {
    fwrite(STDERR, $report->reason() . "\n");
    exit(1);
}

fwrite(STDOUT, "Token validation passed.\n");

Read the token from the consuming process's protected runtime channel. Do not store it in the script or use a literal token in a shell command.

5. Add live operations only when required

clientCredentials() needs an HTTPS token endpoint, a confidential client, and at least one audience. introspect() needs an HTTPS introspection endpoint and the registered client authentication method. userinfo() needs the protected-resource endpoint and, for built-in M7 selectors, the registered client ID. Store any client secret in the process secret manager and inject it only into the trusted runtime.

Use bounded connection and response settings. Treat active() === false, transport failures, malformed responses, and subject mismatches as closed authorization outcomes.