Skip directly to page content
b13 GmbH

Hauptstätter Str. 59
70178 Stuttgart
Germany
+49 (0) 711 460 589 70 [email protected]
Icon featuring a key and overlapping squares, symbolizing security or access control.

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
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
idp.example.com/saml/metadata 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.

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 and Frontend Login
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
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
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
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
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
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
allowEmailAsUsername false Config file only, top level Also matches the name identifier against the email column, not only username. See allowEmailAsUsername
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

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:

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 schemas.microsoft.com/claims/, schemas.microsoft.com/identity/claims/ and schemas.xmlsoap.org/ws/2005/05/identity/claims/ 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: schemas.microsoft.com/identity/claims/displayname 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.

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.