---
title: Configuration
url: "https://b13.com/products/single-sign-on-for-typo3/documentation/configuration"
date: 2026-09-10
modified: 2026-11-10
---

# Configuration

![Icon featuring a key and overlapping squares, symbolizing security or access control.](https://b13.com/fileadmin/_processed_/0/a/csm_sharing-ext-SingleSignOn-S_512e772865.webp)

  Documentation
===============

 TYPO3 Module “Single-Sign-On”
 Version 2.0.3 (04 Nov 2026)

   Chapters of this Documentation        There are three configuration sources, and which one a key belongs in is not a matter of taste:

| Source | Scope | Contains |
|---|---|---|
| Extension configuration | both | The two on/off switches and where the backend configuration file lives. See [Extension Settings](https://b13.com/products/single-sign-on-for-typo3/documentation/installation#c12322) |
| Service provider configuration file | both | Everything the SAML toolkit itself needs, plus the backend’s own TYPO3 settings |
| Site configuration, `settings.sso_authentication` | frontend only | The frontend’s TYPO3 settings, and the pointer to its configuration file |

The backend has no site context at login time, which is why it reads TYPO3-specific settings from its configuration file while the frontend reads them from the site configuration. The same key therefore lives in two different places depending on scope, and this chapter states which for every one of them.

   The Configuration File
------------------------

`BackendServiceProviderConfigurationFile` for the backend, the site setting `metadata` for the frontend. Three forms are accepted:

| Form | Read As |
|---|---|
| `EXT:my_ext/Configuration/sso.yaml` | YAML. `%env(...)%` placeholders are resolved. Everything below is available |
| `EXT:my_ext/Configuration/idp.xml` | Plain identity provider metadata. Only `idp`, `strict: true`, `debug: false` and `security.requestedAuthnContext: false` come out of it—there is no place for a TYPO3 setting, so `enforceSSO` and `allowEmailAsUsername` cannot be used |
| `<a href="https://idp.example.com/saml/metadata" rel="noreferrer" target="_blank">idp.example.com/saml/metadata</a>` | Fetched and parsed as identity provider metadata, same limitation as XML |

A path that is neither `EXT:`-prefixed nor a URL is treated as a URL and fails.

YAML files may nest everything under a single `sso_typo3:` root key, which is then unwrapped. Without that key the file is read as-is.

**`idp` is required in a YAML file and has to be a string.** It is either the metadata URL of the identity provider—fetched and parsed on use—or any other string. An inline `idp:` block in the toolkit’s own nested notation is not supported here and fails; see [Known Limits](#c12348).

   Keys Read by This Extension
-----------------------------

Everything in this table is read by the extension itself. Where a key exists in both scopes, the two locations are given.

| Key | Default | Where | Effect |
|---|---|---|---|
| `enabled` | *(none)* | Site config only | Required, and required to be true, or frontend SSO is off for this site. There is no equivalent for the backend—`enableBE` and the presence of a configuration file decide there |
| `metadata` | *(none)* | Site config only | Required for the frontend: the configuration file described above |
| `enforceSSO` | `false` | Config file (backend) · site config (frontend) | On, SSO becomes the only accepted login for that scope: the password fields disappear **and** a posted password is rejected during authentication. See [Backend Login](https://b13.com/products/single-sign-on-for-typo3/documentation/backend-login#c12363) and [Frontend Login](https://b13.com/products/single-sign-on-for-typo3/documentation/frontend-login#c12382) |
| `entityId` | The backend entry point URL · the site base | Config file (backend) · site config (frontend) | The service provider identity registered at the identity provider. A value without a scheme is replaced by [`BackendBaseUrl`](#c12342) |
| `acsUrl` | `<entry point>auth/sso/acs` · `/_auth/sso/acs` | Config file (backend) · site config (frontend) | Where the identity provider posts its assertion. A path is resolved against the base URL. An overridden value is used as-is and still recognized even when it does not follow the `/auth/sso` convention |
| `metadata.url` | *(empty)* | Config file, backend only | Path of the service provider metadata endpoint. Matched as a **substring** of the request path, which is why the shipped example configures `/auth/sso/metadata` for an endpoint served at `/typo3/auth/sso/metadata`. Keep it specific enough not to match unrelated backend routes. Empty disables the endpoint |
| `metadataUrl` | *(empty)* | Site config, frontend only | The same endpoint for the frontend, matched against the path **exactly**. Empty disables it. Setting it in a backend file has no effect |
| `x509cert` | *(none)* | Config file (backend) · site config (frontend) | Public certificate. An absolute path, a path relative to the project root, or the PEM content itself |
| `privateKey` | *(none)* | Config file (backend) · site config (frontend) | Private key, resolved the same way |
| `NameIDFormat` | `urn:oasis:names:tc:SAML:2.0:nameid-format:unspecified` | Config file only, top level | The name identifier format requested in the authentication request. A value nested under `sp:` is ignored |
| `userStoragePid` | `0` | Config file (backend) · site config (frontend) | Page a federated user is created on. **Leave it at `0` for the backend**, see [`userStoragePid`](https://b13.com/products/single-sign-on-for-typo3/documentation/user-federation#c12392) |
| `loginFormPage` | `0` | Config file (backend) · site config (frontend) | Frontend only in effect: the page excluded from the enforced redirect, and the page TYPO3 resolves while an assertion is being processed. See [Frontend Login](https://b13.com/products/single-sign-on-for-typo3/documentation/frontend-login#c12386) |
| `loginStatusPage` | the site’s root page | Site config, frontend only | Page a logout lands on. Read directly from the site configuration, not through the configuration file |
| `noGroupsPage` | *(none, no redirect)* | Site config, frontend only | Page a logged-in visitor without any usable group is sent to. Unset, the visitor stays where they are. See [Frontend Login](https://b13.com/products/single-sign-on-for-typo3/documentation/frontend-login#c12387) |
| `federation.enabled` | `false` | Config file (backend) · site config (frontend) | On, an identity with no TYPO3 user gets one created. Off, it is rejected. See [User Federation](https://b13.com/products/single-sign-on-for-typo3/documentation/user-federation) |
| `federation.userGroups` | *(empty)* | Config file (backend) · site config (frontend) | Group IDs given to a federated user when no claim maps to `usergroup` |
| `claimsMapping` | *(none)* | Config file (backend) · site config (frontend) | Maps SAML attribute names to user record columns. See [Claims Mapping](#c12343) |
| `allowEmailAsUsername` | `false` | Config file only, top level | Also matches the name identifier against the `email` column, not only `username`. See [`allowEmailAsUsername`](https://b13.com/products/single-sign-on-for-typo3/documentation/user-federation#c12396) |
| `contactPerson` | *(none)* | Config file (backend) · site config (frontend) | Contact block in the generated metadata, omitted when unset. If a type (`technical`, `support`, `administrative`, `billing`, `other`) is given, both `givenName` and `emailAddress` are required, or the toolkit rejects the whole configuration |
| `security.authnRequestsSigned` | `false` | Config file (backend) · site config (frontend) | Sign the authentication request. Only honored when true |
| `security.logoutRequestSigned` | `false` | Config file (backend) · site config (frontend) | Sign the logout request |
| `security.logoutResponseSigned` | `false` | Config file (backend) · site config (frontend) | Sign the logout response |
| `security.allowRepeatAttributeName` | `false` | Config file (backend) · site config (frontend) | Accept an assertion carrying the same attribute name twice instead of rejecting it. See [Common Issues](https://b13.com/products/single-sign-on-for-typo3/documentation/local-development-with-ddev-and-keycloak#c12435) |

  ###  Keys Only the Configuration File Can Carry

For the frontend, the site configuration contributes exactly the keys marked "site config" above. Everything else has to be in the configuration file—`idp`, `allowEmailAsUsername`, `NameIDFormat`, `strict`, `organization`, and any `security` key beyond the four listed. A top-level `x509cert`, `federation` or `claimsMapping` in a frontend configuration file is **not** read; those come from the site configuration only.

  ###  Keys Passed Straight to the SAML Toolkit

Anything else in the configuration file reaches `onelogin/php-saml` untouched. The two worth knowing:

- **`strict`** rejects unsigned or unencrypted messages where a signature or encryption is expected, instead of accepting them with reduced security. This extension never reads it; leave it alone unless you know why you are turning it off.
- **`organization`** shows up in the generated metadata and is otherwise inert.

  ###  Keys That Look Configurable but Are Not

A nested `sp:` block has no effect. `entityId`, `assertionConsumerService` and `singleLogoutService` are assembled from the base URL plus the top-level `entityId` and `acsUrl`, and the computed values overwrite whatever the block says. `sp.NameIDFormat` is overwritten the same way by the top-level key.

The **single logout URL is generated** in both scopes and cannot be configured. For the backend it is the entry point plus `?logintype=slo`, for the frontend the site base plus `?logintype=slo`.

  ###  BackendBaseUrl

Despite the name in the extension configuration form, this only takes effect when `entityId` resolves to a value containing no `://`—the assertion consumer service and single logout URLs are already absolute by the time it is applied. So it matters in exactly one case: a configuration that sets a relative `entityId` such as `'/'` and needs it prefixed with a specific host, for instance because the backend is reachable under several domains. Leave both empty and the default entity ID—the backend entry point of the current request—is used, which is the right answer for a single-domain installation.

It applies to the frontend as well, even though the name says backend: a relative `entityId` in a site configuration is prefixed with the same value.

   Claims Mapping
----------------

`claimsMapping` maps an incoming SAML attribute name to a column of `be_users` or `fe_users`. Two forms:

     Copy

```
```
claimsMapping:
  # attribute name → column
  "urn:oid:2.5.4.42": "realName"
  "urn:oid:1.2.840.113549.1.9.1": "email"
  # attribute name → column, with the accepted values enumerated
  "member":
    field: "usergroup"
    valueMapping:
      "/saml-users": ['1']
      "/editors": ['1', '2', '3']
```
```

  **Attribute names may be written short.** The namespace prefixes `<a href="http://schemas.microsoft.com/claims/" rel="noreferrer" target="_blank">schemas.microsoft.com/claims/</a>`, `<a href="http://schemas.microsoft.com/identity/claims/" rel="noreferrer" target="_blank">schemas.microsoft.com/identity/claims/</a>` and `<a href="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/" rel="noreferrer" target="_blank">schemas.xmlsoap.org/ws/2005/05/identity/claims/</a>` are stripped before matching, so `displayname` and the full URI are equivalent keys.

**A multi-valued attribute is joined with `|`** before mapping. A single value is used as-is.

**`valueMapping` is a filter, not just a translation.** Only incoming values listed there are used; everything else is dropped. The results are joined with a comma, which is what makes it suitable for `usergroup`. Without a `valueMapping`, the raw value is written to the column verbatim.

**A mapping with an empty field name is skipped**, which is how you switch a default off.

  ###  The Default Mapping

One entry is applied *before* yours and can be overridden: `<a href="http://schemas.microsoft.com/identity/claims/displayname" rel="noreferrer" target="_blank">schemas.microsoft.com/identity/claims/displayname</a>` maps to `realName` in the backend and to `name` in the frontend.

   The Settings That Actually Cost You Something
-----------------------------------------------

Three of the keys above are the ones worth a second look before going live.

**`userStoragePid` in the backend.** TYPO3 only looks up `be_users` at the root of the page tree. A backend user federated onto any other page is invisible to every later login, so federation creates a fresh duplicate each time somebody signs in—growing `be_users` by one row per login, each with the group assignment the claims currently produce. Keep it at `0`. In the frontend the same setting is required to be your `fe_users` folder instead, because a frontend login is restricted to it.

**`enforceSSO` without a tested way back in.** It removes the password login for the whole scope, with no per-user exemption. If the identity provider becomes unreachable, nobody signs into the backend until it returns—except through the Install Tool, which has its own authentication. Confirm that access before you switch enforcement on, see [Losing the Identity Provider](https://b13.com/products/single-sign-on-for-typo3/documentation/backend-login#c12366).

**`allowEmailAsUsername` left on after a migration.** It exists so users created with an email address as their username can be matched. TYPO3 does not enforce uniqueness on `email`, so as soon as two active users share an address a login can bind to the wrong record—which means the wrong person’s permissions. Turn it off once the migration is done.

   Known Limits
--------------

These are properties of the current implementation, not settings:

- **A YAML configuration file needs a top-level `idp` string.** An inline `idp` block in the toolkit's nested notation, or a missing `idp` key, aborts resolution of the file.
- **`loginStatusPage` and `noGroupsPage` are read directly from the site configuration** at the point they are needed, not through the configuration file. Leave `loginStatusPage` unset and a logout lands on the site's root page; leave `noGroupsPage` unset and a visitor without groups is not redirected at all. **Set both on any site that uses frontend logout or group-gated access** — the fallbacks keep the site working, they do not do the job the pages are there for.
- **Backend single logout is not implemented.** The URL is generated into the metadata, but nothing handles it.