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

Frontend SSO is switched on per site, in the site configuration:

settings:
  sso_authentication:
    enabled: true
    metadata: 'EXT:my_site_package/Configuration/Sso/frontend.yaml'
    userStoragePid: 42
    loginFormPage: 17
    loginStatusPage: 18

enabled and metadata are both required. Without either, frontend SSO is off for that site and nothing below applies. The remaining keys are in Configuration.

The Contract With Your Own Template

This is the part that changed in 2.0.0. The extension no longer renders the SSO button. ModifyFrontendLoginView listens to EXT:felogin's ModifyLoginFormViewEvent and assigns three variables to the login form's view. Everything visual—the button, hiding the password fields, the wording—is your own Login.html.

A site that rendered the previously shipped partial by name has a broken login page until its template is updated. This section is what to build instead.

EXT:felogin is required. ModifyLoginFormViewEvent is declared there, so without typo3/cms-felogin installed the event does not exist and the listener never fires. It is not a hard dependency of this extension.

Point felogin at your own template path:

plugin.tx_felogin_login.view.templateRootPaths.20 = EXT:my_site_package/Resources/Private/Templates/Felogin/

and put your template at Templates/Login/Login.html below that path. Copy EXT:felogin/Resources/Private/Templates/Login/Login.html as a starting point.

The Three Variables

All three are assigned only when SSO is active for the current site. On a site without SSO they are absent, so a template shared across sites needs to cope with that—f:if on an undefined variable is false, which is usually enough.

Variable Type Value Use It To
additionalAuthenticationProviders array<string, string> ['sso-ad' => 'SSO Login']—a fixed identifier/label pair, not translated and not configurable Detect that SSO is available, and iterate to render one entry per provider
ssoAcsRedirectUrl TYPO3\CMS\Core\Http\Uri The assertion consumer service URL with ?logintype=sso already appended Link an <a> at it to start a login
enforceSSO bool true when enforceSSO is set for this site Hide the username and password fields

enforceSSO in the view is presentation only. The actual rejection of a password login happens during authentication and does not depend on your template getting this right—see Enforcing SSO.

A Minimal Template

<f:if condition="{additionalAuthenticationProviders}">
    <f:for each="{additionalAuthenticationProviders}" as="label" key="identifier">
        <a href="{ssoAcsRedirectUrl}" class="btn btn-primary btn-block"
           data-provider="{identifier}">{label}</a>
    </f:for>
</f:if>

<f:if condition="{enforceSSO}">
    <f:else>
        <!-- the regular username/password fields, e.g. the partial felogin ships -->
        <f:render partial="Login/LoginForm" arguments="{_all}"/>
    </f:else>
</f:if>

Two notes on the markup:

  • Do not hard-code the label. It comes from the variable, and iterating keeps the template working if a second provider is ever added.
  • enforceSSO false does not mean "no SSO". In that case both blocks render, which is the dual-login case the default is built for.
A frontend login form built with EXT:felogin: a "Login with SSO" button rendered by the site's own Login template above the regular username and password fields, which remain available.

Sending the User Somewhere Specific After Login

Append redirect_url to ssoAcsRedirectUrl:

<a href="{ssoAcsRedirectUrl}&redirect_url={f:uri.page(pageUid: 25, absolute: 1)}">
    Login with SSO
</a>

The value is carried through the identity provider as the SAML RelayState and handed back to felogin as its referer, so felogin's redirect mode referer picks it up. Without it, the visitor comes back to the base of the current site language.

It has to be an absolute URL. The value is validated on the way back, not on the way out: a returning RelayState is discarded unless its scheme is http or https and its host matches the host the assertion arrived at, which is what keeps it from being used as an open redirect. A relative path has no host and is dropped by the same check, exactly like a URL pointing at another domain—neither produces an error, the visitor just lands on the site base. Hence absolute: 1 above, and a URI view helper rather than a literal string, so the host always matches the site the visitor is on.

Enforcing SSO per Site

settings:
  sso_authentication:
    enforceSSO: true

Defaults to false, which offers SSO and the regular login side by side.

With enforceSSO: true, any request without a frontend session is redirected to the identity provider—not just requests to the login page. The site becomes inaccessible to anonymous visitors, including search engines. That is the point of the setting for an intranet, and a mistake on a public site.

Enforcement is not only a redirect. A password posted at the login form is rejected during authentication, because the SSO authentication service aborts the chain before the username/password service can run. Hiding the fields in the template and rejecting the credentials are two independent mechanisms, and the second is the one that holds.

Upgrade note. Before this setting existed, an SSO-enabled frontend always redirected every visitor to the identity provider—the equivalent of enforceSSO: true. The default is now false, so a site that wants to keep forcing SSO has to say so explicitly.

loginFormPage

The page configured as loginFormPage is the one exception to the enforced redirect: it renders while logged out, so there is somewhere for the login form to live. With enforcement on and no loginFormPage, every frontend URL bounces to the identity provider, including the page you wanted to put the form on.

The same page has a second job. When the assertion comes back, TYPO3 has to resolve some page for a request addressed to the assertion consumer service path, which is not a page at all. loginFormPage is what it resolves, falling back to the site root page when unset. A root page that is a shortcut cannot be used for this.

A User Without Groups

A logged-in visitor whose only group memberships are the two pseudo-groups every frontend user has—0 and -1—is redirected to noGroupsPage. This is the "you have an account here but no access" case, and it is what you get when the identity provider authenticates somebody your claimsMapping gives no group to.

Set noGroupsPage on any site where that can happen. It is read straight from the site configuration when the case occurs. Unset, there is no redirect — the visitor stays on the page they asked for, with whatever the template shows someone without access.

Logging Out

?logintype=slo on a page of the site starts a single logout: TYPO3 asks the identity provider to end the session, and the TYPO3 session is dropped when the identity provider’s answer comes back. loginStatusPage is where a ?logintype=slo request lands once there is no session left, which is what makes it the page to put a "you are signed out" message on. Unset, the logout lands on the site’s root page instead. The three situations the parameter covers, and the order they run in, are in Single Logout.