Sign in with M7 on a PHP site

The announcement said you can start. This is the first path: put Sign in with M7 on a PHP site using web-php 0.1.3.

The package is a same-origin backend-for-frontend. It owns OAuth state, PKCE, the code exchange, and HttpOnly session cookies. Your app owns pages, routing around /m7_sso_session, and when to ask for the current session. Do not rename the installed directory.

The full contract is the website installation guide. This post is the copyable spine.

A printed page on a wooden desk beside a simple brass push-button.

1. Register the app

Create a development account, then register an OAuth application. The redirect URI for the default install is exact:

https://YOUR_APPLICATION_ORIGIN/m7_sso_session/callback

You will need the origin, client ID, token-endpoint authentication method, client secret if the client is confidential, authorization and token endpoints, acknowledgement endpoint, fingerprints, refresh mode, and a same-origin post-login URL. Issuer is https://sso.user.m7.org. PKCE is S256 only.

2. Verify the zip

m7-identity-web-php-0.1.3.zip
m7-identity-web-php-0.1.3.zip.sha256
m7-identity-web-php-0.1.3.zip.manifest.json

ZIP · SHA-256 · manifest

shasum -a 256 -c m7-identity-web-php-0.1.3.zip.sha256
unzip m7-identity-web-php-0.1.3.zip -d ./staging

Copy only m7_sso_session into the public document root. Keep the docs, manifest, and checksums out of the web root. Do not put a .env, client secret, or pending-envelope key inside that directory.

3. Configure the PHP worker

Set the registered M7_* values on the Apache / PHP-FPM process that serves the site. Fingerprints accept 64 hex or 43 unpadded base64url characters; the SDK still sends lowercase hex on the wire. Reload the worker after changes. The CLI environment is not the web worker.

4. Start login and read the session

window.location.assign("/m7_sso_session/");
const response = await fetch("/m7_sso_session/me", {
  method: "POST",
  credentials: "include",
  headers: { "Content-Type": "application/json" },
  body: "{}",
});

const session = await response.json();
if (!response.ok || session.ok !== true) {
  throw new Error(session.error?.message || "M7 session request failed");
}

Treat HTTP status and ok together. Keep any access token from /me in memory. /profile uses the HttpOnly cookie and does not return the token. Never call /callback-process yourself; the package callback page owns that hop.

A GET to /m7_sso_session/me should be 405. Direct PHP filenames in the package should be rejected.

5. Confirm the loop

On a non-production registration, run login, callback, acknowledgement, /me, /profile, refresh, and logout through the real HTTPS origin before you point a production client at it.

If the site already brokers GitHub or Discord itself, use the OIDC-Connect PHP pattern so M7 is one button beside the others. The website still owns local accounts and linking. Do not key accounts on email alone.

PHP 8.1+, OpenSSL, and cURL. License is MTL-10. Packagist is not available.

That is the install. Next is policy: people, machines, and tenants are not the same principal.