# Set up hosted tenant login

Use the ordinary Web/PHP SDK with the tenant SSO endpoints and an OAuth
application registered inside your organization. Your website starts sign-in;
M7 hosts the login form at `sso.tenant.m7.org`, then returns to your website to
install its session. No separate tenant SDK or Active Tags UI is required for
this full-page flow.

## 1. Install and register the application

Follow [website installation](https://m7.org/docs/sdk/m7-identity/website/installation.md#install-web-php) to install the
`m7_sso_session` directory in your public document root, including its packaged
`.htaccess` routing. Then open
[Application Registration](https://user.m7.org/members/settings/app-registration)
and create or edit the OAuth application under the intended organization.

This example uses a confidential PHP application with `client_secret_basic`,
authorization-code login with PKCE and PAR, `query` responses, and `ack` token
refresh. Enable the matching capabilities in the app registration. Use that
app's client ID, secret and registered fingerprint values below.

Choose one public HTTPS origin, such as `https://www.example.com`. Register:

| Registration field | Value for this layout |
| --- | --- |
| Redirect URI | `<HTTPS_ORIGIN>/m7_sso_session/callback` |
| Post-logout redirect URI | `<HTTPS_ORIGIN>/tenant/` |

Replace `<HTTPS_ORIGIN>` everywhere with the same scheme and hostname, without
a path or trailing slash. `www.example.com` and `example.com` are different
origins; use the one your visitors actually land on. `/tenant/` is only the
example application's landing page. Replace it throughout if your signed-in
area has another path.

## 2. Copy the Apache configuration

Put this in the application's HTTPS virtual host or a private included Apache
configuration file. Replace every `<...>` placeholder. Each `SetEnv` must be
on its own line, and these values must reach the PHP worker serving the SDK.

```apache
# Website and organization-owned OAuth application
SetEnv M7_PUBLIC_ORIGIN "<HTTPS_ORIGIN>"
SetEnv M7_SSO_BASE_PATH "/m7_sso_session"
SetEnv M7_CLIENT_NAME "<APPLICATION_NAME>"
SetEnv M7_CLIENT_ID "<CLIENT_ID>"
SetEnv M7_CLIENT_SECRET "<CLIENT_SECRET>"
SetEnv M7_TOKEN_ENDPOINT_AUTH_METHOD "client_secret_basic"

# Return to this website after login, cancellation or logout
SetEnv M7_REDIRECT_URI "<HTTPS_ORIGIN>/m7_sso_session/callback"
SetEnv M7_CALLBACK_PROCESS_SUCCESS "/tenant/"
SetEnv M7_CALLBACK_HOME "/tenant/"
SetEnv M7_CANCEL_URL "/tenant/"
SetEnv M7_LOGOUT_URI "<HTTPS_ORIGIN>/tenant/"

# Hosted tenant authority: use this whole endpoint profile together
SetEnv M7_OIDC_ISSUER "https://sso.tenant.m7.org"
SetEnv M7_AUTH_ENDPOINT "https://sso.tenant.m7.org/authorize"
SetEnv M7_PAR_ENDPOINT "https://sso.tenant.m7.org/par"
SetEnv M7_TOKEN_ENDPOINT "https://sso.tenant.m7.org/token"
SetEnv M7_ACK_RELAY_ENDPOINT "https://sso.tenant.m7.org/token/ack"
SetEnv M7_ACK_IDENTITY_ENDPOINT "https://id.m7.org/api/v2/oauth/token/ack"
SetEnv M7_INTROSPECTION_ENDPOINT "https://sso.tenant.m7.org/introspect"
SetEnv M7_USERINFO_ENDPOINT "https://sso.tenant.m7.org/userinfo"
SetEnv M7_END_SESSION_ENDPOINT "https://sso.tenant.m7.org/logout"
SetEnv M7_REVOCATION_ENDPOINT "https://sso.tenant.m7.org/revoke"

# Match the registered authorization and refresh policy
SetEnv M7_AUTH_USE_PAR "true"
SetEnv M7_RESPONSE_MODE "query"
SetEnv M7_SCOPE "openid profile email groups offline_access"
SetEnv M7_TOKEN_REFRESH_MODE "ack"
SetEnv M7_FINGERPRINT "<CURRENT_FINGERPRINT_HEX>"
SetEnv M7_NEW_FINGERPRINT "<SUCCESSOR_FINGERPRINT_HEX>"
SetEnv M7_PENDING_ENVELOPE_KEY "<INDEPENDENT_ENVELOPE_KEY_BASE64URL>"
```

The fingerprints must match the registered application. When not rotating,
use the same registered value for both fingerprint settings. For a new
registration, generate a 32-byte hexadecimal value and register that value:

```sh
openssl rand -hex 32
```

Generate a separate pending-envelope key for this installation:

```sh
php -r 'echo rtrim(strtr(base64_encode(random_bytes(32)), "+/", "-_"), "="), PHP_EOL;'
```

Keep the generated values stable across requests and worker restarts. The
pending-envelope key protects the SDK's pending token package locally; it is
not the client secret or a fingerprint and is not sent to SSO. Keep secrets
outside the public document root. Validate the Apache configuration and reload
the applicable web server/PHP worker after installing it.

The tenant authority's logout endpoint is **`/logout`**. Set it explicitly as
above; the SDK's generic derived `/end-session` path is not the tenant profile.
There is no `M7_SSO_ORIGIN` or group-selection environment variable. The
registered client identifies the organization/application, while these
endpoints select the hosted tenant authority.

## 3. Choose who can log in

In Application Registration, edit the **saved organization application** and
open **Knobs → Tenant Policy → Groups → Login groups**, then **Save Groups**.
The tenant controls require an organization-owned app that has already been
saved; they are not shown for an unsaved or personal app.

- Select the groups whose members may use this application. A user must have
  active membership in at least one selected login group.
- An empty Login groups list adds no group restriction; other tenant and
  account checks still apply. A configured group that is unavailable or
  inactive does not turn the restriction off.
- **Registration groups** separately determine which groups new signups join.
  They do not retroactively enroll existing accounts; add those memberships
  separately.

The `groups` value in `M7_SCOPE` requests group claims. It does not configure
which groups may sign in. Set Login groups on the same app whose client ID you
placed in the Apache configuration.

## 4. Add login and logout links

The package routes work directly:

```html
<a href="/m7_sso_session/login">Log in</a>
<a href="/m7_sso_session/logout">Log out</a>
```

If registration is enabled for the tenant/application, add:

```html
<a href="/m7_sso_session/signup">Sign up</a>
```

For shorter URLs, these optional rules belong in the **document-root
`.htaccess`**, before the application's catch-all routing:

```apache
RewriteEngine On
RewriteRule ^login/?$ m7_sso_session/login [L,QSA]
RewriteRule ^signup/?$ m7_sso_session/signup [L,QSA]
RewriteRule ^logout/?$ m7_sso_session/logout [L,QSA]
```

You can then link to `/login`, `/signup` and `/logout`. These aliases do not
change the registered callback or SDK base path.

## 5. Check the complete flow

Open the login link. It should take you to tenant SSO, return through
`/m7_sso_session/callback`, exchange and acknowledge the token package, install
the website's session cookies, then land on `/tenant/`.

Check an allowed account, an incorrect password, an account outside the
configured login groups, and logout. Incorrect passwords and login-group
denials should leave the hosted login form available to try another account;
they should not immediately forward to your site's callback error page.
Logout should return to the configured public origin and landing page.

Your website must still enforce session and access checks on its protected
pages. Setting the post-login path does not protect that path automatically.

If bootstrap reports `M7_PUBLIC_ORIGIN must be an absolute HTTPS URL`, check
that the placeholder was replaced and that the **web PHP worker**, not just
your shell, receives the setting. For additional troubleshooting, use
[Web SSO setup diagnostics](https://m7.org/docs/sdk/m7-identity/website/README.md#web-sso-setup-diagnostics).
