At Commerce Guys we provide a varied range of services, including our cloud PaaS Platform.sh, this Drupal Commerce community website, support, and the Commerce Marketplace.

Our users may need to log in to any of these services, and sometimes several at the same time. So we needed to have a shared authentication system, a way of synchronizing user accounts, and single sign-on (SSO) functionality.

After a lot of research on the existing methods, such as CAS, we found that there was no generic open-source solution which would cover all of our current needs and would also allow us to grow and scale in the future when adding new features or applications.

We decided to implement the OAuth 2.0 and OpenID Connect protocols, which were designed to be flexible, yet simple and standardized - exactly what we wanted.

Naturally, as a result of our work, we published three Drupal modules: OAuth2 Server, OpenID Connect, and OpenID Connect SSO.

In this post I will describe how these modules are designed to work. Each project has a documentation page on Drupal.org, where you can find examples and set-up instructions: links are at the end of the post.

Why OAuth 2.0?

OAuth 2.0 – as its specification describes – is a framework which allows a third-party application to authorize with a server. The application can authorize on behalf of a user, or (in the user’s absence) on its own behalf. There are many ways of using OAuth2, and there are implementations of it in many programming languages.

As well as server-side applications (such as the Drupal clients described below), OAuth2 is a good choice for client-side applications: it supports ‘public’ clients that cannot store tokens securely, and it has a fast ‘implicit flow’ (using URL fragments) for browser-based clients.

As such it would be useful for ‘headless Drupal’ sites which allow users to log in via a separate JavaScript-based front end, and/or via native mobile apps.

Platform.sh has a Web UI, written using the Angular.js framework, and a command-line interface (written in PHP, based on Symfony Console). Both use the flexibility of OAuth2 to allow users to log in with their Marketplace credentials.

Why OpenID Connect?

OpenID Connect (OIDC) is an identity protocol built on OAuth2. An application using OpenID Connect may verify a user's identity with an OAuth2 server via a signed token, and it can also obtain profile information about the user. The OpenID Connect protocol provides a standardized way of verifying and exchanging user information, which means that client applications can easily give users a choice of multiple login providers.

You can use OpenID Connect to let users log in with other services, such as Google. The OpenID Connect module already provides a default ‘provider’ plugin for Google, and it is easy to configure new clients via the UI or to write new plugins in code.

The authorization server

The Drupal 'server' website holds information about user accounts centrally. It has the following modules installed:

Conveniently, OpenID Connect server functionality is built into the OAuth2 module. If you wanted to implement shared authentication without SSO, then the server site would only need the OAuth2 Server module and library.

The server must be accessible over HTTPS with a valid SSL certificate.

See the OAuth2 Server documentation for how to configure the module.

The clients

The Drupal 'client' websites do not allow users to register directly: their user accounts are created during the login process.

When a user clicks to log in on a client site, s/he is redirected to the server's login page. After the user logs in, s/he is redirected back to the client. The client site receives an ID token and an access token, with which it can then request further information about the user (in the background).

The 'client' site has the following modules installed:

OpenID Connect

OpenID Connect SSO, and its submodule OpenID Connect SSO Client

By default, OpenID Connect synchronizes the user name, email address, and timezone with the server. The information is requested by the client site whenever the user logs in.

You can configure OpenID Connect to synchronize more data - for example profile pictures, and other user fields. Each piece of user information that the server provides is called a ‘user claim’. Claims can be requested individually, or as part of a ‘scope’.

OpenID Connect, by default, does not synchronize any role or permission information; its primary purpose is identity, not authorization. Client sites may each have very different roles or permissions for their users.

The clients themselves must be trusted and recognized by the server. Each client must have a ‘client ID’ and a ‘client secret’. The ID and secret combination is stored on both the client and the server, and it is used to validate exchanged tokens.

See the OpenID Connect documentation for how to configure clients.

Single Sign-On

Single Sign-On (SSO) is an optional extra for a shared authentication system. It allows users to be automatically logged in to all of your network's websites, when they log in to any one site. Perhaps even more importantly, it ensures that when users log out of any one site, they are logged out of all the network’s sites.

The OpenID Connect SSO module achieves this through a system of redirects, in order to share cookies across domain names. It is the same approach used by Google Accounts.

This is a summary of the typical SSO flow:

The user, or “Resource Owner” (for simplicity, let’s call her Alice) visits Client 1 (example-client1.com), and clicks ‘Log in’.

She is redirected to the login page on the Server (example-server.com), where she enters her credentials. She is then redirected back to Client 1, as usual. So far, this is the normal OAuth2 flow.

The OpenID Connect SSO module redirects Alice’s browser to an ‘SSO script’, a single standalone PHP script which is hosted on multiple domains.

The first address of this SSO script is <example-client2.com/sso.php>. It then redirects the browser to all of the domains in the ‘network’: <example-client3.com/sso.php>, <example-client4.com/sso.php>, and <example-client5.com/sso.php>.

At each domain, the SSO script was able to set a ‘login’ cookie in the browser. The cookie simply denotes that Alice should be logged in.

Alice visits Client 2 (example-client2.com), or any of the other client sites. Because a login cookie is set for that domain, she is immediately redirected to the Server, where she is already logged in, so she is redirected back again to the client site, with the proper authentication.

When Alice logs out, on any of these network sites, the same process happens in reverse. She is redirected to the SSO script again, which unsets any ‘login’ cookies and sets a new ‘logout’ cookie, for all of the domains involved.

The SSO script’s redirect process is invisible to Alice, and it’s fast, because this is just a standalone PHP script (avoiding Drupal’s bootstrap). On each domain, the script need only set a cookie and issue a redirect. These cookies contain no sensitive information - no tokens, no timestamps, no user IDs - they only signify Alice’s intent to be logged in (or out). As such, they are a simple and secure way of implementing SSO.

See the OpenID Connect SSO documentation for how to set up the script and the module.

More information

If you want to set up OpenID Connect for your own Drupal site(s), this is a recording of a recent Drupal Commerce Tech Talk (by Nick Vahalik), which is a great start: https://www.youtube.com/watch?v=3K-2IfC8lpg

Further links: