OpenID Connect integration for TYPO3 

Introduction 

Using this TYPO3 extension enables your TYPO3 instance to use external identity providers (IdPs) to authenticate frontend and/or backend users using the OpenID Connect protocol.

This allows to leverage Single-Sign-On (SSO) scenarios.

After installing and configuring the extension, users will have a dedicated button to login via the configured IdP and will be returned to TYPO3 with an active session.

Various configuration options allow to map information retrieved from the IdP to the TYPO3 user record. For instance: Name, contact data, groups/roles

Identity provider examples 

This is an incomplete list of well-known identity providers:

  • Keycloak
  • Authentik
  • WSO2 Identity Server
  • Microsoft EntraID
  • Google
  • GitHub
  • Gitlab
  • ID Austria

Usage for frontend 

Next to ext:felogin 

The login can be triggered by a button, which can be placed next to your existing felogin form. So you can use both login-mechanisms in parallel.

After the login process, the user will be redirected according to the rules defined in the felogin plugin on the same page.

Direct OIDC Login 

If OpenID Connect is your only means of frontend login, you can use the included "OIDC Login" plugin. Add it to your login page, where you would normally put the felogin form. After adding the OIDC Login plugin, requests to the login page will immediately be redirected to the identity provider.

After the login process, the user will be redirected:

  • The OIDC Login supports the same redirect_url parameter as the felogin box
  • If no parameter is set, OIDC Login will redirect the user to the page configured at plugin.tx_oidc_login.defaultRedirectPid.
  • If that configuration is not set either, the user will be redirected to '/'.

Usage for backend 

If enabled, the extension provides a login provider for backend of the TYPO3 instance.

Configuration 

The extension requires at least a configuration for how user information from the IdP is mapped to TYPO3 user records fe_users/be_users.

Mapping user fields 

  • Configuration is done through TypoScript within the keys plugin.tx_oidc.mapping.fe_users and plugin.tx_oidc.mapping.be_users
  • Information about the user from OIDC attributes (ID Token or UserInfo-endpoint) will be recognized by the specific characters <>:

    email = <mail>
    
    Copied!
  • You may combine multiple markers as well, e.g.,

    name = <family_name>, <given_name>
    
    Copied!
  • Support for stdWrap in field definition, e.g.,

    name = <name>
    name.wrap = |-OIDC
    
    Copied!
  • Support for TypoScript data fallback (//). This will check multiple field names and return the first one yielding some non-empty value. E.g.,

    username = <sub> // <contact_number> // <emailaddress> // <benutzername>
    
    Copied!

Mapping user groups 

It is possible to assign TYPO3 user groups to a user based on the Roles attribute sent via OIDC.

Steps to follow:

  • Create your groups within TYPO3
  • Use the additional pattern-field within the group record to relate each group to Roles within OpenID Connect
  • Local TYPO3 groups (not related to some role) will not be added or removed from a user record
  • Default TYPO3 group(s) as configured in the extension's global configuration will always be added

OIDC Login plugin TypoScript configuration 

  • plugin.tx_oidc_login.defaultRedirectPid UID of the page that users will be redirected to, if no redirect_url parameter is set with the request.

PKCE (Proof of Key for Code Exchange) 

If your IdP supports Proof of Key for Code Exchange you can enable it by setting enableCodeVerifier in the extension configuration. A shared secret will be sent along preventing Authorization Code Interception Attacks. See RFC7636 for details.

Logging 

For debugging purposes it may be helpful to enable DEBUG-level logging. In addition, rerouting all log lines to a dedicated file is also recommended.

The following instructions in your sitepackage's ext_localconf.php or global config/system/additional.php file will configure the system appropriately:

$GLOBALS['TYPO3_CONF_VARS']['LOG']['Causal']['Oidc']['writerConfiguration'] = [
    \TYPO3\CMS\Core\Log\LogLevel::DEBUG => [
        \TYPO3\CMS\Core\Log\Writer\FileWriter::class => [
            'logFileInfix' => 'oidc'
        ],
    ],
];
Copied!

Hint: Be sure to read Configuration of the Logging system to fine-tune your configuration on any production website.

Integrating your identity provider with specific packages 

This extension uses an underlying PHP library for OAuth2, which can be extended for specific identity providers by adding additional packages.

Example: For Microsoft EntraID (Azure) the package is thenetworg/oauth2-azure

In order to use these kinds of packages, one needs to implement a custom OAuth2ProviderFactory, which takes care of initializing the specific provider.

Here is an example for the aforementioned Azure package.

Register your custom factory class in the extension configuration oauthProviderFactory = \Reelworx\Sitesetup\Authentication\OAuth2ProviderFactory. Put this class into your site-package, typically in the file packages/<sitepackage>/Classes/Autentication/OAuth2ProviderFactory.php:

<?php

declare(strict_types=1);

namespace Reelworx\Sitesetup\Authentication;

use Causal\Oidc\Factory\OAuthProviderFactoryInterface;
use League\OAuth2\Client\Provider\AbstractProvider;
use TheNetworg\OAuth2\Client\Provider\Azure;
use TYPO3\CMS\Core\Utility\GeneralUtility;

/* requires some ENV variables to be set, see below */
final class OAuth2ProviderFactory implements OAuthProviderFactoryInterface
{
    public function create(array $settings): AbstractProvider
    {
        $options = [
            'clientId' => $settings['oidcClientKey'],
            'redirectUri' => $settings['oidcRedirectUri'],
            'urlAuthorize' => $settings['oidcEndpointAuthorize'],
            'urlAccessToken' => $settings['oidcEndpointToken'],
            'urlResourceOwnerDetails' => $settings['oidcEndpointUserInfo'],
            'scopes' => GeneralUtility::trimExplode(',', $settings['oidcClientScopes'], true),
            'defaultEndPointVersion' => Azure::ENDPOINT_VERSION_2_0,
            'tenant' => getenv('AZURE_OAUTH_CLIENT_TENANT'),
        ];
        if ($settings['oidcClientSecret']) {
            $options['clientSecret'] = $settings['oidcClientSecret'];
        } else {
            // https://learn.microsoft.com/en-us/entra/identity-platform/certificate-credentials
            // PEM certificate (newline potentially encoded as '\n'
            $options['clientCertificatePrivateKey'] = getenv('AZURE_OAUTH_CLIENT_CERTIFICATE');
            // SHA-1 thumbprint of the X.509 certificate's DER encoding.
            $options['clientCertificateThumbprint'] = getenv('AZURE_OAUTH_CLIENT_CERTIFICATE_THUMBPRINT');
        }
        return new Azure($options);
    }
}
Copied!

Developer information 

For customization purposes this extension provides 8 events. Please lookup their usage within the code to identify the right event(s) matching your requirements.

Maintainer's corner 

Running acceptance tests 

The Build folder contains a docker compose test environment for this oidc extension. It contains:

  • TYPO3 v13 instance with ext-oidc installed
  • TYPO3 v14 instance with ext-oidc installed
  • mock oidc server
  • Playwright test runner to run acceptance tests
  • VNC Server to watch the playwright tests

To build the test environment and run the playwright tests run the following command:

cd Build
docker compose up --build --exit-code-from playwright && echo "Success" || echo "Fail"
Copied!

Reference 

Implementation concept 

This extension builds a wrapper around the league/oauth2-client PHP library. It provides TYPO3 AuthenticationServices which integrate the authentication with frontend and backend.

In order to encapsulate and store the "state" parameter recommended for the request towards the IdP, the extensions creates a JWT stored in a cookie. This allows for state-less authentication flow, helpful for multi-server setups, where shared PHP-sessions are hard to implement. (Note the distinction between PHP- and anonymous TYPO3-session here. During the authentication phase there is no TYPO3-session available yet, so the "state" would have to be stored within a PHP-session.)

Specification 

https://openid.net/specs/openid-connect-core-1_0.html

Credits 

This TYPO3 extension is created and maintained by:

A big "Thanks" goes out to all contributors.